过程很简单,传递ViewModel到附加属性,附加属性引发相关事件和取消事件,从而引发VM中的委托。
修改版本4 2020年7月23日
简化内容。更多东西可以扩展后续的东西可以自由修改。
public abstract class AttachObject : Animatable { protected Delegate RunDelegate;
protected override Freezable CreateInstanceCore() { return (Freezable)Activator.CreateInstance(this.GetType()); } public virtual void RunAction() { if (AttachObjectTarget != null && !string.IsNullOrWhiteSpace(AttachObjectEventName)) { var GetSource = AttachObjectTarget.GetType(); var RunMothod = GetSource.GetEvent(AttachObjectEventName); var ClassMethod = this.GetType().GetMethod(nameof(DoAcion), BindingFlags.Public | BindingFlags.Instance); RunDelegate = Delegate.CreateDelegate(RunMothod.EventHandlerType, this, ClassMethod); RunMothod.AddEventHandler(AttachObjectTarget, RunDelegate); } } public virtual void OnDeach() { if (RunDelegate != null) { var GetSource = AttachObjectTarget.GetType(); var mothod = GetSource.GetEvent(AttachObjectEventName); mothod.RemoveEventHandler(AttachObjectTarget, RunDelegate); RunDelegate = null;
AttachObjectTarget=null; } } protected virtual void OnAttach(object args) { } public virtual void DoAcion(object sender, EventArgs e) { OnAttach(e); } public DependencyObject AttachObjectTarget { get; set; } public string AttachObjectEventName { get { return (string)GetValue(AttachObjectEventNameProperty); } set { SetValue(AttachObjectEventNameProperty, value); } } public static readonly DependencyProperty AttachObjectEventNameProperty = DependencyProperty.Register("AttachObjectEventName", typeof(string), typeof(AttachObject), new PropertyMetadata(string.Empty)); }
附加属性
public class AttachMethod { public static FreezableCollection<AttachObject> GetAttachObjectTarget(DependencyObject obj) { if (!(obj.GetValue(AttachObjectTargetProperty) is FreezableCollection<AttachObject> list)) { list = new FreezableCollection<AttachObject>(); obj.SetValue(AttachObjectTargetProperty, list); } return list; } private static readonly DependencyProperty AttachObjectTargetProperty = DependencyProperty.RegisterAttached("DrakAttachObjectTarget", typeof(FreezableCollection<AttachObject>), typeof(AttachMethod), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged))); private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.OldValue != null) { var list = e.OldValue as FreezableCollection<AttachObject>; if (list.Count > 0) { foreach (var item in list) { item.OnDeach(); } } } if (e.NewValue != null) { var list = e.NewValue as FreezableCollection<AttachObject>; if (list.Count > 0) { foreach (var item in list) { if (!string.IsNullOrWhiteSpace(item.AttachObjectEventName)) { if (item.AttachObjectTarget == null) { item.AttachObjectTarget = d; item.RunAction(); } } } } } } }
测试内容
public class EventMethod : AttachObject { protected override void OnAttach(object args) { if (args != null && DoCommand !=null&& DoCommand.CanExecute(args)) { DoCommand.Execute(args); } } public ICommand DoCommand { get { return (ICommand)GetValue(DoCommandProperty); } set { SetValue(DoCommandProperty, value); } } public static readonly DependencyProperty DoCommandProperty = DependencyProperty.Register("DoCommand", typeof(ICommand), typeof(EventMethod), new PropertyMetadata(null)); }
<Button Content="Click"> <local:AttachMethod.AttachObjectTarget> <local:EventMethod AttachObjectEventName="Click" DoCommand="{Binding DoTest1}" /> <local:EventMethod AttachObjectEventName="MouseWheel" DoCommand="{Binding DoTest2}"/> </local:AttachMethod.AttachObjectTarget> </Button>
截图
修改版本3 2020年5月19日22点09分
完了彻底一样了,支持多个绑定
截图
Xaml
<Button Height="120" VerticalAlignment="Top" Content="click" x:Name="b1" > <local:Attach.ViewModelData> <local:AttachModel Command="{Binding Click}" EventName="Click" PushAttach="{Binding ElementName=cb1,Path=IsChecked}" /> <local:AttachModel Command="{Binding Move}" EventName="MouseRightButtonUp" PushAttach="{Binding ElementName=cb1,Path=IsChecked}" /> </local:Attach.ViewModelData> </Button> <CheckBox Height="120" Content="click" x:Name="cb1" IsChecked="True" />
代码:
public class AttachModel: FreezableCollection<AttachModel> { public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AttachModel), new PropertyMetadata(null)); public ICommand Command { get =>(ICommand) GetValue(CommandProperty) ; set => SetValue(CommandProperty, value); } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AttachModel), new PropertyMetadata(null)); public object CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); } public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(AttachModel), new PropertyMetadata(null)); public string EventName { get => GetValue(EventNameProperty).ToString(); set => SetValue(EventNameProperty, value); } protected override Freezable CreateInstanceCore() { return (AttachModel)Activator.CreateInstance(typeof(AttachModel)); } public static readonly DependencyProperty PushAttachProperty = DependencyProperty.Register("PushAttach", typeof(bool), typeof(AttachModel), new PropertyMetadata(false)); public bool PushAttach { get => (bool)GetValue(PushAttachProperty); set => SetValue(PushAttachProperty, value); } private DependencyObject ElementUI; private Delegate dlg; public void SetParameter(DependencyObject dependency) { if(ElementUI!=dependency) this.ElementUI = dependency; if (PushAttach && Command != null && EventName != "") { if (dlg == null) DoAcion(); } else if (dlg != null) UnDoAcion(); } public void UnDoAcion() { if (dlg != null) { var uisource = ElementUI.GetType(); var mothod = uisource.GetEvent(EventName); mothod.RemoveEventHandler(ElementUI, dlg); dlg = null; } } public void DoAcion() { var getsource = ElementUI.GetType(); var mothod = getsource.GetEvent(EventName); var k = Activator.CreateInstance(typeof(AttachModel)); var local = this.GetType().GetMethod(nameof(EventMethod), BindingFlags.Public | BindingFlags.Instance); dlg = Delegate.CreateDelegate(mothod.EventHandlerType, this,local); mothod.AddEventHandler(ElementUI, dlg); } public void EventMethod(object sender, EventArgs e) { if (CommandParameter != null) if (Command.CanExecute(CommandParameter)) Command.Execute(CommandParameter); if (CommandParameter == null) if (Command != null) if (Command.CanExecute(e)) Command.Execute(e); } } public class Attach { private static readonly DependencyProperty ViewModelDataProperty = DependencyProperty.RegisterAttached("ViewModel", typeof(FreezableCollection<AttachModel>), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged))); private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { var list = e.NewValue as FreezableCollection<AttachModel>; if(list.Count>0) foreach (var item in list) item.SetParameter(d); } } public static FreezableCollection<AttachModel> GetViewModelData(DependencyObject d) { if (!(d.GetValue(ViewModelDataProperty) is FreezableCollection<AttachModel> list)) { list = new FreezableCollection<AttachModel>(); d.SetValue(ViewModelDataProperty, list); } return list; } }
修正版本2 2020年5月19日 07点03分
彻底一模一样了,和之前写的。
不过更顺了
添加内容
public class AttachModel: Animatable { public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(AttachModel), new PropertyMetadata(null)); public ICommand Command { get =>(ICommand) GetValue(CommandProperty) ; set => SetValue(CommandProperty, value); } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(AttachModel), new PropertyMetadata(null)); public object CommandParameter { get => GetValue(CommandParameterProperty); set => SetValue(CommandParameterProperty, value); } public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(AttachModel), new PropertyMetadata(null)); public string EventName { get => GetValue(EventNameProperty).ToString(); set => SetValue(EventNameProperty, value); } public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(AttachModel), new PropertyMetadata(null)); protected override Freezable CreateInstanceCore() { return new AttachModel(); } public object Source { get => GetValue(SourceProperty); set => SetValue(SourceProperty, value); } public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register("SourceName", typeof(string), typeof(AttachModel), new PropertyMetadata(null)); public string SourceName { get => GetValue(SourceNameProperty).ToString(); set => SetValue(SourceNameProperty, value); } public static readonly DependencyProperty PushAttachProperty = DependencyProperty.Register("PushAttach", typeof(bool), typeof(AttachModel), new PropertyMetadata(false)); public bool PushAttach { get => (bool)GetValue(PushAttachProperty); set => SetValue(PushAttachProperty, value); } } public class Attach { private static DependencyObject ElementUI; private static Delegate dlg; private static AttachModel model; public static readonly DependencyProperty ViewModelDataProperty = DependencyProperty.RegisterAttached("ViewModelData", typeof(AttachModel), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged))); private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (ElementUI != d) ElementUI = d; if (e.NewValue != null) { model = e.NewValue as AttachModel; if (model.PushAttach) { if (model.Command != null) DoAcion(); } else if (dlg != null) { UnDoAcion(); } } } public static void SetViewModelData(DependencyObject d, AttachModel value) => d.SetValue(ViewModelDataProperty, value); public static AttachModel GetViewModelData(DependencyObject d) => (AttachModel)d.GetValue(ViewModelDataProperty); private static void UnDoAcion() { var uisource =ElementUI.GetType(); var mothod = uisource.GetEvent(model.EventName); mothod.RemoveEventHandler(ElementUI, dlg); var getsource = model.Source.GetType(); var sourcemothod = getsource.GetProperty(model.SourceName).GetValue(model.Source) as Action<object, EventArgs>; sourcemothod = null; } private static void DoAcion() { var getsource = ElementUI.GetType(); var mothod = getsource.GetEvent(model.EventName); var k = Activator.CreateInstance(typeof(Attach)); var local = k.GetType().GetMethod(nameof(EventMethod), BindingFlags.Public | BindingFlags.Instance); dlg = Delegate.CreateDelegate(mothod.EventHandlerType, k, local); mothod.AddEventHandler(ElementUI, dlg); } public void EventMethod(object sender, EventArgs e) { //var getsource = model.Source.GetType(); //var mothod = getsource.GetProperty(model.SourceName).GetValue(model.Source) as Action<object, EventArgs>; //mothod?.Invoke(sender, e); if (model.CommandParameter != null) if (model.Command.CanExecute(model.CommandParameter)) model.Command.Execute(model.CommandParameter); if(model.CommandParameter==null) if (model.Command.CanExecute(e)) model.Command.Execute(e); } #region //public static readonly DependencyProperty EventNameProperty = DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(AttachModel), new PropertyMetadata(null, new PropertyChangedCallback(OnEventNameValueChanged))); //public static void SetEventName(DependencyObject d, object value) => d.SetValue(EventNameProperty, value); //public static string GetEventName(DependencyObject d) => (string)d.GetValue(EventNameProperty); //private static void OnEventNameValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) //{ // if (!e.NewValue.Equals(EventName)) // EventName = e.NewValue.ToString(); //} //public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached("Source", typeof(object), typeof(AttachModel), new PropertyMetadata(null, new PropertyChangedCallback(OnSourceValueChanged))); //public static void SetSource(DependencyObject d, object value) => d.SetValue(SourceProperty, value); //public static object GetSource(DependencyObject d) => (object)d.GetValue(SourceProperty); //private static void OnSourceValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) //{ // if(ElementUI!=d) // ElementUI = d; // if(Source!=e.NewValue) // Source = e.NewValue; //} //public static readonly DependencyProperty SourceNameProperty = DependencyProperty.RegisterAttached("SourceName", typeof(string), typeof(AttachModel), new PropertyMetadata(null, new PropertyChangedCallback(OnSourceNameValueChanged))); //private static void OnSourceNameValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) //{ // if(e.NewValue!=null) // if (!e.NewValue.Equals(SourceName)) // SourceName = e.NewValue.ToString(); //} //public static void SetSourceName(DependencyObject d, object value) => d.SetValue(SourceNameProperty, value); //public static string GetSourceName(DependencyObject d) => (string)d.GetValue(SourceNameProperty); #endregion } public class CommandBase : ICommand { private Action ex; private Action<EventArgs> ex2; public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { ex?.Invoke(); ex2?.Invoke((EventArgs)parameter); } public CommandBase(Action action) => this.ex = action; public CommandBase(Action<EventArgs> action) => this.ex2 = action; }
model内部
public ICommand Click { get { return new CommandBase(new Action<EventArgs>(OnClick)); } } private void OnClick(EventArgs obj) { MessageBox.Show(obj.ToString()); }
xaml
<Button Height="120" VerticalAlignment="Top" Content="click" x:Name="b1" > <local:Attach.ViewModelData > <local:AttachModel Source="{Binding }" Command="{Binding Click}" EventName="Click" PushAttach="{Binding ElementName=cb1,Path=IsChecked}" SourceName="OnSelect"/> </local:Attach.ViewModelData> </Button> <CheckBox Height="120" Content="click" x:Name="cb1" IsChecked="True" />
修正版本1:日期2020年5月18日 23点21分
有点像我之前写的https://www.cnblogs.com/T-ARF/p/12594980.html
但是这个更加简单,不用太多的属性。没有更多的限制
public class AttachModel: Animatable { public static readonly DependencyProperty EventNameProperty = DependencyProperty.Register("EventName", typeof(string), typeof(AttachModel), new PropertyMetadata(null)); public string EventName { get => GetValue(EventNameProperty).ToString(); set => SetValue(EventNameProperty, value); } public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(object), typeof(AttachModel), new PropertyMetadata(null)); protected override Freezable CreateInstanceCore() { return new AttachModel(); } public object Source { get => GetValue(SourceProperty); set => SetValue(SourceProperty, value); } public static readonly DependencyProperty SourceNameProperty = DependencyProperty.Register("SourceName", typeof(string), typeof(AttachModel), new PropertyMetadata(null)); public string SourceName { get => GetValue(SourceNameProperty).ToString(); set => SetValue(SourceNameProperty, value); } public static readonly DependencyProperty PushAttachProperty = DependencyProperty.Register("PushAttach", typeof(bool), typeof(AttachModel), new PropertyMetadata(false)); public bool PushAttach { get => (bool)GetValue(PushAttachProperty); set => SetValue(PushAttachProperty, value); } } public class Attach { private static DependencyObject ElementUI; private static Delegate dlg; private static AttachModel model; public static readonly DependencyProperty ViewModelDataProperty = DependencyProperty.RegisterAttached("ViewModelData", typeof(AttachModel), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged))); private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (ElementUI != d) ElementUI = d; if (e.NewValue != null) { model = e.NewValue as AttachModel; if (model.PushAttach) { DoAcion(); } else if (dlg != null) { UnDoAcion(); } } } public static void SetViewModelData(DependencyObject d, AttachModel value) => d.SetValue(ViewModelDataProperty, value); public static AttachModel GetViewModelData(DependencyObject d) => (AttachModel)d.GetValue(ViewModelDataProperty); private static void UnDoAcion() { var uisource =ElementUI.GetType(); var mothod = uisource.GetEvent(model.EventName); mothod.RemoveEventHandler(ElementUI, dlg); var getsource = model.Source.GetType(); var sourcemothod = getsource.GetProperty(model.SourceName).GetValue(model.Source) as Action<object, EventArgs>; sourcemothod = null; } private static void DoAcion() { var getsource = ElementUI.GetType(); var mothod = getsource.GetEvent(model.EventName); var k = Activator.CreateInstance(typeof(Attach)); var local = k.GetType().GetMethod(nameof(EventMethod), BindingFlags.Public | BindingFlags.Instance); dlg = Delegate.CreateDelegate(mothod.EventHandlerType, k, local); mothod.AddEventHandler(ElementUI, dlg); } public void EventMethod(object sender, EventArgs e) { var getsource = model.Source.GetType(); var mothod = getsource.GetProperty(model.SourceName).GetValue(model.Source) as Action<object, EventArgs>; mothod?.Invoke(sender, e); } }
XAML代码
此处source绑定的是datacontext
<Button Height="120" VerticalAlignment="Top" Content="click" x:Name="b1" > <local:Attach.ViewModelData > <local:AttachModel Source="{Binding }" EventName="Click" PushAttach="{Binding ElementName=cb1,Path=IsChecked}" SourceName="OnSelect"/> </local:Attach.ViewModelData> </Button> <CheckBox Height="120" Content="click" x:Name="cb1" IsChecked="True" />
***************************老版本*******************************************
public class Attach { private static DependencyObject ElementUI; private static object Source; private static string SourceName; private static string EventName; private static Delegate dlg; public static readonly DependencyProperty EventNameProperty = DependencyProperty.RegisterAttached("EventName", typeof(string), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnEventNameValueChanged))); public static void SetEventName(DependencyObject d, object value) => d.SetValue(EventNameProperty, value); public static string GetEventName(DependencyObject d) => (string)d.GetValue(EventNameProperty); private static void OnEventNameValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (!e.NewValue.Equals(EventName)) EventName = e.NewValue.ToString(); } public static readonly DependencyProperty PushAttachProperty = DependencyProperty.RegisterAttached("PushAttach", typeof(bool), typeof(Attach), new PropertyMetadata(false, new PropertyChangedCallback(OnPushAttachValueChanged))); public static void SetPushAttach(DependencyObject d, bool value) => d.SetValue(PushAttachProperty, value); public static bool GetPushAttach(DependencyObject d) => (bool)d.GetValue(PushAttachProperty); private static void OnPushAttachValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue == true) DoAcion(); if ((bool)e.NewValue == false) UnDoAcion(); } private static void UnDoAcion() { var uisource = ElementUI.GetType(); var mothod = uisource.GetEvent(EventName); mothod.RemoveEventHandler(ElementUI, dlg); var getsource = Source.GetType(); var sourcemothod = getsource.GetProperty(SourceName).GetValue(Source) as Action<object, EventArgs>; sourcemothod = null; } private static void DoAcion() { var getsource = ElementUI.GetType(); var mothod = getsource.GetEvent(EventName); var k = Activator.CreateInstance(typeof(Attach)); var local = k.GetType().GetMethod(nameof(EventMethod),BindingFlags.Public|BindingFlags.Instance); dlg = Delegate.CreateDelegate(mothod.EventHandlerType, k, local); mothod.AddEventHandler(ElementUI, dlg); } public void EventMethod(object sender, EventArgs e) { var getsource = Source.GetType(); var mothod = getsource.GetProperty(SourceName).GetValue(Source) as Action<object, EventArgs>; mothod?.Invoke(sender, e); } public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached("Source", typeof(object), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnSourceValueChanged))); public static void SetSource(DependencyObject d, object value) => d.SetValue(SourceProperty, value); public static object GetSource(DependencyObject d) => (object)d.GetValue(SourceProperty); private static void OnSourceValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(ElementUI!=d) ElementUI = d; if(Source!=e.NewValue) Source = e.NewValue; } public static readonly DependencyProperty SourceNameProperty = DependencyProperty.RegisterAttached("SourceName", typeof(string), typeof(Attach), new PropertyMetadata(null, new PropertyChangedCallback(OnSourceNameValueChanged))); private static void OnSourceNameValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(e.NewValue!=null) if (!e.NewValue.Equals(SourceName)) SourceName = e.NewValue.ToString(); } public static void SetSourceName(DependencyObject d, object value) => d.SetValue(SourceNameProperty, value); public static string GetSourceName(DependencyObject d) => (string)d.GetValue(SourceNameProperty); }
xaml
<Button Height="120" VerticalAlignment="Top" Content="click" x:Name="b1" local:Attach.Source="{Binding RelativeSource={RelativeSource Mode=Self},Path=DataContext}" local:Attach.EventName="Click" local:Attach.SourceName="OnEvent" local:Attach.PushAttach="{Binding ElementName=cb1,Path=IsChecked}"/>
<CheckBox Height="120" Content="click" x:Name="cb1" IsChecked="False" />
ViewMode中放置一个委托即可
public class VMTest: INotifyPropertyChanged { protected void OnValueChanged(string Name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); public event PropertyChangedEventHandler PropertyChanged; public Action<Object,EventArgs> OnEvent { get; set; } public VMTest() { OnEvent =new Action<Object,EventArgs>(OnEvent); } private void OnEvent(object arg1, EventArgs arg2) { MessageBox.Show("click"); } }
效果图