【问题标题】:WPF MVVM and View inheritanceWPF MVVM 和视图继承
【发布时间】:2011-09-27 07:49:55
【问题描述】:

我有大约十几个不同的视图,除了它们绑定到的属性的名称外,它们几乎相同。例如,以下部分是两种不同的视图:

<TextBlock Text="{Binding PersonName}">       
<GroupBox Header="{Binding PersonName}">
  <ComboBox Text="{Binding SelectedPersonName}" SelectedItem="{Binding SelectedPerson}" ItemsSource="{Binding People}" DisplayMemberPath="PersonName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding PersonEntries}"


<TextBlock Text="{Binding CarName}">       
<GroupBox Header="{Binding CarName}">
  <ComboBox Text="{Binding SelectedCarName}" SelectedItem="{Binding SelectedCar}" ItemsSource="{Binding Cars}" DisplayMemberPath="CarName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding CarEntries}"

请注意,这些与块之间唯一真正的区别是所使用的绑定的名称(Person vs Car)。

我正在考虑创建一个其他视图继承自的 BaseView 类。这个基类将使用足够通用的绑定名称,以便可以重复使用,例如:

<TextBlock Text="{Binding DataItemName}">       
<GroupBox Header="{Binding DataItemName}">
  <ComboBox Text="{Binding SelectedDataItemName}" SelectedItem="{Binding SelectedDataItem}" ItemsSource="{Binding DataItems}" DisplayMemberPath="DataItemName"/>
</GroupBox>
<igDP:XamDataGrid DataSource="{Binding DataItemEntries}"

这样,我的 PersonsView 和 CarsView 可以从 BaseView 继承,仅此而已。不过,我还必须对 ViewModel 进行更改,以便它们公开正确命名的属性,例如 DataItem。我想我可以创建一个基本的 ViewModel 接口来公开所需的属性并让其他 ViewModel 实现它。

对以上内容有什么想法吗?像我描述的那样尝试创建基本视图或基本视图模型是不是一个坏主意?

谢谢。

【问题讨论】:

  • 我之前使用过类似的设置,效果很好。我会说这是非常主观的,并且取决于项目。

标签: c# wpf mvvm


【解决方案1】:

也许您可以继续拥有一个通用视图模型,但改为拥有多个 数据层。这基本上可以帮助您推动数据层的复杂性, 基本上更容易测试和调试。但是一切都太依赖上下文了。 祝你好运。

【讨论】:

    【解决方案2】:

    你真的要在你的视图模型中创建继承,而不是你的视图。我会定义一个ItemViewModelBase 类,它公开ItemNameItemsSelectedItemName 属性并从中派生我的视图模型。

    视图本身并没有真正“继承”。实际上,除非您需要在视图中进行自定义,否则您不需要多个视图:您只需要一个呈现ItemViewModelBase 对象的视图。

    当然,如果您确实需要不同的视图,您可以进行一定程度的自定义,例如:

    <DataTemplate DataType="{x:Type CarsViewModel}">
       <DockPanel>
          <Label DockPanel.Dock="Top">Cars</Label>
          <local:ItemView/>
       </DockPanel>
    </DataTemplate>
    

    这是一个很酷的想法,还有另一个原因。现在,如果您不提供数据模板,那么每当 WPF 呈现一个对象时,它都会创建一个包含object.ToString()TextBlock。实现通用基类为您提供了一种仅通过创建一个数据模板来全局覆盖此行为的方法,例如:

    <DataTemplate DataType="{x:Type ItemViewModelBase}">
       <TextBlock Text="{Binding ItemName}"/>
    </DataTemplate>
    

    这并不比重写ToString() 以返回ItemName(这是我要开始的地方)更容易,但是如果(例如)您想要一个ToolTip,当用户将鼠标悬停在它上面时会显示详细信息,你只需将它添加到这个模板中,它就可以在你的 UI 中随处使用。

    【讨论】:

    • 谢谢罗伯特。我现在正在创建一个 ItemViewModelBase 类并且有一个问题。 ItemViewModelBase 是一个抽象类,我想定义适当的属性(ItemName、Items 等)。我的 Items 属性是 ObservableCollection: public virtual ObservableCollection??> Items { get;放; }。我会将什么作为集合类型?从该基类派生的类将具有不同的列表()。基础视图模型是放置属性的正确位置吗?我确实希望所有派生类都实现它,所以看起来确实如此。
    • 另一个问题。假设我不需要对我的视图进行任何自定义。在这种情况下,我只需要一个视图。目前尚不清楚我将如何设置它。是否建议我为 ItemViewModelBase 创建一个 DataTemplate 和一个单独的视图(用户控件)来表示它?我之前没有将 DataTemplates 与 mvvm 一起使用,所以我试图弄清楚。现在我使用 Unity 注册我的视图模型,当创建 veiw 时,视图模型被注入到视图中。当我尝试创建视图时,如何区分驱动视图模型?
    • 就您的第一个问题而言,我会开始将其设为ObservableCollection&lt;object&gt;,看看这是否会造成任何麻烦。对于第二个问题,如果您创建一个DataTemplate,其DataTypeItemViewModelBase,它将用于呈现您的所有ItemViewModelBase 对象,除非您为其中一个子类创建特定模板。在 MSDN 上查找数据模板选择,了解在没有 Unity 的情况下模板选择如何工作的信息;它非常强大。
    猜你喜欢
    • 1970-01-01
    • 2017-11-14
    • 1970-01-01
    • 2013-09-20
    • 2022-10-07
    • 2011-06-19
    • 2013-07-07
    • 1970-01-01
    • 2013-11-08
    相关资源
    最近更新 更多