【问题标题】:WPF - Handling custom attached events on custom controlsWPF - 处理自定义控件上的自定义附加事件
【发布时间】:2010-11-23 12:00:57
【问题描述】:

我有一个这样声明的路由事件(名称已更改以保护无辜者):

public class DragHelper : DependencyObject {
    public static readonly RoutedEvent DragCompleteEvent = EventManager.RegisterRoutedEvent(
        "DragComplete",
        RoutingStrategy.Bubble,
        typeof(DragRoutedEventHandler),
        typeof(DragHelper)
    );

    public static void AddDragCompleteHandler( DependencyObject dependencyObject, DragRoutedEventHandler handler ) {
        UIElement element = dependencyObject as UIElement;
        if (element != null) {
            element.AddHandler(DragCompleteEvent, handler);
        }
    }

    public static void RemoveDragCompleteHandler( DependencyObject dependencyObject, DragRoutedEventHandler handler ) {
        UIElement element = dependencyObject as UIElement;
        if (element != null) {
            element.RemoveHandler(DragCompleteEvent, handler);
        }
    }

相当标准的东西。在 XAML 中,我有一个包含单个自定义控件的 DataTemplate。我正在尝试将此事件(以及其他一些附加属性)附加到控件:

<DataTemplate ...>
    <My:CustomControl
        My:DragHelper.IsDragSource="True"
        My:DragHelper.DragComplete="DragCompleteHandler" />
</DataTemplate>

这无法产生预期的结果。具体来说,在调用为 DragComplete 事件调用 RaiseEvent() 的代码时,从不调用处理程序。事实上,任何其他自定义路由事件的处理程序也不是在此 XAML 文件的其他地方挂钩。

我尝试更改路由事件的名称,并尝试将数据模板从一个带有 DataType 的模板切换为一个带有 x:Key 的模板。这对行为没有产生明显的变化。

但是,如果我将 My:CustomControl 更改为任何内置 WPF 控件,例如 TextBlock,则事件会完全按照我的预期触发。同样,如果我用我的项目中的任何其他自定义 UserControl 子类替换我的自定义控件,则行为将恢复为损坏的、无事件似乎要处理的状态。

这对我来说没有多大意义。我需要做一些具体的事情来让这个场景起作用吗?好像应该没关系。我想可能是我在所有自定义控件中所做的特定事情导致事件处理中断,但是到目前为止我尝试过的三个或四个自定义控件中没有看到任何共同点。

【问题讨论】:

    标签: c# wpf user-controls attached-properties


    【解决方案1】:

    你还没有发布你所有的代码,所以我不得不推断并组合我自己的版本。它对我来说没问题。也许与您的代码进行比较和对比:

    Window1.xaml.cs

    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfApplication1
    {
        public partial class Window1 : Window
        {
            public Window1()
            {
                InitializeComponent();
            }
    
            private void DragCompleteHandler(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("YEP");
            }
        }
    
        public class CustomControl : TextBox
        {
        }
    
        public class DragHelper : DependencyObject
        {
            public static readonly DependencyProperty IsDragSourceProperty = DependencyProperty.RegisterAttached("IsDragSource",
                typeof(bool),
                typeof(DragHelper),
                new FrameworkPropertyMetadata(OnIsDragSourceChanged));
    
            public static bool GetIsDragSource(DependencyObject depO)
            {
                return (bool)depO.GetValue(IsDragSourceProperty);
            }
    
            public static void SetIsDragSource(DependencyObject depO, bool ids)
            {
                depO.SetValue(IsDragSourceProperty, ids);
            }
    
            public static readonly RoutedEvent DragCompleteEvent = EventManager.RegisterRoutedEvent(
                "DragComplete",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(DragHelper)
            );
    
            public static void AddDragCompleteHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
            {
                UIElement element = dependencyObject as UIElement;
                if (element != null)
                {
                    element.AddHandler(DragCompleteEvent, handler);
                }
            }
    
            public static void RemoveDragCompleteHandler(DependencyObject dependencyObject, RoutedEventHandler handler)
            {
                UIElement element = dependencyObject as UIElement;
                if (element != null)
                {
                    element.RemoveHandler(DragCompleteEvent, handler);
                }
            }
    
            private static void OnIsDragSourceChanged(DependencyObject depO, DependencyPropertyChangedEventArgs e)
            {
                (depO as TextBox).TextChanged += delegate
                {
                    (depO as TextBox).RaiseEvent(new RoutedEventArgs(DragCompleteEvent, null));
                };
            }
        }
    }
    

    Window1.xaml

    <Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="Window1" Height="300" Width="300">
        <Window.Resources>
            <DataTemplate x:Key="Test">
                <local:CustomControl
                    local:DragHelper.IsDragSource="True"
                    local:DragHelper.DragComplete="DragCompleteHandler" />
            </DataTemplate>
        </Window.Resources>
    
        <ContentControl ContentTemplate="{StaticResource Test}"/>
    </Window>
    

    【讨论】:

    • 谢谢。我的自定义控件是从 UserControl 派生的,但即使将它切换到像您这样的 TextBox 仍然对我来说存在问题。我省略了其余代码,因为除了一些命名空间更改之外,它们基本上都与您的相同。但是,它是一个更大项目的一部分,因此可能会与某些全局样式或资源进行某种交互,或者我不知道这可能会影响问题。我会看看我能做什么。
    • 好吧,所以我有点愚弄了。从对我有用的完整示例开始,我尝试了各种方法将其转换为我在大型项目中看到的非功能性案例。过了一会儿,我偶然发现对您的基本代码进行了非常简单的更改,从而重现了该问题。如果我采用您的 DragHelper 实现并将其移动到主应用程序引用的不同程序集并相应地修改 Window1.xaml(添加 xmlns:other 和用户 other: 而不是本地:) 那么我不再看到消息框触发当我在文本框中输入时。 :|
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2018-05-28
    相关资源
    最近更新 更多