学习MVVM设计模式后第一次用于生产
WPF的MVVM設計模式
從winform轉變到WPF的過程,難點主要還是在MVVM的設計模式。當然,如果依然采用winform的涉及方式,在每個控件背后綁定事件的方式運用在wpf中,依然可行,但是假如GUI改版,其背后綁定的特別為此界面設計的事件不得不多數棄用。而MVVM最大的好處是將一切業務邏輯放在ViewModel中 ,將GUI的操作放在view中,將數據結構放在Model中,如圖摘自MSDN
實際使用
使用了Prism框架,省去了去構造實現INotifyPropertyChanged的基類,直接繼承BindableBase
namespace Prism.Mvvm{ // // 摘要: // Implementation of System.ComponentModel.INotifyPropertyChanged to simplify models. public abstract class BindableBase : INotifyPropertyChanged { protected BindableBase(); // // 摘要: // Occurs when a property value changes. public event PropertyChangedEventHandler PropertyChanged; // // 摘要: // Notifies listeners that a property value has changed. // // 參數: // propertyName: // Name of the property used to notify listeners. This value is optional and can // be provided automatically when invoked from compilers that support System.Runtime.CompilerServices.CallerMemberNameAttribute. protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null); // // 摘要: // Raises this object's PropertyChanged event. // // 參數: // propertyExpression: // A Lambda expression representing the property that has a new value. // // 類型參數: // T: // The type of the property that has a new value protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression); // // 摘要: // Checks if a property already matches a desired value. Sets the property and notifies // listeners only when necessary. // // 參數: // storage: // Reference to a property with both getter and setter. // // value: // Desired value for the property. // // propertyName: // Name of the property used to notify listeners. This value is optional and can // be provided automatically when invoked from compilers that support CallerMemberName. // // 類型參數: // T: // Type of the property. // // 返回結果: // True if the value was changed, false if the existing value matched the desired // value. protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null); }以及用來構造Command的基類DelegateCommand
namespace Prism.Commands{ // // 摘要: // An System.Windows.Input.ICommand whose delegates do not take any parameters for // Prism.Commands.DelegateCommand.Execute and Prism.Commands.DelegateCommand.CanExecute. public class DelegateCommand : DelegateCommandBase { // // 摘要: // Creates a new instance of Prism.Commands.DelegateCommand with the System.Action // to invoke on execution. // // 參數: // executeMethod: // The System.Action to invoke when System.Windows.Input.ICommand.Execute(System.Object) // is called. public DelegateCommand(Action executeMethod); // // 摘要: // Creates a new instance of Prism.Commands.DelegateCommand with the System.Action // to invoke on execution and a Func to query for determining if the command can // execute. // // 參數: // executeMethod: // The System.Action to invoke when System.Windows.Input.ICommand.Execute(System.Object) // is called. // // canExecuteMethod: // The System.Func`1 to invoke when System.Windows.Input.ICommand.CanExecute(System.Object) // is called public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod); protected DelegateCommand(Func<Task> executeMethod); protected DelegateCommand(Func<Task> executeMethod, Func<bool> canExecuteMethod); // // 摘要: // Factory method to create a new instance of Prism.Commands.DelegateCommand from // an awaitable handler method. // // 參數: // executeMethod: // Delegate to execute when Execute is called on the command. // // 返回結果: // Constructed instance of Prism.Commands.DelegateCommand public static DelegateCommand FromAsyncHandler(Func<Task> executeMethod); // // 摘要: // Factory method to create a new instance of Prism.Commands.DelegateCommand from // an awaitable handler method. // // 參數: // executeMethod: // Delegate to execute when Execute is called on the command. This can be null to // just hook up a CanExecute delegate. // // canExecuteMethod: // Delegate to execute when CanExecute is called on the command. This can be null. // // 返回結果: // Constructed instance of Prism.Commands.DelegateCommand public static DelegateCommand FromAsyncHandler(Func<Task> executeMethod, Func<bool> canExecuteMethod); // // 摘要: // Determines if the command can be executed. // // 返回結果: // Returns true if the command can execute, otherwise returns false. public virtual bool CanExecute(); // // 摘要: // Executes the command. public virtual Task Execute(); // // 摘要: // Observes a property that is used to determine if this command can execute, and // if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged // on property changed notifications. // // 參數: // canExecuteExpression: // The property expression. Example: ObservesCanExecute((o) => PropertyName). // // 返回結果: // The current instance of DelegateCommand public DelegateCommand ObservesCanExecute(Expression<Func<object, bool>> canExecuteExpression); // // 摘要: // Observes a property that implements INotifyPropertyChanged, and automatically // calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications. // // 參數: // propertyExpression: // The property expression. Example: ObservesProperty(() => PropertyName). // // 類型參數: // T: // The object type containing the property specified in the expression. // // 返回結果: // The current instance of DelegateCommand public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression); }}第一次使用MVVM設計模式,沒有理解在多個ViewModel之間通信,所以不得不采用單一ViewModel和多個view,這樣導致了一個ViewModel的臃腫和復雜,看似結構簡單,但是實際的邏輯越來越混亂。在沒有理解Event Aggregator如何使用的情況下,這是可行方案。
MVVM使用感受
最主要的感受是MVVM將UI和業務邏輯分離,UI就只寫UI,不用像WinForm一樣在每個事件背后,如果要獲得UI某個TextBox的數據,得通過如下獲取
public void SomeButton_Clicked(object sender, EventArgs e){ string text = textBox1.Text; DoSomeThings(text); ...}同樣,后臺事件要更新前臺UI數據時
pubic void SomeButton_Clicked(object sender, EvnetArgs e){ DoOtherThings(); textBox1.Text = "Some Text";}這種硬編碼的形式,遇到UI的重大變化,必須就將背后事件對應UI的控件名稱全部更改才能繼續運行。當軟件達到一定復雜度,這樣做就是災難性的。
而MVVM,使用了數據綁定,雖然增加了一點代碼,但是帶來的好處巨大。在ViewModel中先定義要綁定的數據
private string name;public string Name{ get{return name;} set{ if (name != value) { name = value; OnPropertyChanged("Name"); // 實現INotifyPropertyChanged接口 }}}然后在view中將其和TextBox數據綁定
<TextBox Text="{Binding Name, Mode=TwoWay}">這里的數據綁定方式是雙向綁定,后臺數據變化會自動通知前臺UI線程更新數據,相反,前臺UI線程更改了數據,后臺的數據也會相應變化。這樣,在實際數據更新時,不用去查看綁定的UI控件名稱,也不用擔心在其他線程更新控件數據時要用oneControl.Invoke(Action action)。
總結
第一次使用MVVM感受到的優點:
數據綁定,不用考慮具體UI控件的名稱,不用手動更新UI數據。
UI可操作性更大,支持template
業務邏輯和UI分離,界面改版方便
但同樣帶來了缺點:
代碼量明顯增加
對于小軟件來說,開發沒有WinFrom來的敏捷
總結
以上是生活随笔為你收集整理的学习MVVM设计模式后第一次用于生产的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从严治码-别人在项目中下毒,我该怎么治?
- 下一篇: asp.net core 系列之Star