通过对this question的慷慨帮助,我整理了以下MVVM结构,该结构在XAML(当前日期/时间)中实时显示模型的变化,非常好。
这种设置的一个很好的优势是 当你看到你的视图时 Visual Studio或。的设计模式 混合,你看到时间滴答, 这意味着在设计时你 可以访问您的实时数据 模型。
在实现此功能的过程中,我很惊讶地看到大部分批量从我的ViewModel迁移到我的模型,包括实现INotifyPropertyChange。另一个变化是我不再绑定到ViewModel上的属性,而是绑定到方法 。
所以目前这是我最喜欢的MVVM风格:
视野愚蠢:
ViewModel是瘦的:
模特很胖:
问题:
如果您只是将XAML和代码复制到新的WPF项目中,以下代码将起作用。
XAML:
<Window x:Class="TestBinding99382.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestBinding99382"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:ShowCustomerViewModel}"
MethodName="GetCurrentCustomer"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource DataSourceCustomer}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Path=LastName}"/>
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/>
</StackPanel>
</DockPanel>
</Window>
代码背后:
using System.Windows;
using System.ComponentModel;
using System;
using System.Threading;
namespace TestBinding99382
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
//view model
public class ShowCustomerViewModel
{
public Customer GetCurrentCustomer() {
return Customer.GetCurrentCustomer();
}
}
//model
public class Customer : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
private DateTime _timeOfMostRecentActivity;
private static Customer _currentCustomer;
private Timer _timer;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
this.RaisePropertyChanged("FirstName");
}
}
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
this.RaisePropertyChanged("LastName");
}
}
public DateTime TimeOfMostRecentActivity
{
get
{
return _timeOfMostRecentActivity;
}
set
{
_timeOfMostRecentActivity = value;
this.RaisePropertyChanged("TimeOfMostRecentActivity");
}
}
public Customer()
{
_timer = new Timer(UpdateDateTime, null, 0, 1000);
}
private void UpdateDateTime(object state)
{
TimeOfMostRecentActivity = DateTime.Now;
}
public static Customer GetCurrentCustomer()
{
if (_currentCustomer == null)
{
_currentCustomer = new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now
};
}
return _currentCustomer;
}
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}
答案 0 :(得分:28)
这是我的观点,因为它值得:
我真的不同意你建议的方法(除了愚蠢的观点)。在现实生活中,您通常必须使用现有模型:它可能是您没有时间(或将要)更改的遗留代码,甚至是您没有代码的库。在我看来,模型应该完全不知道它的显示方式,并且应该可以在非WPF应用程序中轻松使用。因此,它不必实现INotifyPropertyChanged
INotifyCollectionChanged
之类的任何特定接口,以使其在MVVM中可用。我认为与UI相关的所有逻辑都应该存在于ViewModel中。
关于RoutedEvents
和RoutedCommands
,它们并不适合与MVVM模式一起使用。我通常尝试使用尽可能少的RoutedEvents
,而根本不使用RoutedCommands
。相反,我的ViewModel公开了我绑定到XAML中的UI的RelayCommand
属性(有关RelayCommand
的详细信息,请参阅Josh Smith的this article)。当我真的需要为某些控件处理事件时,我使用附加行为将事件映射到ViewModel命令(看看Marlon Grech's implementation)
所以,总结一下:
当然这只是我的方法,它可能不是最好的,但我觉得很舒服;)
答案 1 :(得分:2)
我同意托马斯的观点。 我对WPF架构的任何人的建议是: