views:

51

answers:

3

Can someone please help me out with this? I have the following template setup in WPF:

    <Style TargetType="{x:Type Label}" x:Key="NavLink">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate x:Name="NavLinkControlTemplate" TargetType="{x:Type Label}">
                    <Border x:Name="NavLinkBorder">
                        <ContentPresenter x:Name="NavLinkContent" Margin="4,4,4,4" />
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="NavLinkBorder" Property="Background" Value="#CCCCCC" />
                            <Setter Property="Cursor" Value="Hand" />
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="False">
                            <Setter TargetName="NavLinkBorder" Property="Background" Value="#EAEAEA" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

When my program is loaded, it automatically creates a list of labels that serve as the navigation menu. As you can see from the above, when the mouse hovers over one of the labels the background color is changed. The only problem with this is that I also have a context menu applied to the labels, and when I right-click to bring it up the label background goes back to its original color instead of staying the MouseOver color.

I've Googled for about an hour or so and can't seem to find a Trigger Property that will check if the right mouse button is pressed, so I'm assuming there isn't one. I'm thinking maybe I can accomplish this via code.

I have tried the following code, but I'm not having any luck:

    // this event is being added to each label at runtime...
    tempLabel.MouseRightButtonUp += new MouseButtonEventHandler(NavLink_RightClicked);

    // this is the method that the right-click calls...
    private void NavLink_RightClicked(object sender, EventArgs e)
        {
            if (sender is Label)
            {
                currentContextLink = sender as Label;

                // the below line won't work because the ControlTemplate seems to be overwriting it...
                currentContextLink.Background = new SolidColorBrush(appFunctions.HexToColor("#FF0000"));
            }
        }

I also tried getting the Label's parent element as a Border, but it seems that since it's setup through a template, the parent of the Label is actually the StackPanel I have containing all the labels.

Can someone please help me figure out how to access the border and change its Background color, or maybe guide me in any direction that may help me accomplish this?

Any help is GREATLY appreciated!

A: 

Try this in your style:

<EventTrigger RoutedEvent="MouseRightButtonUp">
    <BeginStoryboard>
        <Storyboard>
            <ColorAnimation To="#FF0000" Duration="0" Storyboard.TargetName="NavLinkBorder" Storyboard.TargetProperty="(Background).(Color)"  />
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>

Note that the <Trigger Property="IsMouseOver" Value="False"> will change the color back to #EAEAEA once the mouse is moved off. If you want the color to "stick", modify your ControlTemplate as follows:

<Border x:Name="NavLinkBorder">
    <Border x:Name="NavLinkInnerBorder" Background="Transparent" >
        <ContentPresenter x:Name="NavLinkContent" Margin="4,4,4,4" />
    </Border>
</Border>

...and change the ColorAnimation to look like this:

<ColorAnimation To="#FF0000" Duration="0" Storyboard.TargetName="NavLinkInnerBorder" Storyboard.TargetProperty="(Background).(Color)"  />
Rob Perkins
See further issue below please. There wasn't enough room in this comment box to post it all.
Randy
A: 

Thank you for your help, but I'm somewhat new to WPF, and am not very good with RoutedEvents. I added the first section of code like you suggested, but when I run it I get the following error:

Cannot convert string 'MouseRightButtonUp' in attribute 'RoutedEvent' to object of type 'System.Windows.RoutedEvent'. RoutedEventConverter cannot convert from System.String. Error at object 'System.Windows.EventTrigger' in markup file 'MyProgram;component/frmmain.xaml' Line 62 Position 43.

My XAML style code now looks like this:

    <Style TargetType="{x:Type Label}" x:Key="NavLink">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Label}">
                    <Border x:Name="NavLinkBorder" Background="#CCCCCC">
                        <ContentPresenter x:Name="NavLinkContent" Margin="4,4,4,4" />
                    </Border>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="NavLinkBorder" Property="Background" Value="#CCCCCC" />
                            <Setter Property="Cursor" Value="Hand" />
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="False">
                            <Setter TargetName="NavLinkBorder" Property="Background" Value="#EAEAEA" />
                        </Trigger>
                        <EventTrigger RoutedEvent="MouseRightButtonUp">
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation To="#FF0000" Duration="0" Storyboard.TargetName="NavLinkBorder" Storyboard.TargetProperty="(Background).(Color)"  />
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

And, I didn't post this before, but this is what the code looks like that generates my labels:

    Label tempLabel = new Label();
    tempLabel.Content = "My Link";
    tempLabel.ContextMenu = (ContextMenu)FindResource("NavContextMenu");
    tempLabel.FontSize = 12;
    tempLabel.Foreground = new SolidColorBrush(appFunctions.HexToColor("#000057"));
    tempLabel.Name = "myNavLink";
    tempLabel.Style = (Style)FindResource("NavLink");

    tempLabel.MouseLeftButtonUp += new MouseButtonEventHandler(NavLink_LeftClicked);
    tempLabel.MouseRightButtonUp += new MouseButtonEventHandler(NavLink_RightClicked);

    navPanel.Children.Add(tempLabel);

When I get the error, it highlights this line from the above code:

    tempLabel.Style = (Style)FindResource("NavLink");

Maybe I'm not attaching the label's style correctly...?

Randy
+1  A: 

You can add an additional data trigger to examine the ContextMenu's IsOpen property through binding.

<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=ContextMenu.IsOpen}" Value="True">
    <Setter TargetName="NavLinkBorder"  Property="Background" Value="#CCCCCC" />
    <Setter Property="Cursor" Value="Hand" />
</DataTrigger>

You can also get rid of the MouseOver="false" trigger and just set Background="#EAEAEA" on NavLinkBorder as the default value which will take over when no triggers are active.

Alternately, you can switch the border color setting to use template binding, which would help your code method to work. This is a good practice to use anyway as it makes your templates more flexible since different Background values can be set on individual Label instances. Here's the Style with some TemplateBindings and the context menu trigger added.

<Style TargetType="{x:Type Label}" x:Key="NavLink">
    <Setter Property="Background" Value="#EAEAEA" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate x:Name="NavLinkControlTemplate" TargetType="{x:Type Label}">
                <Border x:Name="NavLinkBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ContentPresenter x:Name="NavLinkContent" Margin="4,4,4,4" />
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="NavLinkBorder" Property="Background" Value="#CCCCCC" />
                        <Setter Property="Cursor" Value="Hand" />
                    </Trigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=ContextMenu.IsOpen}" Value="True">
                        <Setter TargetName="NavLinkBorder" Property="Background" Value="#CCCCCC" />
                        <Setter Property="Cursor" Value="Hand" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
John Bowen
John, thank you VERY much! The background color stays now; however, there is still one small bug. Since all my labels share the same context menu, when it opens the background color changes on ALL the labels instead of just the one I clicked. Is there a way to identify just the source element, or should I just create individual context menus for each label?
Randy
Nevermind, John, I was able to get accomplish this using code to determine when the context menu was opened and closed and changing the background of the sender, just as you stated! Thank you very much!
Randy