MVVM 中的数据模板是否已过时?
我创建了以下模型(简化了代码以说明情况):
public abstract class Account
{
public string Name { get; set; }
}
public class Person : Account
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Company : Account
{
public string Owner { get; set; }
}
接下来我创建了一个视图模型:
public class ViewModel
{
public Account Model { ... }
public string Name { ... }
public string FirstName { ... }
public string LastName { ... }
public string Owner { ... }
...
}
最后是视图:
<UserControl>
<UserControl.Resources>
<!-- Person data template -->
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />
</Grid>
</DataTemplate>
<!-- Company data template -->
<DataTemplate x:Key="companyTemplate" DataType="{x:Type model:Company}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Owner}" />
</Grid>
</DataTemplate>
<!-- Data template selector for different account types -->
<local:AccountTemplateSelector x:Key="templateSelector"
PersonTemplate="{StaticResource personTemplate}"
CompanyTemplate="{StaticResource companyTemplate}" />
</UserControl.Resources>
<StackPanel Name="rootLayout" DataContext="{Binding Path=viewModel}">
<ContentControl Content="{Binding Path=Model}"
ContentTemplateSelector="{StaticResource templateSelector}"/>
<Button Content="Save" />
<Button Content="Close" />
</StackPanel>
</UserControl>
因此,当加载的模型为 Person
类型时显示 personTemplate
;反之亦然,当模型为 Company
时,将显示 companyTemplate
。
我的问题是:
- 这种方法有意义吗?删除
模型
会更聪明吗ViewModel
类中的属性,并引入一个枚举或只是一个简单的bool
如果true
则显示个人,如果“false”则显示公司? - 在定义数据模板时,我将
DataType
指定为Person
和Company
类型(对我来说这样做是很自然的)。我是否需要它,因为在最 下一行我将新的数据上下文设置为来自UserControl
? - 数据模板的 DataType 是否应该是不同的视图模型,例如
PersonViewModel
和CompanyViewModel
?创建它们有意义吗? - 我怎样才能,我到底能不能让数据模板继承数据上下文
ContentControl
自动?
我知道这一切最终都是个人选择的问题,但由于我正在学习 MVVM(我正在使用 MVVM Light),我想知道哪种方法是最值得推荐的?我仍然不完全理解何时应将模型中的类用作数据模板的数据类型以及何时应将视图模型用于此目的。表示模型的程序集是否应该在视图程序集中引用(假设视图、模型和视图模型都驻留在单独的程序集中)?
感谢您的所有澄清!
更新:
此更新应该解释当模型类的属性未直接绑定到一个控件时,将模型类作为数据模板中的 DataType
的问题视图中。
Person
中有一个枚举和一个新属性,所以现在看起来像这样:
public class Person : Account
{
public enum GenderType { Female, Male, NotSpecified }
public string FirstName { get; set; }
public string LastName { get; set; }
public GenderType Gender {get; set; }
}
在视图中,person 的数据模板当然也发生了变化:
<!-- Person data template -->
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />
<RadioButton Name="Female" />
<RadioButton Name="Male" />
<RadioButton Name="NotSpecified" />
</Grid>
</DataTemplate>
如果 Content
设置为 ContentControl
的ViewModel
的 Model
属性,我将如何解决性别/单选按钮的情况;因为,现在它们以一个控件/一个属性的方式不匹配?
I have created the following model (the code is simplified to illustrate the situation):
public abstract class Account
{
public string Name { get; set; }
}
public class Person : Account
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Company : Account
{
public string Owner { get; set; }
}
Next I have created a view model:
public class ViewModel
{
public Account Model { ... }
public string Name { ... }
public string FirstName { ... }
public string LastName { ... }
public string Owner { ... }
...
}
And finally, the view:
<UserControl>
<UserControl.Resources>
<!-- Person data template -->
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />
</Grid>
</DataTemplate>
<!-- Company data template -->
<DataTemplate x:Key="companyTemplate" DataType="{x:Type model:Company}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=Owner}" />
</Grid>
</DataTemplate>
<!-- Data template selector for different account types -->
<local:AccountTemplateSelector x:Key="templateSelector"
PersonTemplate="{StaticResource personTemplate}"
CompanyTemplate="{StaticResource companyTemplate}" />
</UserControl.Resources>
<StackPanel Name="rootLayout" DataContext="{Binding Path=viewModel}">
<ContentControl Content="{Binding Path=Model}"
ContentTemplateSelector="{StaticResource templateSelector}"/>
<Button Content="Save" />
<Button Content="Close" />
</StackPanel>
</UserControl>
So, when the model that is loaded is of type Person
the personTemplate
is shown; vice versa, when the model is Company
the companyTemplate
is shown.
My questions are:
- Does this approach make sense at all? Would it be smarter to delete the
Model
property in theViewModel
class and to introduce an enum or just a simplebool
which would show person iftrue
, or company if `false? - While defining the data templates, I specified
DataType
s toPerson
andCompany
types (it was natural to me to do it this way). Do I need it at all because in the very
next line I am setting a new data context to be the one from theUserControl
? - Should the
DataType
s of the data templates be different view models, something likePersonViewModel
andCompanyViewModel
? Does it make sense to create them? - How can I, and can I at all, make data template inherit the data context from the
ContentControl
automatically?
I know that all this is a matter of a personal choice in the end, but since I am learning MVVM (I am using MVVM Light), I am wondering which approach would be the most recommendable one? I still do not fully understand when should the classes from models be used as data types for data templates and when should view models be used for that purpose. Should the assembly that represents the model even be referenced in the view assembly (assuming that view, model and view model all reside in separate assemblies)?
Thanks for all the clarifications!
UPDATE:
This update should explain the problem of having classes of the model as DataType
s in the data templates when the property of the model class is not directly binded to just one control in the view.
There is an enum and a new property in the Person
, so now it looks like this:
public class Person : Account
{
public enum GenderType { Female, Male, NotSpecified }
public string FirstName { get; set; }
public string LastName { get; set; }
public GenderType Gender {get; set; }
}
And in the view, the data template of the person is changed as well of course:
<!-- Person data template -->
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}">
<Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}">
<TextBlock Text="{Binding Path=Name}" />
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />
<RadioButton Name="Female" />
<RadioButton Name="Male" />
<RadioButton Name="NotSpecified" />
</Grid>
</DataTemplate>
If the Content
of the ContentControl
is set to Model
property of the ViewModel
, how would I resolve the gender/radio buttons situation; because, now they do not match in the way one control/one property?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会将其更改为:
像这样,您可以为类定义隐式样式,并且不必使用模板选择器。另外,您不需要
ViewModel
类中的所有字符串属性:免责声明,RadioButtons 中的绑定使用 此处。
I would change it to this:
like this you define implicit styles for your classes and you don't have to use a templateselector. Also then you don't need all your string properties in the
ViewModel
class:Disclaimer, the binding in the RadioButtons uses a Converter from here.
绝对不是(它们已经过时了吗)。
Account
属性选择模板。这样,您可以将 ItemsSource 直接绑定到 DataContext,并且它将在 DataTemplate 中可用。Absolutely positively not (are they obsolete).
Account
property. That way, you can bind the ItemsSource directly to the DataContext, and it will be available within the DataTemplate.