【问题标题】:What is the best way to add new field into Model collection in ViewModel in MVVM app?在 MVVM 应用程序的 ViewModel 中将新字段添加到模型集合中的最佳方法是什么?
【发布时间】:2018-02-07 19:13:38
【问题描述】:

我正在使用 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>

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


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

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

我可以在 ViewModel 中创建新的包装器集合(某种class Wrapper { Foo item, bool Visibility })并将其绑定到ItemsControl。但在这种情况下,我必须手动控制添加、删除和编辑,并将所有更改从List&lt;Wrapper&gt; 转移到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

【问题讨论】:

  • 要绑定的 IsChecked 属性在哪里定义...?
  • 如何在 WinForms 控件中绑定/填充FooList.Items
  • @SeeSharpCode 我不绑定它。 WinForms 控件是旧的 3D 可视化控件 (VTK)。
  • @mm8 这就是问题所在。如果我不能在 Foo 类中定义它,我应该在哪里定义它以及如何绑定它。
  • 你应该在 Foo 类中定义它。看我的回答。 Foo 不应被视为“接口事物”。那是你的问题。

标签: wpf mvvm collections binding


【解决方案1】:

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

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

Foo 不是“接口的东西”,或者至少不应该是。视图模型应该包含视图绑定到的属性。向其中添加 IsChecked 属性没有任何问题。在您的情况下,这听起来确实是最好的解决方案。

【讨论】:

  • 我认为问题在于向模型类添加特定于视图的属性。我在这里看不到 Foo 作为视图模型。
  • 它是/应该是视图模型。直接绑定到域对象不是很常用。
  • Foo 不是接口的东西。 IsVisible 属性是接口的东西。这就是为什么我不想在模型类中添加仅接口属性。
  • 你没有抓住重点; Foo 不应该是模型类。它是一个视图模型,具有视图绑定到的属性。您通常不会绑定到没有“接口”属性的域对象。这是你的问题。
  • @mm8 您是否建议为域对象创建一些包装器,该包装器将具有“接口”属性?
【解决方案2】:

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

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

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

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

ViewModel 向您的 Windows 窗体发送一条消息,这个消息处理您的控件的可见性。

【讨论】:

  • 当然,当用户单击 ToggleButton 时,我可以附加一个事件处理程序、一个命令或任何可调用的对象,但这并不能解决问题:ViewModel 没有绑定到切换按钮的属性.问题是如何在集合中添加一个新字段,我可以在不触及 Model 类本身的情况下将新的用户控件绑定到该字段。
猜你喜欢
  • 1970-01-01
  • 2010-11-07
  • 1970-01-01
  • 2014-04-28
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-20
相关资源
最近更新 更多