【问题标题】:WPF how to pass events to sibling elementsWPF如何将事件传递给兄弟元素
【发布时间】:2010-06-22 06:29:16
【问题描述】:

我已阅读帖子Button.MouseDown 接着,我想再问 1 个问题。 我的 XAML 如下:

    <Window.Resources>
    <Style TargetType="{x:Type ContentControl}">
        <Setter Property="BorderThickness" Value="5" />
        <Setter Property="Padding" Value="10" />
        <Setter Property="Background" Value="PaleGreen" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
                        <ContentPresenter/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<StackPanel Tag="Panel" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
    <ContentControl BorderBrush="Red" Tag="C1" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
        <ContentControl BorderBrush="Green" Tag="C2" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
            <StackPanel Tag="Panel2" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown">
                <ContentControl Content="Click Me" BorderBrush="Blue" Tag="C3" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown"/>
                <ContentControl Content="Click Me2" BorderBrush="Blue" Tag="C33" PreviewMouseDown="PreviewMouseDown" MouseDown="MouseDown"/>
            </StackPanel>
        </ContentControl>
    </ContentControl>
</StackPanel>

我的cs如下:

        private void PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        Debug.WriteLine(((FrameworkElement) sender).Tag + " Preview");
    }

    private void MouseDown(object sender, MouseButtonEventArgs e)
    {
        Debug.WriteLine(((FrameworkElement) sender).Tag + " Bubble");
    }

如何将鼠标向上/向下事件从 C3 传输到 C33?基本上我希望 1 个兄弟姐妹的所有事件也能到达其他兄弟姐妹。

【问题讨论】:

    标签: wpf events event-bubbling


    【解决方案1】:

    您可以从 C3 的 EventHandler 调用 C33 的 RaiseEvent 方法:

    private void C3_MouseDown(object sender, MouseButtonEventArgs e)
    {
      C33.RaiseEvent(e);
    }
    

    顺便说一句,我注意到您正在使用 Tag 来命名您的元素。一个更合适的属性是 Name 属性。一般规则是 Tag 属性的使用仅适用于大约 0.001% 的 WPF 程序(十万分之一)。在所有常用它的情况下,都有更好的方法来做同样的事情。

    【讨论】:

    • 我们是否也必须为所有其他事件处理程序编写这些代码?是否有捷径可以仅在一个功能中完成?
    【解决方案2】:

    我为这种场景写了一个行为:

    using System.Reflection;
    using System.Windows;
    using System.Windows.Interactivity;
    
    namespace Behaviors
    {
        public class RedirectRoutedEventBehavior : Behavior<UIElement>
        {
            public static readonly DependencyProperty RedirectTargetProperty =
                DependencyProperty.Register("RedirectTarget", typeof(UIElement),
                    typeof(RedirectRoutedEventBehavior),
                    new PropertyMetadata(null));
    
            public static readonly DependencyProperty RoutedEventProperty =
                DependencyProperty.Register("RoutedEvent", typeof(RoutedEvent), typeof(RedirectRoutedEventBehavior),
                    new PropertyMetadata(null, OnRoutedEventChanged));
    
            public UIElement RedirectTarget
            {
                get => (UIElement) this.GetValue(RedirectTargetProperty);
                set => this.SetValue(RedirectTargetProperty, value);
            }
    
            public RoutedEvent RoutedEvent
            {
                get => (RoutedEvent) this.GetValue(RoutedEventProperty);
                set => this.SetValue(RoutedEventProperty, value);
            }
    
            private static MethodInfo MemberwiseCloneMethod { get; }
                = typeof(object)
                    .GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);
    
            private static void OnRoutedEventChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                ((RedirectRoutedEventBehavior) d).OnRoutedEventChanged((RoutedEvent) e.OldValue, (RoutedEvent) e.NewValue);
            }
    
            private void OnRoutedEventChanged(RoutedEvent oldValue, RoutedEvent newValue)
            {
                if (this.AssociatedObject == null)
                {
                    return;
                }
    
                if (oldValue != null)
                {
                    this.AssociatedObject.RemoveHandler(oldValue, new RoutedEventHandler(this.EventHandler));
                }
    
                if (newValue != null)
                {
                    this.AssociatedObject.AddHandler(newValue, new RoutedEventHandler(this.EventHandler));
                }
            }
    
            protected override void OnAttached()
            {
                base.OnAttached();
                if (this.RoutedEvent != null)
                {
                    this.AssociatedObject.AddHandler(this.RoutedEvent, new RoutedEventHandler(this.EventHandler));
                }
            }
    
            protected override void OnDetaching()
            {
                if (this.RoutedEvent != null)
                {
                    this.AssociatedObject.RemoveHandler(this.RoutedEvent, new RoutedEventHandler(this.EventHandler));
                }
    
                base.OnDetaching();
            }
    
            private static RoutedEventArgs CloneEvent(RoutedEventArgs e)
            {
                return (RoutedEventArgs) MemberwiseCloneMethod.Invoke(e, null);
            }
    
            private void EventHandler(object sender, RoutedEventArgs e)
            {
                var newEvent = CloneEvent(e);
                e.Handled = true;
    
                if (this.RedirectTarget != null)
                {
                    newEvent.Source = this.RedirectTarget;
                    this.RedirectTarget.RaiseEvent(newEvent);
                }
            }
        }
    }
    

    用法:

    <ContentControl x:Name="A" Content="Click Me" BorderBrush="Blue">
        <i:Interaction.Behaviors>
            <behaviors:RedirectRoutedEventBehavior RoutedEvent="UIElement.MouseDown" 
                                               RedirectTarget="{Binding ElementName=B}" />
            <behaviors:RedirectRoutedEventBehavior RoutedEvent="UIElement.PreviewMouseDown" 
                                               RedirectTarget="{Binding ElementName=B}" />
        </i:Interaction.Behaviors>
    </ContentControl>
    <ContentControl x:Name="B" Content="Click Me2" BorderBrush="Blue" />
    

    这会将MouseDownPreviewMouseDown 事件从A 重定向到B

    您的项目需要Install-Package System.Windows.Interactivity.WPF,以及 xmlns 声明:

    xmlns:behaviors="clr-namespace:Behaviors"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    

    【讨论】:

      猜你喜欢
      • 2018-10-24
      • 2018-01-27
      • 2021-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-12
      • 2014-07-27
      • 1970-01-01
      相关资源
      最近更新 更多