作過WPF開發的人,都知道作MVVM架構,最麻煩的是Event的綁定,由於Event是不能被綁定的,同時現有的條件下,命令是沒法替代Event。而在開發過程當中沒法避免Event事件,這樣MVVM的架構就不能徹底實現了。web
因此後來微軟提供了一個折中的方案,使用Trigger觸發器和System.Windows.Interactivity結合經過事件綁定事件,我的以爲這個方法也挺能夠的。編程
還有Prism框架方法,我看過可是這個方法比較繁瑣可用性不高。數組
後來經過搜索和本身研究知道了一個解決方案,能夠綁定全部事件,這個是原始版本,我我的正在研究一個徹底的版本,但願能徹底支持Event屬性。架構
對於編程學習喜歡的方式,我我的是這個見解,我作開發也有一年多了,WPF開發也有九個月了。從小白到如今入門略有深刻。再也不侷限於實現效果,而是更喜歡實現功能的原汁原味的代碼。不少效果也許我不能寫出完整的代碼,也沒有那麼多的時間,可是深刻看了別人的設計代碼,老是受益良多。框架
工做這麼長時間,總算明白爲何Java那麼受歡迎了。由於做爲技術人員到了必定境界,更喜歡瞭解具體的實現過程,而對於直接使用SDK的興趣淡了很多。打個比方微軟提供了不少優秀的SDK,可是就像家庭同樣,越是包辦一切的好父母,每每不太招孩子們的喜歡,不是孩子們不懂得感恩,而是社會天然規律,你沒法成長,你便很容易感受到本身無能,無能的人哪有快樂而言。less
正文:具體的類圖 經過類圖能夠看到結構至關清晰,它們的依賴關係是單向的。是屬於低耦合的關係ide
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Data; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { /// <summary> /// 這個類的做用是真正的綁定命令 /// 將命令綁定到對應的控件上 /// </summary> public class Events { /// <summary> /// 事件行爲屬性 /// 註冊屬性名 /// </summary> private static readonly DependencyProperty EventBehaviorsProperty = DependencyProperty.RegisterAttached("EventBehaviors",typeof(EventBehaviorCollection),typeof(Control),null); private static readonly DependencyProperty InternalDataContextProperty = DependencyProperty.RegisterAttached("InternalDataContext", typeof(Object), typeof(Control), new PropertyMetadata(null, DataContextChanged)); public static readonly DependencyProperty CommandsProperty = DependencyProperty.RegisterAttached("Commands", typeof(EventCommandCollection), typeof(Events), new PropertyMetadata(null, CommandsChanged)); private static void DataContextChanged(DependencyObject dependencyObject,DependencyPropertyChangedEventArgs e) { var target = dependencyObject as Control; if (target == null) return; foreach (var behavior in GetOrCreateBehavior(target)) { behavior.Bind(); } } public static EventCommandCollection GetCommands(DependencyObject dependencyObject) { return dependencyObject.GetValue(CommandsProperty) as EventCommandCollection; } public static void SetCommands(DependencyObject dependencyObject,EventCommandCollection eventCommands) { dependencyObject.SetValue(CommandsProperty,eventCommands); } private static void CommandsChanged(DependencyObject dependencyObject,DependencyPropertyChangedEventArgs e) { var target = dependencyObject as Control; if (target == null) return; var behaviors = GetOrCreateBehavior(target); foreach (var eventCommand in e.NewValue as EventCommandCollection) { var behavior = new EventBehavior(target); behavior.Bind(eventCommand); behaviors.Add(behavior); } } private static EventBehaviorCollection GetOrCreateBehavior(FrameworkElement target) { var behavior = target.GetValue(EventBehaviorsProperty) as EventBehaviorCollection; if (behavior == null) { behavior = new EventBehaviorCollection(); target.SetValue(EventBehaviorsProperty,behavior); target.SetBinding(InternalDataContextProperty,new Binding()); } return behavior; } } }
EventBehaviorCollection 函數
using System; using System.Collections.Generic; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { /// <summary> /// 事件名稱集合 /// </summary> public class EventCommandCollection : List<EventCommand> { } }
EventBehavior 學習
using System; using System.ComponentModel; using System.Reflection; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { /// <summary> /// 事件行爲 /// 這個類的做用是將,經過反射將事件名,實例化一個真正的事件對象 /// </summary> public class EventBehavior : CommandBehaviorBase<Control> { private EventCommand _bindingInfo; public EventBehavior(Control control) : base(control) { } public void Bind(EventCommand bindingInfo) { ValidateBindingInfo(bindingInfo); _bindingInfo = bindingInfo; Bind(); } private void ValidateBindingInfo(EventCommand bindingInfo) { if (bindingInfo == null) throw new ArgumentException("bindingInfo is Null"); if (string.IsNullOrEmpty(bindingInfo.CommandName)) throw new ArgumentException("bindingInfo.CommandName is Null"); if (string.IsNullOrEmpty(bindingInfo.EventName)) throw new ArgumentException("bindingInfo.EventName is Null"); } public void Bind() { ValidateBindingInfo(_bindingInfo); HookPropertyChanged(); HookEvent(); SetCommand(); } public void HookPropertyChanged() { var dataContext = this.TargetObject.DataContext as INotifyPropertyChanged; if (dataContext == null) return; dataContext.PropertyChanged -= this.DataContextPropertyChanged; dataContext.PropertyChanged += this.DataContextPropertyChanged; } private void DataContextPropertyChanged(object sender,PropertyChangedEventArgs e) { if (e.PropertyName == _bindingInfo.CommandName) this.SetCommand(); } private void SetCommand() { var dataContext = this.TargetObject.DataContext; if (dataContext == null) return; var propertyInfo = dataContext.GetType().GetProperty(_bindingInfo.CommandName); if (propertyInfo == null) throw new ArgumentException("propertyInfo is null,commandName is error"); this.Command = propertyInfo.GetValue(dataContext,null) as ICommand; } /// <summary> /// 鉤事件 /// 有助於綁定AttachedProperty屬性 /// </summary> private void HookEvent() { var eventNames = _bindingInfo.EventName.Split('.'); int length = eventNames.Length; //分開來,目的是爲了提升效率 if (length == 1) { var eventInfo = this.TargetObject.GetType().GetEvent(_bindingInfo.EventName, BindingFlags.Public | BindingFlags.Instance); if (eventInfo == null) throw new ArgumentException("eventInfo is Null,eventName is error"); eventInfo.RemoveEventHandler(this.TargetObject, this.GetEventMethod(eventInfo)); eventInfo.AddEventHandler(this.TargetObject, GetEventMethod(eventInfo)); } else { //TargetObject控件加載完成後觸發執行 this.TargetObject.Initialized += (sender, e) => { var tempObject = SelectVisual(eventNames, this.TargetObject); var tempEventInfo = tempObject.GetType().GetEvent(eventNames[length-1], BindingFlags.Public | BindingFlags.Instance); if (tempEventInfo == null) throw new ArgumentException("eventInfo is Null,eventName is error"); tempEventInfo.RemoveEventHandler(tempObject, this.GetEventMethod(tempEventInfo)); tempEventInfo.AddEventHandler(tempObject, GetEventMethod(tempEventInfo)); }; } } #region 篩選內部控件 /// <summary> /// 篩選Visual /// </summary> /// <param name="names"></param> /// <param name="obj"></param> /// <returns></returns> private static Visual SelectVisual(string[] names, Control obj) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); int act = assemblies.Length; for (int i = 0; i < act; i++) { if (assemblies[i].FullName.Split(',')[0] == "PresentationFramework") { return SelectVisual(assemblies[i], names, 0, obj); } } return null; } /// <summary> /// 命名空間名稱集合 /// </summary> static string[] namespaceNames = {"System.Windows.Controls.Primitives","System.Windows.Controls" }; /// <summary> /// 篩選Visual /// </summary> /// <param name="assembly"></param> /// <param name="names"></param> /// <param name="i"></param> /// <param name="obj"></param> /// <returns></returns> private static Visual SelectVisual(Assembly assembly, string[] names,int i,Visual obj) { Type type=null; int tempLength=namespaceNames.Length; for (int j = 0; j < tempLength; j++) { type = assembly.GetType(string.Format("{0}.{1}",namespaceNames[j], names[i])); if(type!=null) { break; } } if (type == null) { return null; } obj = GetDescendantByType(obj, type); if (names.Length == (i+2))//判斷是否到了數組有效的位置,由於爲了偷懶沒有對string[]進行去尾操做,由於string[]最後一個數據是事件名稱,在這裏是 無效的 { return obj; } return SelectVisual(assembly, names, i+1, obj); } /// <summary> /// 經過Type獲取包含的控件 /// </summary> /// <param name="element"></param> /// <param name="type"></param> /// <returns></returns> private static Visual GetDescendantByType(Visual element, Type type) { if (element == null) return null; if (element.GetType() == type||element.GetType().BaseType==type) return element; Visual foundElement = null; if (element is FrameworkElement) (element as FrameworkElement).ApplyTemplate(); int cnt = VisualTreeHelper.GetChildrenCount(element); for (int i = 0; i < cnt; i++) { Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; foundElement = GetDescendantByType(visual, type); if (foundElement != null) break; } return foundElement; } #endregion private Delegate _method; private Delegate GetEventMethod(EventInfo eventInfo) { if (eventInfo == null) throw new ArgumentException("eventInfo is null"); if (eventInfo.EventHandlerType == null) throw new ArgumentException("EventHandlerType is null"); if (this._method == null) { this._method = Delegate.CreateDelegate( eventInfo.EventHandlerType,this,GetType().GetMethod("OnEventRaised",BindingFlags.NonPublic|BindingFlags.Instance)); } return _method; } private void OnEventRaised(object sender,EventArgs e) { this.ExecuteCommand(); } } }
EventCommandCollection this
using System; using System.Collections.Generic; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { /// <summary> /// 事件名稱集合 /// </summary> public class EventCommandCollection : List<EventCommand> { } }
CommandBehaviorBase
using System; using System.Windows.Controls; using System.Windows.Input; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { /// <summary> /// 基於行爲的處理鏈接的一個命令 /// 這個類能夠用來提供新的行爲,好比按鈕的Clik事件行爲 /// 鼠標進入控件的事件行爲 /// </summary> /// <typeparam name="T"></typeparam> public class CommandBehaviorBase<T> where T : Control { /// <summary> /// 定義的一個命令 /// </summary> private ICommand command; /// <summary> /// 命令傳值的內容 /// </summary> private object commandParameter; /// <summary> /// 弱引用對象 /// 即對象被引用的狀況下,容許垃圾回收來回收對象 /// </summary> private readonly WeakReference targetObject; /// <summary> /// 命令中容許事件發生的事件的方法, /// 即容許事件發生的條件 /// </summary> private readonly EventHandler commandCanExecuteChangedHandler; #region 屬性 /// <summary> /// 相應的命令被執行和監控 /// </summary> public ICommand Command { get { return this.command; } set { if (this.command != null) { this.command.CanExecuteChanged -= this.commandCanExecuteChangedHandler; } this.command = value; if (this.command != null) { this.command.CanExecuteChanged += this.commandCanExecuteChangedHandler; this.UpdateEnabledState(); } } } /// <summary> /// 命令中傳值的內容 /// </summary> public object CommandParameter { get { return this.commandParameter; } set { if (this.commandParameter != value) { this.commandParameter = value; this.UpdateEnabledState(); } } } /// <summary> /// 一個弱引用的對象 /// </summary> protected T TargetObject { get { return targetObject.Target as T; } } #endregion /// <summary> /// 構造函數 /// </summary> /// <param name="targetObject">行爲上的目標對象</param> public CommandBehaviorBase(T targetObject) { this.targetObject = new WeakReference(targetObject); this.commandCanExecuteChangedHandler = new EventHandler(this.CommandCanExecuteChanged); } /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void CommandCanExecuteChanged(object sender,EventArgs e) { this.UpdateEnabledState(); } /// <summary> /// 基於屬性的命令的執行,來更新的目標對象。 /// </summary> protected virtual void UpdateEnabledState() { if (this.TargetObject == null) { this.Command = null; this.CommandParameter = null; }else if(this.Command!=null) { this.TargetObject.IsEnabled = this.Command.CanExecute(this.CommandParameter); } } /// <summary> /// 執行命令 /// </summary> protected virtual void ExecuteCommand() { if (this.Command != null) { this.Command.Execute(this.CommandParameter); } } } }
EventCommand
using System; namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors { public class EventCommand { /// <summary> /// 命令名稱 /// 這個能夠自定義,好比myCommandClick等 /// </summary> public string CommandName { get; set; } /// <summary> /// 特定的事件名稱 /// 首先要確認綁定的控件支持這個事件 /// 好比Click MouseOver 等 /// </summary> public string EventName { get; set; } } }
如今完整的框架已經搭建好了,如今就是作一個Demo就能夠了。
用命令綁定事件,就要考慮到相似TextBoxBase.TextChanged命令的問題,理解這個的前提是瞭解Attached Property,Attached Property是DependencyObject的一種特殊形式,它利用DependencyProperty.RegisterAttached方法註冊的。能夠被有效的添加到任何繼承自DependencyObject的對象中。同時要明白綁定控件中包含有TextBox這個控件,找到TextBox控件而後綁定它的事件問題就解決了。
說完思路如今提供以上綁事件命令類庫如何使用:
<ComboBox x:Name="cboBox" Margin="115,0,10,0" IsEditable="True" ItemsSource="{Binding ListCollection}" Text="{Binding UserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="15" Height="25" HorizontalAlignment="Left" VerticalAlignment="Center" Width="179"> <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <!--<Behaviors:EventCommand CommandName="cboTextBoxChangedCommand" EventName="TextBox.TextChanged" />--> <Behaviors:EventCommand CommandName="cboTextBoxBaseChangedCommand" EventName="TextBoxBase.TextChanged" /> <Behaviors:EventCommand CommandName="cboSelectionChangedCommand" EventName="SelectionChanged" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </ComboBox>
運用示例代碼來自於這個xaml文件中
MainWindow.xaml
<Window x:Class="EventCommandDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:EventCommandDemo" xmlns:Behaviors="clr-namespace:ManMonthMyth.Practices.Composite.Presentation.Behaviors;assembly=ManMonthMyth.Practices.Composite.Presentation.Behaviors" Title="MainWindow" Width="400" Height="300" WindowStyle="None" ResizeMode="NoResize" Background="LightPink" WindowStartupLocation="CenterScreen"> <Window.Triggers> <EventTrigger SourceName="chkRememberPwd" RoutedEvent="CheckBox.Unchecked"> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="chkLanding" Storyboard.TargetProperty="IsChecked"> <DiscreteBooleanKeyFrame KeyTime="0:0:0.01" Value="False" /> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger SourceName="chkLanding" RoutedEvent="CheckBox.Checked"> <BeginStoryboard> <Storyboard> <BooleanAnimationUsingKeyFrames Storyboard.TargetName="chkRememberPwd" Storyboard.TargetProperty="IsChecked"> <DiscreteBooleanKeyFrame KeyTime="0:0:0.01" Value="True" /> </BooleanAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> <Viewbox> <Grid Width="400" Height="300"> <Grid.RowDefinitions> <RowDefinition Height="120" /> <RowDefinition Height="40" /> <RowDefinition Height="40" /> <RowDefinition Height="30" /> <RowDefinition /> </Grid.RowDefinitions> <StackPanel Grid.Row="1" Orientation="Horizontal"> <ComboBox x:Name="cboBox" Margin="115,0,10,0" IsEditable="True" ItemsSource="{Binding ListCollection}" Text="{Binding UserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="15" Height="25" HorizontalAlignment="Left" VerticalAlignment="Center" Width="179"> <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <!--<Behaviors:EventCommand CommandName="cboTextBoxChangedCommand" EventName="TextBox.TextChanged" />--> <Behaviors:EventCommand CommandName="cboTextBoxBaseChangedCommand" EventName="TextBoxBase.TextChanged" /> <Behaviors:EventCommand CommandName="cboSelectionChangedCommand" EventName="SelectionChanged" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </ComboBox> <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="註冊帳號" > <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <Behaviors:EventCommand CommandName="TxTMouseEnterCommand" EventName="MouseEnter" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </TextBlock> </StackPanel> <StackPanel Grid.Row="2" Orientation="Horizontal"> <PasswordBox Margin="115,0,10,0" local:PasswordBoxBindingHelper.IsPasswordBindingEnabled="True" local:PasswordBoxBindingHelper.BindedPassword="{Binding Path=UserPassword,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="15" Height="25" HorizontalAlignment="Left" VerticalAlignment="Center" Width="179" > <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <Behaviors:EventCommand CommandName="pwdGotFocusCommand" EventName="GotFocus" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </PasswordBox> <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Name="textBlock2" Text="忘記密碼" Style="{Binding ElementName=textBlock1,Path=Style}" /> </StackPanel> <StackPanel Grid.Row="3" Orientation="Horizontal"> <CheckBox x:Name="chkRememberPwd" Content="記住密碼" IsThreeState="False" HorizontalAlignment="Left" Margin="115,0,0,0" VerticalAlignment="Top" > <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <Behaviors:EventCommand CommandName="chkUncheckedCommand" EventName="Unchecked"/> <Behaviors:EventCommand CommandName="chkCheckedCommand" EventName="Checked" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </CheckBox> <CheckBox x:Name="chkLanding" Content="自動登錄" IsThreeState="False" HorizontalAlignment="Left" Margin="15,0,0,0" VerticalAlignment="Top" /> </StackPanel> <StackPanel Grid.Row="4" Orientation="Horizontal"> <Button Margin="120,0,0,0" Height="33" Width="181" Name="btnLogin" VerticalAlignment="Top"> <TextBlock FontSize="18" FontFamily="Consolas;Microsoft YaHei" Foreground="Blue" Text="登 錄" /> <Behaviors:Events.Commands> <Behaviors:EventCommandCollection> <!--<Behaviors:EventCommand CommandName="btnMouseDoubleClickCommand" EventName="MouseDoubleClick" />--> <Behaviors:EventCommand CommandName="btnClickCommand" EventName="Click" /> </Behaviors:EventCommandCollection> </Behaviors:Events.Commands> </Button> </StackPanel> </Grid> </Viewbox> </Window>
運行後的界面
MainWindow.xaml 後臺代碼 MainWindow.cs
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace EventCommandDemo { /// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); #region 綁定數據和命令 MainViewModel _viewmodel = null; this.Loaded += (sender, e) => { if (_viewmodel == null) { _viewmodel = new MainViewModel(); this.DataContext = _viewmodel; } }; #endregion } } }
Mainwindow.xaml輔助類 PasswordBoxBindingHelper.cs,提供PasswordBox綁定屬性
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace EventCommandDemo { public static class PasswordBoxBindingHelper { public static bool GetIsPasswordBindingEnabled(DependencyObject obj) { return (bool)obj.GetValue(IsPasswordBindingEnabledProperty); } public static void SetIsPasswordBindingEnabled(DependencyObject obj, bool value) { obj.SetValue(IsPasswordBindingEnabledProperty, value); } public static readonly DependencyProperty IsPasswordBindingEnabledProperty = DependencyProperty.RegisterAttached("IsPasswordBindingEnabled", typeof(bool), typeof(PasswordBoxBindingHelper),new UIPropertyMetadata(false,OnIsPasswordBindingEnabledChanged)); private static void OnIsPasswordBindingEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as System.Windows.Controls.PasswordBox; if (passwordBox != null) { passwordBox.PasswordChanged -= PasswordBoxPasswordChanged; if ((bool)e.NewValue) { passwordBox.PasswordChanged += PasswordBoxPasswordChanged; } } } static void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e) { var passwordBox = (System.Windows.Controls.PasswordBox)sender; if (!String.Equals(GetBindedPassword(passwordBox), passwordBox.Password)) { SetBindedPassword(passwordBox, passwordBox.Password); //目的是讓打字的光標顯示在最後 int length = passwordBox.Password.Length; SetPasswordBoxSelection(passwordBox, length, length); } } public static string GetBindedPassword(DependencyObject obj) { return (string)obj.GetValue(BindedPasswordProperty); } public static void SetBindedPassword(DependencyObject obj, string value) { obj.SetValue(BindedPasswordProperty, value); } public static readonly DependencyProperty BindedPasswordProperty = DependencyProperty.RegisterAttached("BindedPassword", typeof(string), typeof(PasswordBoxBindingHelper),new UIPropertyMetadata(string.Empty, OnBindedPasswordChanged)); private static void OnBindedPasswordChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as System.Windows.Controls.PasswordBox; if (passwordBox != null) { passwordBox.Password = e.NewValue == null ? string.Empty : e.NewValue.ToString(); } } /// <summary> /// 在更改了密碼框的密碼後, 須要手動更新密碼框插入符(CaretIndex)的位置, 惋惜的是, /// 密碼框並無給咱們提供這樣的屬性或方法(TextBox有, PasswordBox沒有), /// 能夠採用下面的方法來設置 /// </summary> /// <param name="passwordBox"></param> /// <param name="start"></param> /// <param name="length"></param> private static void SetPasswordBoxSelection(System.Windows.Controls.PasswordBox passwordBox, int start, int length) { var select = passwordBox.GetType().GetMethod("Select", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); select.Invoke(passwordBox, new object[] { start, length }); } } }
MainWindow的ViewModel文件MainViewModel.cs 提供綁定數據和命令及命令實現方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using System.Windows; namespace EventCommandDemo { public class MainViewModel : ViewModelBase { public MainViewModel() { cboMouseEnterCommand = new ViewModelCommand((Object parameter) => { cboMouseEnterEvent(); }); cboTextBoxChangedCommand = new ViewModelCommand((Object parameter) => { cboTextBoxChangedEvent(); }); cboTextBoxBaseChangedCommand = new ViewModelCommand((Object parameter) => { cboTextBoxBaseChangedEvent(); }); cboSelectionChangedCommand = new ViewModelCommand((Object parameter) => { cboSelectionChangedEvent(); }); btnClickCommand = new ViewModelCommand((Object parameter) => { btnClickEvent(); }); btnMouseDoubleClickCommand = new ViewModelCommand((Object paramenter) => { btnMouseDoubleClickEvent(); }); pwdGotFocusCommand = new ViewModelCommand((Object paramenter) => { pwdGotFocusEvent(); }); chkCheckedCommand = new ViewModelCommand((Object paramenter) => { chkCheckedEvent(); }); chkUncheckedCommand = new ViewModelCommand((Object paramenter) => { chkUncheckedEvent(); }); var tempList =new string[]{"一個","兩個","三個"}; ListCollection = tempList; } #region 事件命令 /// <summary> /// 下拉框 鼠標進入事件命令 /// </summary> public ICommand cboMouseEnterCommand { get; private set; } /// <summary> /// 下拉框文本改變事件命令,經過TextBox.TextChanged /// </summary> public ICommand cboTextBoxChangedCommand { get;private set; } /// <summary> /// 下拉框文本改變事件命令,經過TextBoxBase.TextChanged /// </summary> public ICommand cboTextBoxBaseChangedCommand { get; private set; } /// <summary> /// 下拉框,選中事件 /// </summary> public ICommand cboSelectionChangedCommand { get; private set; } /// <summary> /// 登錄按鈕單機事件命令 /// </summary> public ICommand btnClickCommand { get; private set; } /// <summary> /// 登錄按鈕雙擊事件命令 /// </summary> public ICommand btnMouseDoubleClickCommand { get; private set; } /// <summary> /// 密碼框獲取焦點事件命令 /// </summary> public ICommand pwdGotFocusCommand { get; private set; } /// <summary> /// 多選框非選中事件命令 /// </summary> public ICommand chkUncheckedCommand { get;private set; } /// <summary> /// 多選框選中事件命令 /// </summary> public ICommand chkCheckedCommand { get;private set; } #endregion #region 事件執行方法 /// <summary> /// 下拉框 鼠標進入事件,執行方法。 /// </summary> private void cboMouseEnterEvent() { MessageBox.Show("下拉框,鼠標進入事件被觸發了"); } /// <summary> /// 下拉框文本改變事件,執行方法 /// </summary> private void cboTextBoxBaseChangedEvent() { MessageBox.Show("TextBoxBase - 用戶名輸入,下拉框文本改變事件被觸發了"); } private void cboTextBoxChangedEvent() { MessageBox.Show("TextBox - 用戶名輸入,下拉框文本改變事件被觸發了"); } /// <summary> /// 下拉框選中事件,執行方法 /// </summary> private void cboSelectionChangedEvent() { MessageBox.Show("下拉框,下拉框選中一個Item事件被觸發了"); } /// <summary> /// 登錄按鈕單機事件,執行方法 /// </summary> private void btnClickEvent() { MessageBox.Show("登錄按鈕,鼠標單機(Click)事件被觸發了"); } /// <summary> /// 登錄按鈕雙擊事件,執行方法 /// </summary> private void btnMouseDoubleClickEvent() { MessageBox.Show("登錄按鈕,鼠標雙擊事件被觸發了"); } /// <summary> /// 密碼框獲取焦點事件,執行方法 /// </summary> private void pwdGotFocusEvent() { MessageBox.Show("密碼框獲取了焦點,事件被觸發了"); } /// <summary> /// 多選框,非選中狀態事件,執行方法 /// </summary> private void chkUncheckedEvent() { MessageBox.Show("多選框沒選中,事件被觸發了"); } /// <summary> /// 多選框,選中狀態事件,執行方法 /// </summary> private void chkCheckedEvent() { MessageBox.Show("多選框選中,事件被觸發了"); } #endregion #region 成員 private string[] listCollection; #endregion #region 屬性 public string[] ListCollection { get { return listCollection; } set { this.SetProperty(ref this.listCollection,value);} } #endregion } }
ViewModel輔助類有ViewModelBase.cs,ViewModelCommand.cs 分別提供屬性更改通知和Command命令接口ICommand實現類
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; namespace EventCommandDemo { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; #region 支持.NET4.5 protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (object.Equals(storage, value)) { return false; } storage = value; this.OnPropertyChanged(propertyName); return true; } private void OnPropertyChanged([CallerMemberName] string propertyName = null) { var eventHandler = this.PropertyChanged; if (eventHandler != null) { eventHandler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion #region 支持.NET4.0 //private static string GetProperyName(string methodName) //{ // if (methodName.StartsWith("get_") || methodName.StartsWith("set_") || // methodName.StartsWith("put_")) // { // return methodName.Substring("get_".Length); // } // throw new Exception(methodName + " not a method of Property"); //} //protected bool SetProperty<T>(ref T storage, T value) //{ // if (object.Equals(storage, value)) { return false; } // storage = value; // string propertyName = GetProperyName(new System.Diagnostics.StackTrace(true).GetFrame(1).GetMethod().Name); // this.OnPropertyChanged(propertyName); // return true; //} //private void OnPropertyChanged(string propertyName) //{ // var eventHandler = this.PropertyChanged; // if (eventHandler != null) // { // eventHandler(this, new PropertyChangedEventArgs(propertyName)); // } //} #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EventCommandDemo { public class ViewModelCommand : System.Windows.Input.ICommand { private Action<Object> action; public Action<Object> ViewModelAction { get { return action; } set { action = value; } } public ViewModelCommand(Action<Object> act) { action = act; } public bool CanExecute(Object parameter) { return true; } public void Execute(Object parameter) { this.ViewModelAction(parameter); } public event EventHandler CanExecuteChanged { add { } remove { } } } }
事件被綁定後觸發相關事件界面:
這裏分享源碼EventCommandDemo.zip文件下載地址,但願你們在技術的殿堂裏都能快速成長。
源碼下載:
本文做者夜神,首發博客園,轉載請註明。