【问题标题】:WPF-Canvas doesn't show bound items of ObservableCollectionWPF-Canvas 不显示 ObservableCollection 的绑定项目
【发布时间】:2014-11-11 05:00:13
【问题描述】:

我正在开发一个小型状态图编辑器。 我尝试在 MVVM 模式中实现它。

到目前为止我得到了什么:

我的主要观点

<UserControl.Resources>
    <vm:StateChartViewModel x:Key="StateChartViewModel"/>
    <DataTemplate DataType="{x:Type vm:StateViewModel}">
        <views:StateWidget/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:TransitionViewModel}">
        <views:TransitionWidget/>
    </DataTemplate>
</UserControl.Resources>


<Canvas Background="Transparent"
        DataContext="{StaticResource StateChartViewModel}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseLeftButtonDown">
            <command:EventToCommand Command="{Binding  CreateStateCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>

    <ItemsControl Canvas.Left="0"
                  Canvas.Top="0" 
                  ItemsSource="{Binding Transitions}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="0" />
                <Setter Property="Canvas.Top" Value="0" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

    <ItemsControl Canvas.Left="0"
                  Canvas.Top="0"
                  ItemsSource="{Binding States}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="0"/>
                <Setter Property="Canvas.Top" Value="0"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

</Canvas>

我为 StateViewModel 和 TransitionViewModel 设置的 DataTemplates 是这些 viewModel 的视图

状态视图(StateWidget)

<UserControl.Resources>
    <vm:StateViewModel x:Key="StateViewModel"/>
</UserControl.Resources>
<Grid x:Name="XMainGrid"
      DataContext="{StaticResource StateViewModel}">
    <Rectangle Fill="CornflowerBlue" 
               RadiusX="5" RadiusY="5" 
               ClipToBounds="True">
    </Rectangle>
    <StackPanel Orientation="Horizontal"  Margin="10">
        <TextBox Text="{Binding Path=State.Name}" 
                 Background="Transparent"/>            
        <Polygon Points="0,0 20,0 10,10" 
                 Fill="DarkSlateGray" 
                 Margin="10,5,0,0"/>
    </StackPanel>
</Grid>

TransitionView(TransitionWidget)

<UserControl.Resources>
    <vm:TransitionViewModel x:Key="TransitionViewModel"/>
</UserControl.Resources>
<Canvas DataContext="{StaticResource TransitionViewModel}">
    <Line X1="{Binding SourceState.Position.X}"
          Y1="{Binding SourceState.Position.Y}"
          X2="{Binding TargetState.Position.X}"
          Y2="{Binding TargetState.Position.Y}"
          Stroke="DarkGreen"
          StrokeThickness="4"
          />
</Canvas>

在 StateChartViewModel 中,我有 2 个带有 StateViewModels 和 TransitionModels 的 ObservableCollections

    private ObservableCollection<StateViewModel> _states;
    public ObservableCollection<StateViewModel> States
    {
        get
        {
            if (_states == null)
                _states = new ObservableCollection<StateViewModel>();

            return _states;
        }
    }

    private ObservableCollection<TransitionViewModel> _transitions;
    public ObservableCollection<TransitionViewModel> Transitions
    {
        get
        {
            if (_transitions == null)
                _transitions = new ObservableCollection<TransitionViewModel>();

            return _transitions;
        }
    }

    private RelayCommand<MouseEventArgs> _createStateCommand; 
    public ICommand CreateStateCommand
    {
        get
        {
            if (_createStateCommand == null)
                _createStateCommand = new RelayCommand<MouseEventArgs>(AddNewState);

            return _createStateCommand;
        }
    }

    private void AddNewState(MouseEventArgs e)
    {
        var newState = new StateViewModel();
        _states.Add(newState);
    }

我的问题是,当我将 StateViewModels 添加到状态以及转换时,主视图中的画布没有显示任何这些项目。将 SateWidgets 直接添加到画布的子项时,它们会出现在画布中。但我认为必须有一个解决方案,而无需手动执行。

编辑

StateView (StateWidget) 和 TransitionView (TransitionWidget) 应该都显示在同一个画布上! StateViewModels 应显示为 StateWidgets,TransitionViewModels 应显示为 Transitionwidgets。

  MainCanvas

  /--------------\    TransitionWidget    /--------------\
  | StateWidget1 |------------------------| StateWidget2 |
  \--------------/                        \--------------/

【问题讨论】:

  • 您好,您在 StateView 和 TransistionView 上都设置了数据上下文,同时您将这些数据的集合存储在不同的虚拟机中。从 StateView 和 TransistionView 中移除 datacontext,因此列表中的项目设置为 datacontext。

标签: wpf xaml mvvm binding itemscontrol


【解决方案1】:

在您的 vm OnPropertyChanged("States") 中的 AddNewState 方法中是多余的,因为 OC 在您添加或删除项目时会通知 ui。但是你的观点有问题:

状态视图

<Grid x:Name="XMainGrid">
   <Rectangle Fill="CornflowerBlue" 
           RadiusX="5" RadiusY="5" 
           ClipToBounds="True">
   </Rectangle>
   <StackPanel Orientation="Horizontal"  Margin="10">
       <!-- Use twoway if you want to your binding to post back to your vm -->
       <TextBox Text="{Binding Path=State.Name, Mode=TwoWay}" 
                Background="Transparent"/>            
       <Polygon Points="0,0 20,0 10,10" 
                Fill="DarkSlateGray" 
               Margin="10,5,0,0"/>
   </StackPanel>
</Grid>

TransitionView:

<Canvas>
   <Line X1="{Binding SourceState.Position.X}"
      Y1="{Binding SourceState.Position.Y}"
      X2="{Binding TargetState.Position.X}"
      Y2="{Binding TargetState.Position.Y}"
      Stroke="DarkGreen"
      StrokeThickness="4"/>
</Canvas>

现在您从列表项中继承数据上下文,而不是为列表中的每个项目创建一个新的视图模型作为数据上下文,我认为这是您的问题。顺便说一句,这些 ViewModels 用于提到的两个视图,它们是数据模型吗?确保在所有嵌套类中实现INotifyPropertyChanged。您是否考虑过使用 ViewModelLocator BTW? 我非常喜欢 GalaSoft MVVM Light。

干杯

【讨论】:

  • 感谢您的回答。当然, OnPropertyChanges 调用是多余的。我尝试了您的更改,但这并没有改变任何东西。 ViewModel 具有数据模型的属性,所有 ViewModel 都扩展了实现 INotifyPropertyChanged 的​​ BaseViewModel。如果我不设置 dataContext,视图从哪里获取数据?
  • @Zarzan 很高兴看到你做的事情如你所描述的那样好,总是很高兴听到! :) 不幸的是,我在这里有点着急,所以我现在无法重新创建您的项目。 There is a similar case here。数据上下文应该从您的 StateChartViewModel 继承,或者在您的项目控件中,每个项目都将被赋予列表中项目的数据上下文。
  • 我稍微编辑了我的问题,以便更清楚想要什么。我认为 ViewModelLocator 用于显示不同的 ViewModel 但不是同时显示?还是在我的情况下也有用?
猜你喜欢
  • 2013-01-02
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 2016-02-21
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
相关资源
最近更新 更多