过程很简单,传递ViewModel到附加属性,附加属性引发相关事件和取消事件,从而引发VM中的委托。
修正版本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"); } }
效果图