【问题标题】:Copy all event handlers from one control to another at runtime在运行时将所有事件处理程序从一个控件复制到另一个控件
【发布时间】:2017-11-01 04:15:22
【问题描述】:

我正在尝试将每个事件处理程序从一个控件复制到另一个(相同类型)。 我发现了几个使用 Winform 的示例,但 WPF 没有...

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">

    <StackPanel x:Name="panel">
        <Button x:Name="btn1" 
                Content="Button 01"/>
    </StackPanel>
</Window>


using System;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            btn1.Click += (s, e) => Console.WriteLine("Button pressed");

            AddButton();
        }

        private void AddButton()
        {
            Button btn2 = new Button() { Content = "Button 02" };
            panel.Children.Add(btn2);

            // Copy all event handler from btn1 to btn2 ??
        }
    }
}

问题是我无权访问任何处理程序方法名称,因为我想从另一个类复制事件处理程序...

【问题讨论】:

  • “将每个事件处理程序从一个控件复制到另一个控件(相同类型)”是什么意思?你想让btn1点击处理程序也处理btn2的点击事件吗?
  • events 是一个 C# 概念,独立于 UI 框架。如果您找到了使用 System.Windows.Forms.Button 类执行此操作的代码,为什么不能使用 System.Windows.Controls.Button 类?
  • 我需要的是最终会产生类似的东西:btn2.Click += (s, e) =&gt; Console.WriteLine("Button pressed"); 或任何其他可能已分配给 btn1 的事件处理程序,而不仅仅是 ClickEvent
  • 您仍然没有回答问题:“使用 Winform 执行的几个示例 [a]mple[s] 有什么问题”? wpf 和 winforms 订阅事件的方式没有区别。
  • 我试过这个帖子:link 这似乎正是我想要的,但无法使其适用于 WPF...

标签: c# wpf reflection


【解决方案1】:

我终于找到了有用的东西here:

这是我正在使用的解决方案:

using System;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using BF = System.Reflection.BindingFlags;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            btn1.Click += (s, e) => Console.WriteLine($"{((Button)s).Content}a pressed");
            btn1.Click += Btn1_Click;
            btn1.MouseEnter += (s, e) => Console.WriteLine($"{((Button)s).Content} mouse entered");

            AddButton();
        }

        private void Btn1_Click(object sender, RoutedEventArgs e)
        {
            Console.WriteLine($"{((Button)sender).Content}b pressed");
        }


        private void AddButton()
        {
            Button btn2 = new Button() { Content = "Button 02" };
            panel.Children.Add(btn2);

            // Copy all event handler from btn1 to btn2 ??
            FieldInfo[] fields = btn1.GetType().GetFields(BF.Static | BF.NonPublic | BF.Instance | BF.Public | BF.FlattenHierarchy);
            foreach (FieldInfo field in fields.Where(x => x.FieldType == typeof(RoutedEvent)))
            {
                RoutedEventHandlerInfo[] routedEventHandlerInfos = GetRoutedEventHandlers(btn1, (RoutedEvent)field.GetValue(btn1));
                if (routedEventHandlerInfos != null)
                {
                    foreach (RoutedEventHandlerInfo routedEventHandlerInfo in routedEventHandlerInfos)
                        btn2.AddHandler((RoutedEvent)field.GetValue(btn1), routedEventHandlerInfo.Handler);
                }
            }
        }


        /// <summary>
        /// Get a list of RoutedEventHandlers
        /// Credit: Douglas : https://stackoverflow.com/a/12618521/3971575
        /// </summary>
        /// <param name="element"></param>
        /// <param name="routedEvent"></param>
        /// <returns></returns>
        public RoutedEventHandlerInfo[] GetRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
        {
            // Get the EventHandlersStore instance which holds event handlers for the specified element.
            // The EventHandlersStore class is declared as internal.
            PropertyInfo eventHandlersStoreProperty = typeof(UIElement).GetProperty("EventHandlersStore", BF.Instance | BF.NonPublic);
            object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);

            // If no event handlers are subscribed, eventHandlersStore will be null.
            // Credit: https://stackoverflow.com/a/16392387/1149773
            if (eventHandlersStore == null)
                return null;

            // Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance 
            // for getting an array of the subscribed event handlers.
            MethodInfo getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", BF.Instance | BF.Public | BF.NonPublic);

            return (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(eventHandlersStore, new object[] { routedEvent });
        }

    }
}

这样,我将 Click 事件的两个处理程序和 MouseEntered 事件的一个处理程序分配给第二个按钮。

【讨论】:

    猜你喜欢
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多