I have this configuration:

UserControl
- Grid
- - Grid
- - - Grid.Triggers
- - - - EventTrigger (this is where I want to listen for an event on UserControl)
- - ...etc

I am trying to create a routed event (maybe this I am going the wrong direction?) using this documentation: http://msdn.microsoft.com/en-us/library/ms752288(v=vs.110).aspx

So far, I have:

#region Show Blackout Event
public static readonly RoutedEvent ShowBlackoutEvent =
    EventManager.RegisterRoutedEvent("ShowBlackout", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(PatchManagerView));

// Provide CLR accessors for the event 
public event RoutedEventHandler ShowBlackout
{
    add { AddHandler(ShowBlackoutEvent, value); }
    remove { RemoveHandler(ShowBlackoutEvent, value); }
}

void RaiseShowBlackout()
{
    Dispatcher.Invoke(() => RaiseEvent(new RoutedEventArgs(ShowBlackoutEvent)));
}
#endregion

What I want is that when this event is raised, the event trigger condition is satisfied and plays the animation.

Edit - Working Code:

XAML

<UserControl x:Class="uPatch.Views.PatchManagerView"
             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:uPatch"
             xmlns:views="clr-namespace:uPatch.Views"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d" 
             d:DesignHeight="800" d:DesignWidth="600">
    <UserControl.Resources>
        <!--<Storyboard  x:Key="ShowBlurAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Radius" From="0" To="15" Duration="0:0:.25" />
        </Storyboard>-->
        <Storyboard x:Key="ShowBlackoutAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:.25" />
        </Storyboard>
        <Storyboard x:Key="HideBlackoutAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:.25" />
        </Storyboard>
        <Storyboard x:Key="ShowPatchAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Width" From="1" To="480" Duration="0:0:.25" />
            <DoubleAnimation Storyboard.TargetProperty="Height" From="1" To="320" Duration="0:0:.25" />
        </Storyboard>
        <Storyboard x:Key="HidePatchAnimation">
            <DoubleAnimation Storyboard.TargetProperty="Width" From="480" To="1" Duration="0:0:.25" />
            <DoubleAnimation Storyboard.TargetProperty="Height" From="320" To="1" Duration="0:0:.25" />
        </Storyboard>
    </UserControl.Resources>
    <Grid>
        <Grid x:Name="DimableGrid">
            <!--<Grid.Effect>
                <BlurEffect x:Name="blurEffect">
                    <BlurEffect.Radius>
                        <MultiBinding>
                            <MultiBinding.Converter>
                                <local:MultiplyConverter />
                            </MultiBinding.Converter>
                            <Binding Path="DataContext.DimAmount" RelativeSource="{RelativeSource AncestorType={x:Type UserControl}}" />
                            <Binding Path="Tag" ElementName="DimableGrid" />
                        </MultiBinding>
                    </BlurEffect.Radius>
                </BlurEffect>
            </Grid.Effect>-->
            <Grid x:Name="AllPatches">
                <Grid.RowDefinitions>
                    <RowDefinition Height="35" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Grid Grid.Row="0" HorizontalAlignment="Left">
                    <StackPanel Orientation="Horizontal" local:MarginSetter.Margin="2">
                        <Button Content="Add New Patch" Width="100" Height="25"/>
                        <Button Content="Add New Patch" Width="100" Height="25"/>
                    </StackPanel>
                </Grid>
                <Grid Grid.Row="1">
                    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" >
                        <ItemsControl AlternationCount="2" ItemsSource="{Binding PatchManager.Patches}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Vertical"   />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Grid x:Name="RowItem">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto" />
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="75" />
                                        </Grid.ColumnDefinitions>
                                        <TextBlock Grid.Column="0" Margin="5,0,0,0" VerticalAlignment="Center" Text="{Binding Version}" />
                                        <Button Grid.Column="2" Content="View" 
                                            Command="{Binding Path=DataContext.ViewPatch, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 
                                            CommandParameter="{Binding}" />
                                    </Grid>
                                    <DataTemplate.Triggers>
                                        <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                                            <Setter Property="Background" Value="Gray" TargetName="RowItem"/>
                                        </Trigger>
                                        <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                                            <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}" TargetName="RowItem"/>
                                        </Trigger>
                                        <Trigger Property="ItemsControl.IsMouseOver" Value="True">
                                            <Setter Property="Border.Background" Value="{DynamicResource FocusBrush}" TargetName="RowItem"/>
                                        </Trigger>
                                    </DataTemplate.Triggers>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </ScrollViewer>
                </Grid>
            </Grid>

            <Grid x:Name="Blackout">
                <Grid.Triggers>
                    <EventTrigger RoutedEvent="views:PatchManagerView.ShowPatch">
                        <BeginStoryboard Storyboard="{StaticResource ShowBlackoutAnimation}" />
                    </EventTrigger>
                    <EventTrigger RoutedEvent="views:PatchManagerView.HidePatch">
                        <BeginStoryboard Storyboard="{StaticResource HideBlackoutAnimation}" />
                    </EventTrigger>
                </Grid.Triggers>
                <Grid.Style>
                    <Style TargetType="Grid">
                        <Setter Property="Background" Value="#aa000000" />
                        <Setter Property="Visibility" Value="Hidden" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=DataContext.IsShowingPatch, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True" >
                                <Setter Property="Visibility" Value="Visible" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
            </Grid>
        </Grid>

        <Grid x:Name="PatchDisplay"
              local:StoryboardExtensions.Storyboard="{StaticResource HidePatchAnimation}"
              local:StoryboardExtensions.Completed="{Binding HidePatchAnimationCompleted}">
            <Grid.Triggers>
                <EventTrigger RoutedEvent="views:PatchManagerView.ShowPatch">
                    <BeginStoryboard Storyboard="{StaticResource ShowPatchAnimation}" />
                </EventTrigger>
                <EventTrigger RoutedEvent="views:PatchManagerView.HidePatch">
                    <BeginStoryboard Storyboard="{StaticResource HidePatchAnimation}" />
                </EventTrigger>
            </Grid.Triggers>
            <Grid.Style>
                <Style TargetType="Grid">
                    <Setter Property="Visibility" Value="Hidden" />
                    <Setter Property="Width" Value="1" />
                    <Setter Property="Height" Value="1" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsShowingPatch}" Value="True" >
                            <Setter Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Grid.Style>

            <Border Background="{DynamicResource TabControlContentBrush}" BorderThickness="1" CornerRadius="10">
                <Grid Margin="10">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="*" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <views:PatchView Grid.Row="0" Grid.ColumnSpan="2" DataContext="{Binding SelectedPatch}" Margin="5" />
                    <Button Command="{Binding ClosePatchView}" Margin="5" Width="100" Height="25" Grid.Row="1" Grid.Column="2" Content="Close" />
                </Grid>
            </Border>
        </Grid>
    </Grid>
</UserControl>

Code-Behind

using System;
using System.Windows;
using System.Windows.Controls;
using uPatch.ViewModels;

namespace uPatch.Views
{
    /// <summary>
    /// Interaction logic for PatchManagerView.xaml
    /// </summary>
    public partial class PatchManagerView : UserControl
    {
        public PatchManagerView()
        {
            InitializeComponent();
        }

        public PatchManagerView(PatchManagerVM vm)
            : this()
        {
            vm.ShowPatch = () => RaiseShowPatch();
            vm.HidePatch = () => RaiseHidePatch();
            DataContext = vm;
        }

        #region Show Blackout Event
        public static readonly RoutedEvent ShowPatchEvent =
            EventManager.RegisterRoutedEvent("ShowPatch", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(PatchManagerView));

        // Provide CLR accessors for the event 
        public event RoutedEventHandler ShowPatch
        {
            add { AddHandler(ShowPatchEvent, value); }
            remove { RemoveHandler(ShowPatchEvent, value); }
        }

        void RaiseShowPatch()
        {
            Blackout.RaiseEvent(new RoutedEventArgs(ShowPatchEvent));
            PatchDisplay.RaiseEvent(new RoutedEventArgs(ShowPatchEvent));
        }
        #endregion

        #region Hide Blackout Event
        public static readonly RoutedEvent HidePatchEvent =
            EventManager.RegisterRoutedEvent("HidePatch", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(PatchManagerView));

        // Provide CLR accessors for the event 
        public event RoutedEventHandler HidePatch
        {
            add { AddHandler(HidePatchEvent, value); }
            remove { RemoveHandler(HidePatchEvent, value); }
        }

        void RaiseHidePatch()
        {
            Blackout.RaiseEvent(new RoutedEventArgs(HidePatchEvent));
            PatchDisplay.RaiseEvent(new RoutedEventArgs(HidePatchEvent));
        }
        #endregion

    }
}

So it looks like the solution is to call RaiseEvent (passing in the RoutedEvent exposed by the top-level control) on the element which has the EventTrigger. To do this, I had to expose each of the controls via a x:Name property, and raise the event once per each of these controls. I didn't see any difference from Bubble or Direct or Tunnel... so I am still a little confused on the eventing structure that WPF uses.

I'd prefer that EventTriggers listen on top level events and the top level control can be the publisher... It seems odd that I have to publish once per control that needs the EventTrigger to raise for that RoutedEvent.

Still trying to figure out the WPF way of doing things.

有帮助吗?

解决方案

First of all you need to create your routed event as attached event if you want that to tunnel down to your Grid.

public static readonly RoutedEvent ShowBlackoutEvent =
    EventManager.RegisterRoutedEvent("ShowBlackout", RoutingStrategy.Bubble, 
                              typeof(RoutedEventHandler), typeof(MainWindow));

public static void AddShowBlackoutHandler(DependencyObject d,
                                          RoutedEventHandler handler)
{
    UIElement uie = d as UIElement;
    if (uie != null)
    {
       uie.AddHandler(MainWindow.ShowBlackoutEvent, handler);
    }
}

public static void RemoveShowBlackoutHandler(DependencyObject d,
                                             RoutedEventHandler handler)
{
   UIElement uie = d as UIElement;
   if (uie != null)
   {
      uie.RemoveHandler(MainWindow.ShowBlackoutEvent, handler);
   }
}

Also since it's tunnel event, you need to raise from UIElement where you need to handle it. In your case it will be Grid.

Give x:Name to your Grid:

UserControl
- Grid
- - Grid x:Name="grid"
- - - Grid.Triggers
- - - - EventTrigger

and raise an event from code behind:

void RaiseShowBlackout()
{
   grid.RaiseEvent(new RoutedEventArgs(ShowBlackoutEvent));
}

You have declared event as Tunnel event so it will tunnel will from root i.e. UserControl and will continue till sender i.e. grid and EvenTrigger will fire.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top