MVVM+;ViewModel调用的视图特定功能的实现
以下是我想解决的“问题”: 我有许多“仅查看”特定功能,例如:MVVM+;ViewModel调用的视图特定功能的实现,mvvm,separation-of-concerns,Mvvm,Separation Of Concerns,以下是我想解决的“问题”: 我有许多“仅查看”特定功能,例如: 在运行时更改视图的ResourcesDictionary(用于将外观从黑色更改为蓝色或其他颜色) 保存和恢复特定于视图的设置,如视图大小或用户设置的栅格属性 所有这些功能都与ViewModel无关,因为它们实际上是特定于视图的,可能只适用于ViewModel的一个客户端(视图)(如果ViewModel有多个客户端)。上面的例子只是我想要实现的大量功能中的两个,所以我需要一个更通用的解决方案,而不是只适合这两个例子的解决方案 在
- 在运行时更改视图的ResourcesDictionary(用于将外观从黑色更改为蓝色或其他颜色)
- 保存和恢复特定于视图的设置,如视图大小或用户设置的栅格属性
- 创建从DependencyObject继承的ViewBase。我不喜欢这个解决方案,因为它在某种程度上打破了MVVM模式的想法,即视图没有代码落后。为了调用这个方法,我需要引用ViewModel中的视图,这也否定了分离关注点的思想
- 创建IView接口。就像第一次接近一样肮脏。每个视图都需要实现IView,therfor有代码隐藏。此外,ViewModel需要“以某种方式”了解IView实现以调用其方法
- 将ViewModel的属性绑定到视图的触发器、行为和命令。这种方法似乎是最好的,但我认为我会很快在使用限制下运行,因为有些功能可能无法与这种方法配合使用。例如,仅仅将resourceDictionary绑定到视图可能不起作用,因为正确显示新资源需要合并。再说一遍……我只能在ViewModel中查看特定的功能/信息(如resourcesdictionary),但只有ViewModel的特定客户端使用此属性
- 更改应用程序的肤色
- 保存和还原
- 大小
- 网格属性
public class SettingsViewModel
{
public Color Skin { get;set;}
public Size ViewSize {get;set;}
public GridProperties GridProperties {get;set;}
public void Save() {//TODO:Add code}
public void Restore() {//TODO:Add code}
}
您的视图将绑定到该视图模型并实现“如何”
如果您正在创建一个web应用程序,那么how将采用ViewModel并创建html。如果您使用的是WPF,那么您将绑定到XAML中的那些属性并创建UI(这可能会导致您切换出ResourceDictionary等)
另一件帮助我的事情是认识到视图和ViewModel之间的不对称关系。在它最纯粹的形式中,ViewModel应该对视图一无所知,但是视图应该知道它需要知道的关于ViewModel的一切
这就是分离关注点背后的全部要点
对您的“解决方案”的回应:
- 您的第一个选项违反了MVVM原则,您阅读了吗
- 我相信这将帮助您根据ViewModel进行视图选择
- 我不知道您会遇到什么“限制”,但WPF非常强大,并且会有可用的解决方案
如果您对IView接口方法的引入进行了更改,那么您可能会发现很有趣。它通过这个接口解决了我们的问题。您将在示例应用程序中看到这一点。在不引入视图和视图模型之间耦合的情况下,最简单的方法是使用Messenger(在某些框架中也称为中介)。ViewModel只是广播一条“更改主题”消息,视图订阅该消息。使用MVVM Light中的
Messenger
类,您可以执行以下操作:
消息定义
public class ThemeChangeMessage
{
private readonly string _themeName;
public ThemeChangeMessage(string themeName)
{
_themeName = themeName;
}
public string ThemeName { get { return _themeName; } }
}
视图模型
Messenger.Default.Send(new ThemeChangeMessage("TheNewTheme");
查看隐藏代码
public MyView()
{
InitializeComponent();
Messenger.Defaut.Register<ThemeChangeMessage>(ChangeTheme);
}
private void ChangeTheme(ThemeChangeMessage msg)
{
ApplyNewTheme(msg.ThemeName);
}
publicmyview()
{
初始化组件();
Messenger.Defaut.Register(变更主题);
}
私有void ChangeTheme(ThemeChangeMessage消息)
{
ApplyNewTheme(msg.ThemeName);
}
我早就接受了这样一种思维方式,即模式是为人设计的,而不是为模式设计的。很多时候,你会看到MVVM不适合的情况,为了解决这个问题,非常聪明的人想出了一些方法来绕过它,同时保持纯MVVM的外观
但是,如果你同意我的观点,或者你只是想保持简单,另一种方法是允许ViewModel引用视图;当然是通过接口,否则这将是一种糟糕的编程实践。现在的问题是,如何将视图放入viewmodel
最简单的方法是在视图的dataContextChanged事件中执行此操作。但是,如果您想尝试不同的方法,那么使用附加属性或依赖属性将视图注入viewmodel如何
我已经在许多WPF上成功地使用了这种技术
public IMyView InjectedView { set { _injectedView = value; } }
public MyUserControl : IMyView
{
public static readonly DependencyProperty ThisProperty =
DependencyProperty.Register("This", typeof(IMyView), typeof(MyUserControl));
public MyUserControl()
{
SetValue(ThisProperty, this);
}
public IMyView This { get { return GetValue(ThisProperty); } set { /* do nothing */ } }
}
<MyUserControl This="{Binding InjectedView, Mode=OneWayToSource}"/>