過程很簡單,傳遞ViewModel到附加屬性,附加屬性引發相關事件和取消事件,從而引發VM中的委托。 修正版本2 2020年5月19日 07點03分 徹底一模一樣了,和之前寫的。 不過更順了 添加內容 public class AttachModel: Animatable { public sta ...
過程很簡單,傳遞ViewModel到附加屬性,附加屬性引發相關事件和取消事件,從而引發VM中的委托。
修正版本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"); } }
效果圖