WPF-配置自定义事件以触发用户控件上的开始情节提要

WPF-配置自定义事件以触发用户控件上的开始情节提要,wpf,canvas,storyboard,eventtrigger,elementhost,Wpf,Canvas,Storyboard,Eventtrigger,Elementhost,我希望有人能在这里提供帮助,或者建议如何修复我所拥有的,或者建议一种更好的方式来实现我所追求的 我有一个简单的自定义控件,希望能够在该控件上启动/停止/暂停/恢复不透明度动画。我研究了各种解决方案,并认为将EventTrigger与自定义RoutedEvent结合使用是一条前进的道路。我可以让以下内容与标准事件(例如MouseDown)一起使用,但无法让我的自定义事件启动故事板 在加载事件之前,我尝试在构造函数中引发该事件,但两者都没有任何区别 我认为它没有任何相关的影响,但它也被托管在winf

我希望有人能在这里提供帮助,或者建议如何修复我所拥有的,或者建议一种更好的方式来实现我所追求的

我有一个简单的自定义控件,希望能够在该控件上启动/停止/暂停/恢复不透明度动画。我研究了各种解决方案,并认为将
EventTrigger
与自定义
RoutedEvent
结合使用是一条前进的道路。我可以让以下内容与标准事件(例如
MouseDown
)一起使用,但无法让我的自定义事件启动故事板

在加载事件之前,我尝试在构造函数中引发该事件,但两者都没有任何区别

我认为它没有任何相关的影响,但它也被托管在winforms的
ElementHost

xaml:

<UserControl x:Class="Fraxinus.BedManagement.WpfControls.FraxIconX"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Fraxinus.BedManagement.WpfControls"
             mc:Ignorable="d" 
             d:DesignHeight="16" d:DesignWidth="16"
             Loaded="FraxIconX_Loaded">
    <!--Height="16" Width="16" Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}" -->
    <UserControl.Resources>
        <ResourceDictionary>
            <Border x:Key="RoundedBorderMask" Name="iconBorder" CornerRadius="4" Background="White" BorderThickness="2" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <Border BorderThickness="2" CornerRadius="4" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center">
        <local:FraxCanvas x:Name="fraxCanvas" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center">
            <local:FraxCanvas.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" GradientStops="{Binding GradientStops}" />
            </local:FraxCanvas.Background>
            <local:FraxCanvas.Triggers>
                <EventTrigger RoutedEvent="local:FraxCanvas.OnStartStoryboard" SourceName="fraxCanvas">
                    <BeginStoryboard x:Name="storyboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.25" AutoReverse="True" Duration="0:0:1" RepeatBehavior="Forever"></DoubleAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </local:FraxCanvas.Triggers>
            <local:FraxCanvas.OpacityMask>
                <!--https://wpf.2000things.com/2012/05/11/556-clipping-to-a-border-using-an-opacity-mask/-->
                <VisualBrush Visual="{StaticResource RoundedBorderMask}"></VisualBrush>
            </local:FraxCanvas.OpacityMask>
            <Image HorizontalAlignment="Center" VerticalAlignment="Center" Height="16" Width="16" Source="{DynamicResource BitmapClockPng}" />
        </local:FraxCanvas>
    </Border>
</UserControl>
    public class FraxCanvas : Canvas
    {
        public static readonly RoutedEvent StartStoryboardEvent = EventManager.RegisterRoutedEvent("OnStartStoryboard", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(FraxCanvas));

        public event RoutedEventHandler OnStartStoryboard
        {
            add
            {
                this.AddHandler(StartStoryboardEvent, value);
            }

            remove
            {
                this.RemoveHandler(StartStoryboardEvent, value);
            }
        }
    }
FraxCanvas:

<UserControl x:Class="Fraxinus.BedManagement.WpfControls.FraxIconX"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Fraxinus.BedManagement.WpfControls"
             mc:Ignorable="d" 
             d:DesignHeight="16" d:DesignWidth="16"
             Loaded="FraxIconX_Loaded">
    <!--Height="16" Width="16" Background="{Binding Path=Background, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Control}, AncestorLevel=1}}" -->
    <UserControl.Resources>
        <ResourceDictionary>
            <Border x:Key="RoundedBorderMask" Name="iconBorder" CornerRadius="4" Background="White" BorderThickness="2" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <Border BorderThickness="2" CornerRadius="4" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center">
        <local:FraxCanvas x:Name="fraxCanvas" Height="16" Width="16" HorizontalAlignment="Center" VerticalAlignment="Center">
            <local:FraxCanvas.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" GradientStops="{Binding GradientStops}" />
            </local:FraxCanvas.Background>
            <local:FraxCanvas.Triggers>
                <EventTrigger RoutedEvent="local:FraxCanvas.OnStartStoryboard" SourceName="fraxCanvas">
                    <BeginStoryboard x:Name="storyboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0.25" AutoReverse="True" Duration="0:0:1" RepeatBehavior="Forever"></DoubleAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </local:FraxCanvas.Triggers>
            <local:FraxCanvas.OpacityMask>
                <!--https://wpf.2000things.com/2012/05/11/556-clipping-to-a-border-using-an-opacity-mask/-->
                <VisualBrush Visual="{StaticResource RoundedBorderMask}"></VisualBrush>
            </local:FraxCanvas.OpacityMask>
            <Image HorizontalAlignment="Center" VerticalAlignment="Center" Height="16" Width="16" Source="{DynamicResource BitmapClockPng}" />
        </local:FraxCanvas>
    </Border>
</UserControl>
    public class FraxCanvas : Canvas
    {
        public static readonly RoutedEvent StartStoryboardEvent = EventManager.RegisterRoutedEvent("OnStartStoryboard", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(FraxCanvas));

        public event RoutedEventHandler OnStartStoryboard
        {
            add
            {
                this.AddHandler(StartStoryboardEvent, value);
            }

            remove
            {
                this.RemoveHandler(StartStoryboardEvent, value);
            }
        }
    }
两个问题

  • 您只在收听
    EventTrigger.SourceName=“fraxCanvas”
    ,但该事件是在其他地方引发的(父
    UserControl
    )。
    EventTrigger.SourceName
    是一个筛选器属性,它允许 以独占方式处理特定元素的路由事件。如果未设置
    EventTrigger.SourceName
    , 触发器将处理指定的事件,无论 来源
  • 路由事件永远不会到达
    FraxCanvas
    元素,因为父级引发了它。
    RoutingStrategy.Bubble
    :事件从事件源(
    FraxIconX
    元素)传播到 可视化树根,例如,
    窗口

    RoutingStrategy.Tunnel
    :事件从树根开始移动,例如
    窗口
    在事件源处停止,即
    FraxIconX
    元素
  • 解决方案是删除
    EventTrigger.SourceName
    属性,并将触发器移动到事件源(即
    UserControl
    )或事件源的任何父元素:

    <UserControl>    
      <UserControl.Triggers>
        <EventTrigger RoutedEvent="local:FraxCanvas.OnStartStoryboard">
          <BeginStoryboard x:Name="storyboard">
            <Storyboard>
              <DoubleAnimation Storyboard.TargetName="fraxCanvas" 
                               Storyboard.TargetProperty="Opacity" 
                               From="1" To="0.25" />
            </Storyboard>
          </BeginStoryboard>
        </EventTrigger>
      </UserControl.Triggers>
    
      <Border>
        <FraxCanvas x:Name="fraxCanvas" />
      </Border>
    </UserControl>
    

    太棒了,这是一种享受。非常感谢您提供的解决方案和提高我的理解力。我投了更高的票,但由于我的声誉不够,所以没有表现出来。那是我头痛的一大剂量扑热息痛:-)