MVVM 模式实现的正确方法
本文关键字:方法 模式 实现 MVVM | 更新日期: 2023-09-27 18:30:35
我正在尝试实现MVVM,所以我不知道以下内容是否正确。ViewModel似乎是视图的某种模型,因此视图中的关联应显示在ViewModel中,在这种情况下,ViewModels之间应存在一些关联。因此,通过为 ViewModel 类型创建一些模板,应用程序似乎可以工作,下面是一些示例代码:
视图模型:
public class SomeVm : INotifyPropertyChanged
{
public SomeVm()
{
SomeOtherVm = new SomeOtherVm();
}
public INotifyPropertyChanged SomeOtherVm { set; get; }
private int _a;
public int A
{
set {
_a= value;
B = value;
}
get { return _a; }
}
private int _b;
public int B
{
set
{
_b = value;
OnPropertyChanged("B");
}
get { return _b; }
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class SomeOtherVm : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _c;
public int C
{
set
{
_c = value;
D = value;
}
get { return _c; }
}
private int _d;
public int D
{
set
{
_d = value;
OnPropertyChanged("D");
}
get { return _d; }
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
和观点:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<wpfApplication1:SomeVm x:Key="SomeVm"/>
<DataTemplate DataType="{x:Type wpfApplication1:SomeVm}">
<StackPanel d:DesignWidth="339" d:DesignHeight="54">
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding A}" VerticalAlignment="Stretch"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding B}" VerticalAlignment="Stretch"/>
<ContentPresenter Content="{Binding SomeOtherVm}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type wpfApplication1:SomeOtherVm}">
<StackPanel d:DesignWidth="339" d:DesignHeight="54">
<TextBox HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding C}" VerticalAlignment="Stretch"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding D}" VerticalAlignment="Stretch"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentPresenter Content="{DynamicResource SomeVm}" />
</Grid>
</Window>
通过这种方式,可以在一些资源字典中创建所有视图,所以问题是:像这样使用 MVVM 是否正确?如果是,缺点是什么?
通常 ViewModel 应该是整个视图的 DataContext,即它应该是负责提供数据以呈现自身并侦听 UI 命令、事件和属性更改以与业务层(模型)交互的实体。
您实现它的方式是将虚拟机作为资源,并将其设置为内容而不是数据上下文,对于您提到的场景,它可能会很好地工作。但是,应将 VM 设置为整个视图的数据上下文,以便视图中的所有元素都可以绑定到 VM 中的属性以呈现其状态。
在场景中,如果除了内容演示器之外,还必须在视图中再添加一个UI元素,则必须再次访问资源VM。
因此,如果您将虚拟机实例设置为数据上下文(像这样。DataContext = new ViewModel()) 并将您的内容演示者内容绑定到视图的 DataContext,例如 Content={Binding},这将更正确,并且如果您想扩展视图,这将对您有所帮助。这是一篇关于 mvvm 实现的很好的 msdn 文章 http://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx
谢谢
就ViewModel
嵌套而言,这段代码一目了然。在 XAML 中设置的绑定也是正确的。
关于缺点,我将避免在窗口资源中创建wpfApplication1:SomeVm
。通常Window
的DataContext
被设置为WindowViewModel
的实例,而实例又会保留对SomeVm
的引用。想象一下这样的班级:
public class WindowViewModel
{
public SomeVM SomeVM{get; set;}
public string Title {get; set;} //other data to bind by window
//...
}
然后,在初始化窗口时,必须将DataContext
设置为 ViewModel 实例,例如:
MainWindow.DataContext = new WindowViewModel();
在 XAML 中,您将再次使用绑定:
<Grid>
<ContentPresenter Content="{Binding SomeVm}" />
</Grid>
我还建议将隐式DataTemplates
放在字典generic.xaml
而不是窗口中。这样,您就可以在整个应用程序中重复使用这些模板。
此外,最好使用实现常见事件处理的 ViewModelBase 类,这样您就不需要重新实现INotifyPropertyChanged
。还要尽量避免在属性更改通知中使用"魔术字符串"。最好使用基于 lambda 的方法或新的调用方信息属性。我知道您的示例代码可能已简化,但我正在按原样对其进行评论。