Awk*_*der 27 wpf model-view-controller viewmodel
我有一个由几个用户控件组成的窗口,并且想知道每个用户控件是否有自己的ViewModel,或者整个窗口是否只有一个ViewModel?
小智 40
绝对,积极
你的用户控件应该不具有专为他们设计的ViewModels.事实上,这是一种代码味道.它不会立即破坏您的应用程序,但在您使用它时会让您感到痛苦.
UserControl只是使用合成创建Control的简单方法.UserControls仍然是控件,因此应该只关注UI的问题.
为UserControl创建ViewModel时,您要么在其中放置业务逻辑或UI逻辑.使用ViewModels包含UI逻辑是不正确的,因此如果这是您的目标,请丢弃您的VM并将代码放在该控件的代码隐藏中.如果您将业务逻辑放在UserControl中,很可能您正在使用它来隔离应用程序的各个部分,而不是简化控件创建.控件应该简单,并且具有设计它们的单一目的.
为UserControl创建ViewModel时,还可以通过DataContext中断自然的数据流.这是您将经历最痛苦的地方.为了演示,请考虑这个简单的例子.
我们有一个包含People的ViewModel,每个都是Person类型的一个实例.
public class ViewModel
{
public IEnumerable<Person> People { get; private set; }
public ViewModel()
{
People = PeopleService.StaticDependenciesSuckToo.GetPeople();
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在我们的窗口中显示人员列表是微不足道的.
<Window x:Class="YoureDoingItWrong.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:YoureDoingItWrong"
Title="Derp">
<Window.DataContext>
<l:ViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type l:Person}">
<l:PersonView />
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding People}" />
</Window>
Run Code Online (Sandbox Code Playgroud)
该列表自动为Person选择正确的项目模板,并使用PersonView向用户显示该人的信息.
什么是PersonView?它是一个UserControl,旨在显示此人的信息.它是一个人的显示控件,类似于TextBlock是文本的显示控件.它旨在绑定一个人,因此工作顺利.请注意上面的窗口中ListView如何将每个Person实例传输到PersonView,在PersonView中它成为此视觉子树的DataContext.
<UserControl x:Class="YoureDoingItWrong.PersonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Label>Name</Label>
<TextBlock Text="{Binding Name}" />
<Label>Age</Label>
<TextBlock Text="{Binding Age}" />
</StackPanel>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
为了使其顺利运行,UserControl的ViewModel 必须是它所针对的Type的实例.当你通过做愚蠢的事情来打破这个
public PersonView()
{
InitializeComponent();
this.DataContext = this; // omfg
}
Run Code Online (Sandbox Code Playgroud)
要么
public PersonView()
{
InitializeComponent();
this.DataContext = new PersonViewViewModel();
}
Run Code Online (Sandbox Code Playgroud)
你已经破坏了模型的简洁性.通常在这些情况下,您最终会得到令人憎恶的变通方法,其中最常见的是为DataContext 实际应用的内容创建伪DataContext属性.现在你不能将一个绑定到另一个,所以你最终会遇到糟糕的黑客
public partial class PersonView : UserControl
{
public PersonView()
{
InitializeComponent();
var vm = PersonViewViewModel();
// JUST KILL ME NOW, GET IT OVER WITH
vm.PropertyChanged = (o, e) =>
{
if(e.Name == "Age" && MyRealDataContext != null)
MyRealDataContext.Age = vm.PersonAge;
};
this.DataContext = vm;
}
public static readonly DependencyProperty MyRealDataContextProperty =
DependencyProperty.Register(
"MyRealDataContext",
typeof(Person),
typeof(PersonView),
new UIPropertyMetadata());
public Person MyRealDataContext
{
get { return (Person)GetValue(MyRealDataContextProperty); }
set { SetValue(MyRealDataContextProperty, value); }
}
}
Run Code Online (Sandbox Code Playgroud)
您应该将UserControl视为一个更复杂的控件.TextBox是否有自己的ViewModel?不可以.将VM的属性绑定到控件的Text属性,控件在其UI中显示文本.
MVVM不代表"无代码隐藏".将用户控件的UI逻辑放在代码隐藏中.如果它太复杂以至于您需要在用户控件中使用业务逻辑,那么这表明它太过笼统.简化!
想想MVVM中的UserControls - 对于每个模型,您都有一个UserControl,它旨在将该模型中的数据呈现给用户.您可以在任何想要向用户显示该模型的地方使用它.它需要一个按钮吗?在UserControl上公开ICommand属性,并让您的业务逻辑绑定到它.您的业务逻辑是否需要知道内部发生的事情?添加路由事件.
通常情况下,在WPF中,如果你发现自己问为什么做某事很痛,那是因为你不应该这样做.
Ken*_*art 15
这不是一个是或否的问题.这取决于是否有额外的视图模型为您提供更好的可维护性或可测试性.添加视图模型是没有意义的,如果它没有获得任何东西.您需要根据特定用例来衡量开销是否值得.
Pet*_*iho 11
[应该] 每个用户控件都有自己的 ViewModel 还是整个窗口应该只有一个 ViewModel?
不幸的是,这个问题的最高投票答案具有误导性,并且基于我在其他问题中交换的评论,为尝试学习 WPF 的人提供了糟糕的指导。那个回答回复:
你的用户控件应该不具有专为他们设计的ViewModels。
问题是,这不是被问到的问题。
我同意一般观点,即当您编写一个 时UserControl,控件的公共 API 不应该还涉及创建专门用于该控件的视图模型类型。客户端代码必须能够使用它想要的任何视图模型。
但是,这并不排除“每个用户控件 [可能] 拥有自己的 ViewMomdel”的想法。我能想到的至少有两个明显的场景,其中的答案是“是的,每个用户控件都有一个视图模型”:
用户控件是项目展示器(例如ItemsControl)中数据模板的一部分。在这种情况下,视图模型将对应于每个单独的数据元素,并且视图模型对象和呈现该视图模型对象的用户控件之间将存在一对一的对应关系。
在这种情况下,视图模型对象不是“专门为他们设计的”(因此与有问题的答案没有矛盾),但肯定是每个用户控件都有自己的视图模型(对实际问题做出回答)是的,每个用户控件都可能有自己的视图模型”)。
用户控件的实现受益于甚至需要专门为用户控件设计的视图模型数据结构。这个视图模型数据结构不会暴露给客户端代码;这是一个实现细节,因此将使用用户控件从客户端代码中隐藏。但是,这肯定仍然是“专为”该用户控件设计的视图模型数据结构。
这种情形显然不是在所有的,这直接违背了声称有问题“你的用户控件应该不具有专为他们设计的ViewModels。”
现在,我不相信该答案的作者的意图是排除这两种情况中的任何一种。但问题是,试图学习 WPF 的人可能没有足够的上下文来识别差异,因此可能会根据这个强调、高度赞成和误导性的答案错误地概括用户控件和视图模型。
我希望通过提出这个替代观点作为澄清点,并以不那么狭隘的方式回答原始问题,那些在更多地了解 WPF 的同时发现这个问题的人将拥有更好的背景、更好的想法和何时可以实现特定于用户控件的视图模型以及何时不应该实现。
Mar*_*ann 10
我会说每个用户控件都应该有自己的ViewModel,因为这将允许您将来在新的星座中重用ViewModel/UserControl对.
据我所知,您的窗口是用户控件的复合,因此您始终可以创建一个ViewModel,它为每个用户控件组成所有单独的ViewModel.这将为您提供两全其美的体验.
| 归档时间: |
|
| 查看次数: |
11353 次 |
| 最近记录: |