首页 > 代码库 > WPF Event 在 Command 中的应用初级篇,支持所有Event 展示松耦合设计的全部代码 - 解决TextBoxBase.TextChanged或者TextBox.TextChanged等类似事件绑定问题。

WPF Event 在 Command 中的应用初级篇,支持所有Event 展示松耦合设计的全部代码 - 解决TextBoxBase.TextChanged或者TextBox.TextChanged等类似事件绑定问题。

做过WPF开发的人,都知道做MVVM架构,最麻烦的是Event的绑定,因为Event是不能被绑定的,同时现有的条件下,命令是无法替代Event。而在开发过程中无法避免Event事件,这样MVVM的架构就不能完全实现了。

所以后来微软提供了一个折中的方案,使用Trigger触发器和System.Windows.Interactivity结合通过事件绑定事件,个人觉得这个方法也挺可以的。

还有Prism框架方法,我看过但是这个方法比较繁琐可用性不高。

后来通过搜索和自己研究知道了一个解决方案,可以绑定所有事件,这个是原始版本,我个人正在研究一个完全的版本,希望能完全支持Event属性。

对于编程学习喜欢的方式,我个人是这个看法,我做开发也有一年多了,WPF开发也有九个月了。从小白到现在入门略有深入。不再局限于实现效果,而是更喜欢实现功能的原汁原味的代码。很多效果也许我不能写出完整的代码,也没有那么多的时间,但是深入看了别人的设计代码,总是受益良多。

工作这么长时间,总算明白为什么Java那么受欢迎了。因为作为技术人员到了一定境界,更喜欢了解具体的实现过程,而对于直接使用SDK的兴趣淡了不少。打个比方微软提供了很多优秀的SDK,但是就像家庭一样,越是包办一切的好父母,往往不太招孩子们的喜欢,不是孩子们不懂得感恩,而是社会自然规律,你无法成长,你便很容易感觉到自己无能,无能的人哪有快乐而言。

正文:具体的类图 通过类图可以看到结构相当清晰,它们的依赖关系是单向的。是属于低耦合的关系

 

 
现在提供各个类的代码,从上到下,层次从左到右。注意实际上建立类的顺序是相反的,这里只是为了展示方便
 
Events.cs
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;        }    }}
View Code


EventBehaviorCollection

using System;using System.Collections.Generic;namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors{    /// <summary>    /// 事件名称集合    /// </summary>    public class EventCommandCollection : List<EventCommand>    {    }}
View Code


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();        }    }}
View Code


EventCommandCollection

using System;using System.Collections.Generic;namespace ManMonthMyth.Practices.Composite.Presentation.Behaviors{    /// <summary>    /// 事件名称集合    /// </summary>    public class EventCommandCollection : List<EventCommand>    {    }}
View Code


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);            }        }    }}
View Code


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; }    }}
View Code

 

现在完整的框架已经搭建好了,现在就是做一个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=http://www.mamicode.com/"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=http://www.mamicode.com/"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.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.cs

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 =http://www.mamicode.com/= 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 });            }        }}
PasswordBoxBindingHelper.cs

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    }}
MainViewModel.cs

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           }}
ViewModelBase.cs

 

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 { }        }    }}
ViewModelCommand.cs

 

事件被绑定后触发相关事件界面:

 

这里分享源码EventCommandDemo.zip文件下载地址,希望大家在技术的殿堂里都能快速成长。

 

源码下载:

点击下载EventCommandDemo.zip

                                                                                                                       本文作者夜神,首发博客园,转载请注明。

 

WPF Event 在 Command 中的应用初级篇,支持所有Event 展示松耦合设计的全部代码 - 解决TextBoxBase.TextChanged或者TextBox.TextChanged等类似事件绑定问题。