2

我试图掌握 ViewModelLocator 的概念(在 MVVM Light 中,尽管问题通常适用于 ViewModelLocator 的概念,无论使用哪个 MVVM 框架),我很难弄清楚如何使用它。

据我了解,您的视图使用定位器的单例实例上的属性之一作为它们的数据上下文。定位器定义了这些不同的属性,并为每个属性返回正确的视图模型实例。

这一切都很好,但我很难理解你是如何用视图应该呈现的模型数据实际填充这些视图模型的。

例如,假设我有一个显示员工列表的视图。我可以创建一个EmployeesView 和一个EmployeesViewModel。在 ViewModelLocator 中,我可以创建一个返回此EmployeesViewModel 的属性:

public EmployeesViewModel Employees
{
    get
    {
        return ServiceLocator.Current.GetInstance<EmployeesViewModel>();
    }
}

现在,viewmodel 需要一个员工列表,所以我可以创建某种返回所有员工的数据服务,并将其注册到 ViewModelLocator 的构造函数中的 Servicelocator:

public ViewModelLocator()
{
    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    SimpleIoc.Default.Register<IDataService, AllEmployeesDataService>();
}

因此,这将起作用,如果我实例化EmployeesView,EmployeesViewModel 将被实例化并注入一个返回所有员工的数据服务。

但是,现在我想查看刚刚在EmployeesView 中单击的某个员工的详细信息。该员工大概有某种 ID,可以通过它从数据库或其他任何地方检索他/她。

我可以创建一个 EmployeeDetailsView 和一个 EmployeeDetailsViewModel,并向 ViewModelLocator 添加一个属性:

public EmployeeDetailsViewModel EmployeeDetails
{
    return ServiceLocator.Current.GetInstance<EmployeeDetailsViewModel>();
}

也许在 ViewModelLocator 的构造函数中注册某种数据服务:

SimpleIoc.Default.Register<IDataService, EmployeeDetailsDataService>();

但是我如何告诉数据服务或视图模型他们应该为哪个员工提供详细信息?我在哪里传递员工 ID?

我看这一切都错了吗?有人知道任何好的例子吗?我能找到的所有示例都只返回每个视图模型的相同单个实例。

4

2 回答 2

0

我发现 J King 的回答非常好,但我希望能提供更多的信息和选择。

在评论中,您询问如果视图不同会发生什么?
这是我的一个实现:

<ListBox x:Name="YourListView"  
          ItemsSource="{Binding SomeCollection}"
          SelectedItem="{Binding SelectedItemObject, 
                            UpdateSourceTrigger=PropertyChanged}"
         ToolTip="Double click to edit"
          >
    <ListBox.ContextMenu>
        <ContextMenu>
            <MenuItem Header ="Edit me" Command="{Binding Edit_Command}" 
                      CommandParameter="{Binding SelectedItemObject}"
            />
            <MenuItem Header ="Delete me" Command="{Binding Delete_Command}" 
                       CommandParameter="{Binding SelectedItemObject}"
            />
        </ContextMenu>
    </ListBox.ContextMenu>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDoubleClick">
            <Command:EventToCommand Command="{Binding Edit_Command}" 
                            CommandParameter="{Binding ElementName=YourListView, 
                                                Path=SelectedItem}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>

</ListBox>

请注意,双击该列表中的对象,或右键单击并选择两个选项之一(即editdelete),将调用带有参数的命令。

现在,当您使用 时,ContextMenu因为您右键单击和对象,它被选中,您可以发送它。

在双击的情况下,我使用列表框的名称来获取项目。

从这里开始,我将在视图模型中执行如下操作:

private void Execute_Edit(object param)
{
    var your_object = (cast_to_your_type)param;
    Messenger.Default.Send(new SwitchView(new SomeViewModel(_dataService,your_object)));
}

ICommand 将调用Execute_Edit,而后者又将使用 Messenger 发送消息。

这就是我定义的方式SwitchView

/// <summary>
/// Used as message, to switch the view to a different one.
/// </summary>
public class SwitchView
{
    public SwitchView(MyViewModelBase viewmodel)
    {
        ViewModel = viewmodel;
    }

    public MyViewModelBase ViewModel { get; set; }
}

我的 MainWindow 已注册以收听这些消息,并且我们知道要更改什么(显然,对于给定的视图模型:)SomeViewModel。主SwitchView类上的 会将 ViewModel 属性更改为消息传递的属性。

这是我的主要观点:

<Border >
    <ContentControl Content="{Binding Current_VM}" />
</Border>

因此,无论Current_VM属性设置如何,都会向您显示该视图。

希望有帮助:)

于 2013-11-15T06:20:56.840 回答
0

我使用的一个简单示例是使用注入到视图模型的构造函数中的数据服务,就像您一样。该数据服务返回我的对象​​(在您的情况下为员工)的可观察集合。我在同一视图中创建了一个列表框和详细信息网格。因此,我将列表框绑定到可观察的集合,我可以使用 collectionviewsource 对其进行样式设置和排序。对于详细信息,我创建了一个包含我想要显示的必填字段的网格。我在视图模型中为列表框的选定项 (SelectedEmployee) 创建了一个属性,并将它们绑定在一起。然后我将详细信息网格绑定到 SelectedEmployee。这将导致字段显示来自所选员工的值。

现在您可以将它用于所有 CRUD 操作,您可以将列表框的 slecteditemchanged 事件绑定到中继命令并根据需要添加您的业务逻辑。另一件需要注意的是,您可以将其拆分以支持异步操作。我有另一个实现,我获取列表框的选定项更改事件并执行异步获取函数来获取选定项。

我希望这有帮助

于 2013-11-14T18:12:42.007 回答