MVVM——Model-View-ViewModel的缩写形式。
Model——可以理解为带有字段、属性的类。 View——可以理解为我们看到的UI。 View Model——在View
和Model
之间,起到连接作用,并且使得View
和Model
层分离。View Model
不仅仅是Model
的包装,它还包含了程序逻辑,以及
Model
扩展。例如,如果Model
中有一个公开属性不需要在UI上显示,此时我们不需要在View Model
中去定义它。
在MVVM中,VM的地位举足轻重。使用MVVM模式具有以下几个特点:
①视图的cs文件包含极少数的代码,其核心逻辑都被放在<font style="color:#E8323C;">View Model</font>
类中,从而使得程序逻辑与视图耦合度降低。
②<font style="color:#E8323C;">View Model</font>
类作为<font style="color:#E8323C;">View</font>
的<font style="color:#E8323C;">DataContext</font>
。
③在MVVM下,所有的事件和动作都被当成命令,如按钮的点击操作,此时不是触发点击事件,而是绑定到一个点击命令,再由命令去执行对应的逻辑。
第三点很关键,因为在MVVM中,事件都被当成命令来进行处理,其中命令只能与具有Command属性的控件进行绑定。
namespace WpfApplication1
{
//第一步:自然是数据部分了,即Model层的实现。在这里定义了一个Person类,其中包含了2个基本的属性。
public class PersonModel
{
public string Name { get; set; }
public int Age { get; set; }
}
}
namespace WpfApplication1
{
//为了进行测试,下面创建一个静态方法来获得测试数据。
public class PersonDataHelper
{
public static ObservableCollection<PersonModel> GetPersons()
{
ObservableCollection<PersonModel> samplePersons = new ObservableCollection<PersonModel>();
samplePersons.Add(new PersonModel() { Name = "张三", Age = 33 });
samplePersons.Add(new PersonModel() { Name = "王五", Age = 22 });
samplePersons.Add(new PersonModel() { Name = "李四", Age = 35 });
samplePersons.Add(new PersonModel() { Name = "LearningHard", Age = 27 });
return samplePersons;
}
}
}
namespace WpfApplication1
{
//第二步:实现ViewModel层,实现数据和界面之间的逻辑。在视图模型类中,包含了属性和命令,
//因为在MVVM中,事件都当成命令来进行处理,其中命令只能与具有Command属性的控件进行绑定。
//既然要包含命令,首先就需要实现一个命令,这里自定义的命令需要实现ICommand接口。
//这里我们定义了一个QueryCommand。具体的实现代码如下所示:
public class QueryCommand : ICommand
{
#region Fields
private Action _execute;
private Func<bool> _canExecute;
#endregion
public QueryCommand(Action execute) : this(execute, null)
{
}
public QueryCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#region ICommand Member
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public void Execute(object parameter)
{
_execute();
}
#endregion
}
}
namespace WpfApplication1
{
public class PersonListViewModel : INotifyPropertyChanged
{
#region Fields
private string _searchText;
private ObservableCollection<PersonModel> _resultList;
#endregion
#region Properties
public ObservableCollection<PersonModel> PersonList { get; private set; }
// 查询关键字
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
RaisePropertyChanged("SearchText");
}
}
// 查询结果
public ObservableCollection<PersonModel> ResultList
{
get { return _resultList; }
set
{
_resultList = value;
RaisePropertyChanged("ResultList");
}
}
public ICommand QueryCommand
{
get { return new QueryCommand(Searching, CanSearching); }
}
#endregion
#region Construction
public PersonListViewModel()
{
PersonList = PersonDataHelper.GetPersons();
_resultList = PersonList;
}
#endregion
#region Command Handler
public void Searching()
{
ObservableCollection<PersonModel> personList = null;
if (string.IsNullOrWhiteSpace(SearchText))
{
ResultList = PersonList;
}
else
{
personList = new ObservableCollection<PersonModel>();
foreach (PersonModel p in PersonList)
{
if (p.Name.Contains(SearchText))
{
personList.Add(p);
}
}
if (personList != null)
{
ResultList = personList;
}
}
}
public bool CanSearching()
{
return true;
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Methods
private void RaisePropertyChanged(string propertyName)
{
// take a copy to prevent thread issues
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
<Window x:Class="WpfApplication1.PersonsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="PersonsView" Height="300" Width="300">
<Window.DataContext>
<local:PersonListViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Name="searchtxt" Text="{Binding Path=SearchText, Mode=TwoWay}"
HorizontalAlignment="Left" Height="30" Width="280" Margin="10,0,0,0">
</TextBox>
<Button Grid.Row="0" Name="searchBtn" Content="Search" Command="{Binding Path=QueryCommand}"
Width="80" Height="30" HorizontalAlignment="Right" Margin="0,0,10,0">
</Button>
<DataGrid Grid.Row="1" Name="datGrid"
HorizontalAlignment="Center"
VerticalAlignment="Top" ItemsSource="{Binding Path=ResultList}" Width="300">
</DataGrid>
</Grid>
</Window>