在MVVM应用程序的ViewModel中将新字段添加到Model集合的最佳方法是什么?

时间:2017-08-30 07:12:28

标签: wpf mvvm collections binding

我正在使用MVVM Light编写具有MVVM结构的WPF应用程序。 我在模型中有Foo课程:

class Foo: ObservableObject
{
    private string _propA = String.Empty;
    public string PropA
    {
        get => _propA ;

        set
        {
            if (_propA == value)
            {
                return;
            }

            _propA = value;
            RaisePropertyChanged("PropA");
        }
    }

    // same for property PropB, PropC, PropD, etc.
}

我在模型中有一些Foo个对象:

class FooCollection: ObservableObject
{
    private ObservableCollection<Foo> _items = null;
    public IEnumerable<Foo> Items 
    {
        get { ... }
        set { ... }
    } 

    public string Name { get; set; }

    // ...
    // and other methods, properties and fields
}

现在我有了一个ViewModel,其中这个列表是通过一些注入的提供者填充的:

class MainWindowModel: ViewModelBase
{
     private FooCollection _fooList;

     public FooList 
     {
         get => _fooList;
         set 
         {
             _fooList = value;
             RaisePropertyChangedEvent(FooList);
         }
     }

     public MainWindowModel(IFooListProvider provider)
     {
         FooList = provider.GetFooList();
     } 
}

视图,MainWindowModel作为数据上下文:

<TextBlock Text={Binding FooList.Name} />
<ItemsControl ItemsSource="{Binding FooList.Items}">
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <TextBlock Text={Binding PropA} />
             <Button Content={Binding PropB} />
             <!-- other controls with bindings -->
         </DataTemplate>
     </ItemsControl.ItemTemplate>
</ItemsControl>

一切正常,我可以删除和添加新项目,编辑它们等。视图中的所有更改都会在ViewModel和Model中通过绑定和可观察对象自动反映,反之亦然。

但现在我需要将ToggleButton添加到ItemsControl的数据模板,该模板控制窗口其他部分中特定项目的可见性。我在ViewModel中需要IsChecked值,因为窗口其他部分的控件是Windows窗体控件,如果没有ViewModel,我无法直接绑定IsChecked。 但我不想在模型类(Foo,FooCollection)中添加新属性(例如,Visibility),因为它只是一个接口事物而且不需要保存或传递到ViewModel之外的某个地方。

所以我的问题:在ViewModel中向Model集合添加新属性的最佳方法是什么?

我可以在ViewModel(某种class Wrapper { Foo item, bool Visibility })中创建新的包装器集合并将其绑定到ItemsControl。但在这种情况下,我必须手动控制添加,删除和编辑,并将所有更改从List<Wrapper>转移到FooList.Items,所以我不喜欢这个解决方案。有没有更简单的方法来实现这一目标?

版本澄清问题。现在我有:

<ItemsControl ItemsSource="{Binding FooList.Items}">
     <ItemsControl.ItemTemplate>
         <DataTemplate>
             <TextBlock Text={Binding PropA} />
             <Button Content={Binding PropB} />
             <ToggleButton IsChecked={Binding ????????????} />
             <!-- other controls with bindings -->
         </DataTemplate>
     </ItemsControl.ItemTemplate>
</ItemsControl>

我在类中没有绑定IsChecked的字段,我不想将它添加到类中,因为它只是接口事物而不是数据模型字段。例如,我如何创建另一个bool集合并将其与ItemControl一起绑定到此FooList.Items

2 个答案:

答案 0 :(得分:1)

添加属性的最佳位置当然是Foo类。

创建另一个其他类型的集合,在当前集合中为每个Foo对象添加一个对象,然后绑定到这个新对象的某个属性似乎是一个非常糟糕的解决方案,而不是简单地添加一个当前班级的财产。

Foo不是&#34;接口的东西&#34;,或者至少它不应该是。视图模型应该包含视图绑定的属性。向其添加IsChecked属性没有任何问题。这听起来肯定是您案例中的最佳解决方案。

答案 1 :(得分:0)

我不确定我是否理解为什么你需要在模型中添加属性。

您不能只使用命令属性或将EventTrigger添加到切换按钮吗? (参见Sega和Arseny对这两个例子的回答Executing a command on Checkbox.Checked or Unchecked

这样,当您检查toggleButton时,viewModel中有一个方法可以启用或禁用Winform控件的visibility属性。

要从viewModel中的命令更改控件的可见性,可以使用MVVM LIGHT的messenger功能 MVVM Light Messenger - Sending and Registering Objects

ViewModel向您发送一条消息是Windows Forms,并且这个消息处理您的控件的可见性。