views:

241

answers:

3

WPF newbie here so excuse the simple question. How do I cause a trigger to fire on a UserControl from a control outside of that UserControl? Here's what I want to do...

I have a UserControl with a trigger set to display a background color change on itself when IsMouseOver is True. If I mouse over the UserControl, the trigger fires as I expect. What I'd like to do is to create a window that contains the UserControl and a button, and when the user mouses over the button, fire the UserControl's trigger. Something like:

<Window x:Class="WpfApplication1.SimpleUCTry1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1.SimpleUCTry1"
Title="Window1" Height="300" Width="300">
<StackPanel>
    <local:Simple />
    <Button Content="Foo" />
</StackPanel>

So if the user mouses over the "Foo" button, the "Simple" UserControl's trigger would fire.

Is this possible?

Thank you, Andy

+1  A: 

Since your control is "external" to the button, you cannot use property triggers or data triggers to flip the background. What you need is an EventTrigger on Window level.

Start a keyframe or discrete color animation with 0 duration on MouseEnter and remove the mentioned storyboard on MouseLeave:

<Window.Triggers>
    <EventTrigger RoutedEvent="Mouse.MouseEnter" SourceName="button">
        <BeginStoryboard x:Name="Change_Control_Background_Start" 
            Storyboard="{StaticResource Change_Control_Background}"/>
    </EventTrigger>
    <EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="button">
        <RemoveStoryboard 
            BeginStoryboardName="Change_Control_Background_Start"/>
    </EventTrigger>
</Window.Triggers>
Sergey Aldoukhov
Thank you for your response! Would it be also possible to accomplish this with an EventSetter or a RoutedUICommand perhaps?
It is possible to do with EventSetter, but would require a code-behind handler (in that case, you can even handle mouse events directly by the button). As for RoutedUICommand, it is not a good match. Command is something that user does deliberately, and hovering does not fall into this category.
Sergey Aldoukhov
+1  A: 

Sergey's answer is the way to do it, in case you need something that can't be done with EventTrigger you can always wrap your controls in a DataTemplate and use ContentPresenter to show it:

<Window x:Class="WpfApplication1.SimpleUCTry1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1.SimpleUCTry1"
    Title="Window1" Height="300" Width="300">
    <ContentPresenter Content="{Binding}">
        <ContentPresenter.ContentTemplate>
            <DataTemplate>
                <StackPanel>
                    <local:Simple Name="Ctrl1" />
                    <Button Name="Ctrl2" Content="Foo" />
                </StackPanel>
                <DataTemplate.Triggers>
                    <Trigger SourceName="Ctrl2" Property="IsMouseOver" Value="True">
                        <Setter TargetName="Ctrl1" Property="Background" Value="Blue"/>
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ContentPresenter.ContentTemplate>
    </ContentPresenter>
</Window>
Nir
This is a nice way to do it - since Andy already has the UserControl. Just add the button mentioned to it (by definition it is tied to it visually already), and use the mentioned ContentPresenter trick.
Sergey Aldoukhov
A: 

Yet one more way to do it (requires some code behind but is probably the cleanest}

<StackPanel>
    <local:Simple Background="{Binding ElementName=bnFoo, 
                  Path=IsMouseOver, 
                  Converter={StaticResource boolToBackgroundConv}}"/>
    <Button Name="bnFoo" Content="Foo" />
</StackPanel>
Sergey Aldoukhov