MVVM是Model-View-ViewModel的縮寫形式,它通常被用於WPF或Silverlight開發。
Model——可以理解為帶有字段,屬性的類。
View——可以理解為我們所看到的UI。
View Model在View和Model之間,起到連接的作用,並且使得View和Model層分離。View Model不僅僅是Model的包裝,它還包含了程序邏輯,以及Model擴展,例如,如果Model中有一個公開屬性不需要在UI上顯示,此時我們可以不再View Model中去定義它。
在MVVM中,VM的地位可以說是舉足輕重。使用MVVM模式具有以下幾個特點:
視圖的cs文件包括極少的代碼,其核心邏輯都被放在View Model類中,從而使得程序邏輯與視圖耦合度降低。
ViewModel類作為View的DataContext。
在MVVM下,所有的事件和動作都被當成命令,如按鈕的點擊操作,此時不是觸發點擊事件,而是綁定到一個點擊命令,再由命令去執行對應的邏輯。
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 } }
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>
