Edw*_*uay 8 c# architecture wpf mvvm
下面的代码是我以前的MVVM方法的重构(Fat Models,瘦的ViewModels和dumb Views,最好的MVVM方法?),我将逻辑和INotifyPropertyChanged实现从模型中移回ViewModel.这更有意义,因为正如所指出的,您经常必须使用您无法更改或不想更改的模型,因此您的MVVM方法应该能够使用任何模型类,因为它碰巧存在.
此示例仍允许您在Visual Studio和Expression Blend中以设计模式查看模型中的实时数据,我认为这很重要,因为您可以拥有设计器连接的模拟数据存储,例如最小和最大的字符串. UI可能会遇到,以便他可以根据这些极端情况调整设计.
问题:
如果您只是将XAML和代码复制到新的WPF项目中,则以下代码将起作用.
XAML:
<Window x:Class="TestMvvm73892.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestMvvm73892"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:CustomerViewModel}"
MethodName="GetCustomerViewModel"/>
</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>
Run Code Online (Sandbox Code Playgroud)
代码背后:
using System;
using System.Windows;
using System.ComponentModel;
using System.Threading;
namespace TestMvvm73892
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
//view model
public class CustomerViewModel : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
private DateTime _timeOfMostRecentActivity;
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 CustomerViewModel()
{
_timer = new Timer(CheckForChangesInModel, null, 0, 1000);
}
private void CheckForChangesInModel(object state)
{
Customer currentCustomer = CustomerViewModel.GetCurrentCustomer();
MapFieldsFromModeltoViewModel(currentCustomer, this);
}
public static CustomerViewModel GetCustomerViewModel()
{
CustomerViewModel customerViewModel = new CustomerViewModel();
Customer currentCustomer = CustomerViewModel.GetCurrentCustomer();
MapFieldsFromModeltoViewModel(currentCustomer, customerViewModel);
return customerViewModel;
}
public static void MapFieldsFromModeltoViewModel
(Customer model, CustomerViewModel viewModel)
{
viewModel.FirstName = model.FirstName;
viewModel.LastName = model.LastName;
viewModel.TimeOfMostRecentActivity = model.TimeOfMostRecentActivity;
}
public static Customer GetCurrentCustomer()
{
return Customer.GetCurrentCustomer();
}
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
//model
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime TimeOfMostRecentActivity { get; set; }
public static Customer GetCurrentCustomer()
{
return new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now
};
}
}
}
Run Code Online (Sandbox Code Playgroud)
Joe*_*ran 13
我喜欢上面的示例,我认为它实现了MVVM的精神.但是,为了澄清,ViewModel代码和Model代码不应与实际Code Behind位于同一源文件中.事实上,我认为他们不应该在同一个项目中.
根据我的理解,这是MVVM:
M - 模型是从业务层(BL)返回的数据.这应该是轻量级的,包含只读数据.Model类是哑的并且不包含Update,Write或Delete逻辑,并且由BL作为请求,命令,操作等的结果生成.Model类不知道消费应用程序的表示需求,因此可以通过任何方式使用它们.为了真正利用这种可重用性,我们希望Model类独立于UI项目.
VM - ViewModel包含通信层:它向BL发出请求并以适合呈现的方式处理结果.与上面的示例一样,它也接收模型并根据特定的表示需求重新格式化.把它想象成一个"绑定类".在上面的示例中,数据只是从一个对象移动到下一个对象,但ViewModel将负责诸如公开"FullName"类型属性或将前导零添加到ZipCode之类的事情.绑定类是实现INotifyPropertyChanged的绑定类是正确的.而且,为了可重用性,我可能也会将此层提取到自己的项目中.这将允许您尝试各种UI选项而不进行管道更改.
V - View绑定到VM中创建的Binding类对象.View非常愚蠢:它对BL或VM一无所知.数据可以在两个方向上绑定,但VM处理错误,验证等.任何数据同步操作都是通过将请求传回BL,并再次处理结果来处理的.
这取决于应用程序的类型,但是不断检查模型以确定它是否已经改变似乎很重要.假装您正在连接到从DAL构建业务对象(BO)的BL,该DAL连接到DB.在这种情况下,你会不断重新创建BO,我肯定会成为性能杀手.您可以在BL上实现一个侦听通知的结帐系统,或者有一个方法可以将上次已知的更改时间与实际进行比较,或者您可以将BL缓存在BL上.只是一些想法.
另外,我在上面说过,模型应该是轻量级的.有很多重量级的选择,比如CSLA,但我不确定它们是否适合MVVM的想法.
我不是故意让自己成为一名专家,到目前为止,我在设计新软件架构时只研究过这些想法.我想读一些关于这个主题的讨论.