0

我正在开发 WPF/MVVM 中的标准数据输入应用程序。我有一个名为 LabSetupView.xaml 的文件,其中包含三个控件:

  1. 用于显示可用实验室的组合框
  2. 用于显示技术人员的组合框
  3. 用于测试的 ListView

这些控件旨在协同工作 - 当用户选择技术人员时,仅显示该技术人员 ID 的测试。这是通过 Technician to Tests 上的导航属性完成的。

我正在考虑将这些控件移动到各自的 .xaml 文件中<UserControl>,然后将它们嵌套在其中,<Window>因为 LabSetupView.xaml 的 DataContext 只能设置一次。所以,我想如果我将控件组件化,我可以为每个控件拥有 ViewModel(即 LabView.xaml/LabViewModel.xaml 等),并且每个都继承自一个实现必要的 ViewModelBase INotifyPropertyChanged

我的问题是:拥有一个本身没有数据上下文而是包含单独的用户控件的基板 .xaml 文件是一种常见的做法还是正常的做法,每个用户控件都有自己的数据上下文?

我问这个是因为我担心如果我尝试这样的事情,那么数据绑定和 INotifyProperChanged 将无法一起工作,因为这些视图是组件化的。换句话说,我上面的用例(获取技术人员的测试)不会绑定或更新属性。

4

1 回答 1

3

您当然可以让您的主视图(基板 .xaml 文件,如您在上面描述的那样)没有DataContext然后分配DataContext特定子控件,无论它们是否UserControls

但是,根据您的描述,您可能需要考虑将 Composition 与您的 ViewModel 一起使用。在这种情况下,您将拥有一个 MainViewModel,它具有表示 ChildViewModel(技术人员和测试)的属性。这些子 ViewModel 可以通过 MainViewModel 进行通信,也可以不通过 MainViewModel 进行通信,具体取决于您想要如何组合。然后,DataContext主视图的 将是 MainViewModel,而UserControls将只是DataBind该视图模型的属性。

它可能看起来像这样:

public class MainViewModel : BaseViewModel
{
    public TechnicianViewModel Technician { get { return _technician; } }
    public TestViewModel Test { get { return _test; } }
    ...
}

XAML 的缩写示例如下所示(假设 MainViewModel 已设置为 Window 的 DataContext):

<Window x:Class="MainView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

      <StackPanel>
           <local:TechnicianView DataContext="{Binding Technician}"/>
           <local:TestView DataContext="{Binding Test}"/>
      </StackPanel>

</Window>

这就是我解决上述场景类型的方法,并且效果很好。当您可以使用 IoC/DI 通过 IoC 容器注入子视图模型时,它工作得很好。

已编辑

根据您在下面的评论/问题,一些额外的细节。您询问如何在选定的技术人员和该技术人员可用的测试之间建立关系。处理此问题的一种方法是让 TestsViewModel 成为 TechnicanViewModel 的子项。因此,例如,您可以拥有以下内容:

public class MainViewModel : BaseViewModel
{
    public IEnumerable<TechnicianViewModel> AvailableTechnicians { get { return _technicians; } }
    public TechnicianViewModel SelectedTechnician 
    { 
        get { return _selected; } 
        set 
        { 
            _selected = value; 
            RaiseNotifyPropertyChanged("SelectedTechnician");
        } 
    }
    ...
}

public class TechnicianViewModel : BaseViewModel
{
    public IEnumerable<TestViewModel> Tests { get { return _tests; } }
}

然后在您的 XAML 中:

<StackPanel>
     <ListBox ItemsSource="{Binding AvailableTechnicians}" SelectedItem="{Binding SelectedTechnician, Mode=TwoWay}"/>
     <ListBox ItemsSource="{Binding SelectedTechnician.Tests}"/>
</StackPanel>

这将使测试ListBox与技术人员中选定的技术人员同步ListBox。这只是一个示例(在文本编辑器中编写,如果我有任何错误,则不是 VS),而是处理您正在讨论的那种关系的一种方法。

于 2013-02-22T16:16:16.320 回答