做過WPF開發的人,都知道做MVVM架構,最麻煩的是Event的綁定,因為Event是不能被綁定的,同時現有的條件下,命令是無法替代Event。而在開發過程中無法避免Event事件,這樣MVVM的架構就不能完全實現了。
所以后來微軟提供了一個折中的方案,使用Trigger觸發器和System.Windows.Interactivity結合通過事件綁定事件,個人覺得這個方法也挺可以的。
還有Prism框架方法,我看過但是這個方法比較繁瑣可用性不高。
后來通過搜索和自己研究知道了一個解決方案,可以綁定所有事件,這個是原始版本,我個人正在研究一個完全的版本,希望能完全支持Event屬性。
對於編程學習喜歡的方式,我個人是這個看法,我做開發也有一年多了,WPF開發也有九個月了。從小白到現在入門略有深入。不再局限於實現效果,而是更喜歡實現功能的原汁原味的代碼。很多效果也許我不能寫出完整的代碼,也沒有那么多的時間,但是深入看了別人的設計代碼,總是受益良多。
工作這么長時間,總算明白為什么Java那么受歡迎了。因為作為技術人員到了一定境界,更喜歡了解具體的實現過程,而對於直接使用SDK的興趣淡了不少。打個比方微軟提供了很多優秀的SDK,但是就像家庭一樣,越是包辦一切的好父母,往往不太招孩子們的喜歡,不是孩子們不懂得感恩,而是社會自然規律,你無法成長,你便很容易感覺到自己無能,無能的人哪有快樂而言。
正文:具體的類圖 通過類圖可以看到結構相當清晰,它們的依賴關系是單向的。是屬於低耦合的關系

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

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文件下載地址,希望大家在技術的殿堂里都能快速成長。
源碼下載:
本文作者夜神,首發博客園,轉載請注明。