在用户控件中设置DataGrid的ItemsSource

时间:2014-01-22 15:52:23

标签: wpf mvvm binding wpf-controls datacontext

此示例是我的要求的简化版本。如果我能解决这个问题,那么剩下的就很简单了(我希望)。假设我有一个

的类层次结构

A类:

Name
List <Class B>


B类:

Name
List <Class C>


C类:

Name

每个类都有一个单独的视图,视图模型和模型。我的主视图将每个视图放在DockPanel中。每个类的视图都是一个DataGrid,它只是放置每个列表的名称。当我点击A类的名字时,它会显示下面B类的名字。当我单击B类的名称时,它会显示C类的名称。所以基本上3个用户控件都是在我的MainView中的dockpanel上显示的所有DataGrid控件。

我仍然在MVVM中找到自己的脚,我不确定这是否是最好的方法。我想要的方法是每个视图模型都有一个名为SelectedItem的属性绑定到其视图中DataGrid中的SelectedItem。设置该属性后,将设置另一个名为ChildViewModel的属性。但我不知道如何在我的MainView和每个控件中设置它。如何将控件绑定到它的父datacontext,以及如何将项源绑定到父项中的选定项?

1 个答案:

答案 0 :(得分:0)

我将有一个ViewModel,它是Window / UserControl / etc的DataContext,这些控件都被分组。然后设置ClassA加3个SelectedItem属性的集合。在SelectedItem属性中,您需要将下一个设置为null或默认值。

private ObservableCollection<ClassA> _CollectionOfA;
public ObservableCollection<ClassA> CollectionOfA 
{
   get { return _CollectionOfA; }
   set
   {
      if (value == _CollectionOfA)
         return;
      _CollectionOfA = value;
      RaisePropertyChanged(() => CollectionOfA);
   }
}

private ClassA _SelectedClassA;
public ClassA SelectedClassA 
{
   get { return _SelectedClassA; }
   set
   {
      if (value == _SelectedClassA)
         return;
      _SelectedClassA = value;
      SelectedClassB = null; //Or default this to first item in the list, etc.
      RaisePropertyChanged(() => SelectedClassA);
   }
}

//Repeat SelectedClassA pattern for SelectedClassB/SelectedClassC
public ClassB SelectedClassB { get; set; }
public ClassC SelectedClassC { get; set; }

然后在绑定中,您将使用SelectedClassA.CollectionOfClassB属性作为第二个DataGrid的ItemsSource等。

<DataGrid ItemsSource="{Binding CollectionOfClassA}" SelectedItem="{Binding SelectedClassA}">
    //columns defined here
</DataGrid>
<DataGrid ItemsSource="{Binding SelectedClassA.CollectionOfClassB}" SelectedItem="{Binding SelectedClassB}">
    //columns defined here
</DataGrid>
<DataGrid ItemsSource="{Binding SelectedClassB.CollectionOfClassC}" SelectedItem="{Binding SelectedClassC}">
    //columns defined here
</DataGrid>

修改 第一个选项是KISS方法。另一个选择是使用MVVM Light之类的东西,通过它的weak event pattern类实现messenger。在第二个ViewModel的构造函数中,您注册以侦听第一个ViewModel中SelectedItem的更改。在第一个ViewModel的setter中,您发送一条SelectedItem已更改的消息。下面是ClassBViewModel的示例(ClassAViewModel只需要其SelectedClassA setter来发送消息,构造函数中没有侦听器。而ClassCViewModel会监听但不需要发送)。

public class ClassBViewModel : ViewModelBase
{
   private ClassA _SelectedClassA;
   public ClassA SelectedClassA 
   {
      get { return _SelectedClassA; }
      set
      {
         if (value == _SelectedClassA)
            return;
         _SelectedClassA = value;
         RaisePropertyChanged(() => SelectedClassA);
      }
   }

   private ClassB _SelectedClassB;
   public ClassB SelectedClassB
   {
      get { return _SelectedClassB; }
      set
      {
          if (value == _SelectedClassB)
             return;
          var oldValue = _SelectedClassB;
          _SelectedClassB = value;
          Messenger.Default.Send(new PropertyChangedMessage<ClassB>(oldValue, value, "SelectedClassB"));
          RaisePropertyChanged(() => SelectedClassB);
      }
   }

   public ClassBViewModel()
   {
      Messenger.Default.Register<PropertyChangedMessage<ClassA>>(this, (message) => SelectedClassA = message.NewValue);
   }
}

DataGrid的ClassBView xaml看起来仍然相同:

<DataGrid ItemsSource="{Binding SelectedClassA.CollectionOfClassB}" SelectedItem="{Binding SelectedClassB}">
    //columns defined here
</DataGrid>