有種想寫一個MVVM框架的衝動!!! 1、Model中的屬性應不應該支持OnPropertyChanged事件? 不應該。應該有ViewModel對該屬性進行封裝,由ViewModel提供OnPropertyChanged事件。 WPF之MVVM(1)中有實例 2、如何將控制項事件轉換為命令? 在“擴 ...
有種想寫一個MVVM框架的衝動!!!
1、Model中的屬性應不應該支持OnPropertyChanged事件?
不應該。應該有ViewModel對該屬性進行封裝,由ViewModel提供OnPropertyChanged事件。 WPF之MVVM(1)中有實例
2、如何將控制項事件轉換為命令?
- 在“擴展”中添加“System.Windows.Interractivity”引用
- xaml中添加
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity
命名空間 -
使用
<ListBox Name="LbBox" ItemsSource="{Binding Path=SourceCount}"> <i:Interaction.Triggers> <i:EventTrigger EventName="SelectionChanged"> <common:ExInvokeCommandAction Command="{Binding Path=SelectionChangedCmd}" CommandParameter="{Binding ElementName=LbBox, Path=SelectedItem}"/> </i:EventTrigger> </i:Interaction.Triggers> </ListBox>
3、View中如何訪問ViewModel
4、ViewModel中如何訪問View
5、ViewModel之間通信
-
聚合關係
public class VM01 { public string Name{get;set;} } public class VM02 { public list<VM01> Property { get; set; } }
-
組合關係
public class VM01 { public string Name{get;set;} } public class VM02 { public string Name{get;set;} } public class VM03 { private VM01 _vm01; private VM02 _vm02; ... public VM03(VM01 vm01, VM02 vm02){} }
-
依賴關係
這裡主要介紹下依賴關係的ViewModel如何通信
通過一個非常簡單的程式來演示這種實現:點擊左邊的數字,右邊的數字加1。
左邊為LeftViewModel
右邊為RightViewModel
,兩個VM是相互獨立的,通過事件進行通信。
1、定義類型來容納所有需要發送給事件通知接收者的附件信息
public class NumberChangedEventArgs : EventArgs
{
public int Number { get; set; }
public NumberChangedEventArgs(int num)
{
Number = num;
}
}
2、在LeftViewModel
中定義事件成員
public event EventHandler<NumberChangedEventArgs> NumberChanged;
protected virtual void OnNumberChanged(NumberChangedEventArgs e)
{
var handler = NumberChanged;
if (handler != null) handler(this, e);
}
3、定義負責引發事件的方法來通知事件的登記對象
/// <summary>
/// 選擇命令
/// </summary>
private DelegateCommand<ExCommandParameter> _selectionChangedCmd;
public DelegateCommand<ExCommandParameter> SelectionChangedCmd
{
get
{
if (_selectionChangedCmd == null)
{
_selectionChangedCmd = new DelegateCommand<ExCommandParameter>(InvokeMouseDown);
}
return _selectionChangedCmd;
}
}
private void InvokeMouseDown(ExCommandParameter param)
{
var number = param.Parameter is int ? (int) param.Parameter : 0;
//觸發事件
OnNumberChanged(new NumberChangedEventArgs(number));
}
4、定義方法將輸入轉化為期望事件
public class RightViewModel : ViewModelBase
{
public RightViewModel()
{
//訂閱事件
var vm = ViewModelManager.GetByKey("left") as LeftViewModel;
if (vm != null) vm.NumberChanged += VmOnNumberChanged;
}
private int _number;
public int Number
{
get { return _number; }
set
{
_number = value;
OnPropertyChanged("Number");
}
}
/// <summary>
/// 事件處理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void VmOnNumberChanged(object sender, NumberChangedEventArgs e)
{
Number = e.Number + 1;
}
}
問題:RightViewModel
中如何獲取LeftViewModel
呢?
定義一個容器
public static class ViewModelManager
{
private static readonly Dictionary<string, ViewModelBase> Dic = new Dictionary<string, ViewModelBase>();
public static void Add(string key, ViewModelBase value)
{
if (Dic.ContainsKey(key)) return;
Dic.Add(key, value);
}
public static ViewModelBase GetByKey(string key)
{
if (!Dic.ContainsKey(key)) return null;
ViewModelBase value;
Dic.TryGetValue(key, out value);
return value;
}
}
在設置View的DataContext
時將ViewModel添加到ViewModelManager
中
public LeftView()
{
InitializeComponent();
var vm = new LeftViewModel();
ViewModelManager.Add("left", vm);
this.DataContext = vm;
}
總結
回顧上面3篇博文中解決的問題,我們再來看下MvvmLight ToolKit是如何實現MVVM的,這裡引用下園友的總結MvvmLight ToolKit 教程。
我們可以猜測MvvmLight作者使用這些組件是為瞭解決什麼問題?
- ViewModelBase && ObservableObject(INotifyPropertyChanged介面的實現,解決屬性改變通知的問題)
- ViewModelLocator && SimpleIoc(IOC容器,我們的
ViewModelManager
高級版) - RelayCommand(ICommand介面的實現,解決View和ViewModel通信問題)
- EventToCommand && IEventArgsConverter(Interaction的封裝,解決將事件轉換為命令的問題)
- Messenger(解決View和ViewModel以及ViewModel和ViewModel之間通信的問題)
- DispatcherHelper(博客中未提到)
這樣分析後,我們就知道MvvmLight是如何產生的,以及它能為我們做什麼。
吹牛吹到現在,我都有種自己想寫一個MVVM框架的衝動了。你們有沒有?