Style a WPF Button on right mouse click - wpf

Is it possible to add a style trigger in WPF to a Button to determine whether or not the ContextMenu has opened?
If so, I'd like to color the background of the corresponding button if the contextmenu is opened.
Can't find a regular way to do it...

Here's a solution:
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Grid.Column="1" Margin="5" Content="Button" x:Name="theButton">
<Button.Background>
<SolidColorBrush x:Name="BackgroundBrush" Color="LightGray" />
</Button.Background>
<Button.ContextMenu>
<ContextMenu x:Name="contextMenu">
<MenuItem Header="Option 1" />
<MenuItem Header="Option 2" />
</ContextMenu>
</Button.ContextMenu>
<Button.Triggers>
<!-- This changed the color to red when the context menu is openning -->
<EventTrigger RoutedEvent="Button.ContextMenuOpening">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBrush"
Storyboard.TargetProperty="Color" Duration="0:0:0" To="Red" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<!-- This changed the color back to light gray when the context menu is closing -->
<EventTrigger RoutedEvent="Button.ContextMenuClosing">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBrush"
Storyboard.TargetProperty="Color" Duration="0:0:0" To="LightGray" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>

Related

How to target a group of controls in a storyboard WPF

<Storyboard x:Key="OnClick1">
<DoubleAnimation Storyboard.TargetName="{StaticResource test}"
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
RepeatBehavior="2000"
AutoReverse="True"
Duration="0:0:0.7"/>
</Storyboard>
<Window.Triggers>
<EventTrigger RoutedEvent="ButtonBase.Loaded" SourceName="button">
<BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
</Window.Triggers>
<Button x:Name="button2" x:key="test" Content="Button" Margin="234,140,164,0" Height="37" VerticalAlignment="Top"/>
<Button x:Name="button3" x:key="test" Content="Button" Margin="234,140,164,0" Height="37" VerticalAlignment="Top"/>
I am trying to add this double animation to multiple buttons without duplicating the double animation. Initially, I had the TargetName set to the name of the first button and it works but if added key to the button I get this message "The property "key" does not exist in WinFX namespace.
Give ButtonA the storyboard that drives its Opacity. For each other button,
<Button
x:Name="button3"
Opacity="{Binding Opacity, ElementName=button2}"
...
/>
Alternatively, put all the buttons inside a StackPanel (or Grid, or whatever), and animate the parent's Opacity.
The sample markup you have posted doesn't provide a reproducible sample of your issue but you could add a trigger to each Button that you want to animate:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Storyboard x:Key="OnClick1">
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="1"
To="0"
RepeatBehavior="2000"
AutoReverse="True"
Duration="0:0:0.7"/>
</Storyboard>
</Window.Resources>
<StackPanel>
<Button x:Name="button2" Content="Button" Height="37" VerticalAlignment="Top">
<Button.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
</Button.Triggers>
</Button>
<Button x:Name="button3" Content="Button" Height="37" VerticalAlignment="Top">
<Button.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
</EventTrigger>
</Button.Triggers>
</Button>
</StackPanel>
</Window>

How do I slide down a grid with animation on mouse hover in wpf?

My req is to have a grid of 2 rows - the first row will be filled with comboboxes as search criteria for a DB query. The second row will be a DataGrid with the results.
I want the upper grid to slide down from the top when I hover over it, and slide back up on mouse leave. I guess I can have a simple textblock at the top "Filters" and hovering over it will bring down the comboboxes?
I have something like this, but when mouse over, the animation goes up/down with out stopping.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ControlsGrid"
Storyboard.TargetProperty="(Grid.Height)"
From="0"
To="66"
Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ControlsGrid"
Storyboard.TargetProperty="(Grid.Height)"
From="66"
To="0"
Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<TextBlock HorizontalAlignment="Center" FontSize="20" Text="Filters..."/>
</Grid>
<Grid Margin="0" Name="ControlsGrid" VerticalAlignment="top" Background="Yellow"/>
<DataGrid Grid.Row="1" ColumnHeaderStyle="{DynamicResource GridViewColumnHeaderStyle}" Background="LightGray" RowBackground="LightYellow" AlternatingRowBackground="LightBlue"
x:Name="dataGridViewRoomQuery" BorderBrush="Gray" BorderThickness="5"/>
</Grid>
The problem with your approach is that the "hovering" Grid (the one with the event triggers) gets a MouseLeave event whenever the ControlsGrid is placed above it.
You have to put the ControlsGrid into the hovering Grid:
<Grid Grid.Row="0" Background="Transparent">
<Grid.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ControlsGrid"
Storyboard.TargetProperty="Height"
To="66" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="ControlsGrid"
Storyboard.TargetProperty="Height"
To="0" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<TextBlock HorizontalAlignment="Center" FontSize="20" Text="Filters..."/>
<Grid Name="ControlsGrid" Height="0" VerticalAlignment="Top" Background="Yellow">
</Grid>
</Grid>
<DataGrid .../>

Animation in visibility from hidden to collapsed and vice versa

I am trying to achieve something similar to iPhone message view. On a button click, a delete button would slide out for every message and on clicking "done" the delete buttons would slide in. I have been able to achieve that using mvvm except the sliding effect.
Here is the style I could write with my limited knowledge:
<Style TargetType="Border">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowDeleteButton}" Value="false">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
Here "ShowDeleteButton" is a bool property in the view model. This works fine. but the collapsing and "getting visible" is happening abruptly and very fast. I need some sliding animation.
Please note that as the delete buttons disappear, the rest of the controls should take up the rest of space and, as the button appear, the existing controls should shrink and give space to the buttons.
I tried with storyboard animation but even after a couple hours I am not able to figure out the strange errors it is throwing. Here is the code:
<DataTrigger Binding="{Binding ShowDeleteButton}" Value="false">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard BeginTime="0:0:1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visiblity">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard BeginTime="0:0:1">
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visiblity">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
Can someone please help the soul in distress?
regards
Old question... huh...
Anyway... forget about visibility. The trick is to animate Width/Height of the Control placed in Grid's Column/Row where the Column/Row has Width set to Auto. Uff :)
So here is a Grid named "container" with two columns. In the first column can be placed whatever you want, but you should align it to Right since you want it to move when your delete button is displayed. And in the second column there is a Control (representing your DeleteButton) Notice that first column has Width="*" and second column has Width="Auto"
<Grid Background="Purple" Width="350" Height="100">
<CheckBox Content="Show" IsChecked="{Binding Path=ShowDeleteButton}" Height="16" HorizontalAlignment="Left" Margin="12,12,0,0" Name="checkBox1" VerticalAlignment="Top" />
<Grid x:Name="container" Margin="40,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Name="content" Margin="0">
<Label Content="Look I'm flyin'!" Margin="0,30,10,0" VerticalAlignment="Top" HorizontalAlignment="Right"/>
</Grid>
<Control Grid.Column="1" Margin="0">
<Control.Template>
<ControlTemplate>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ShowDeleteButton}" Value="true">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="flyout"
Storyboard.TargetProperty="(Grid.Width)"
From="0" To="120" Duration="0:0:1" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="flyout"
Storyboard.TargetProperty="(Grid.Width)"
From="120" To="0" Duration="0:0:1" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</ControlTemplate.Triggers>
<Grid x:Name="flyout" Width="0">
<Rectangle Fill="Green"/>
<Label Content="I'm DELETE button" Margin="10,30,0,0" VerticalAlignment="Top"/>
</Grid>
</ControlTemplate>
</Control.Template>
</Control>
</Grid>
</Grid>
And the Control in Grid's second column has DataTrigger based on your ViewModel's property "ShowDeleteButton"
Since the Width of column where the Control is placed is Auto you can change the width of the Control using simple DoubleAnimation and you get desired behavior.
EDIT
Look at this if you want the flyout to be over everything else.
<Grid x:Name="LayoutRoot">
<Grid x:Name="container" Width="120" HorizontalAlignment="Right">
<Button x:Name="button" Content="In" Margin="0,13,7.5,0" VerticalAlignment="Top" HorizontalAlignment="Right" d:LayoutOverrides="HorizontalAlignment">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="flyout"
Storyboard.TargetProperty="(Grid.Width)"
From="0" To="120" Duration="0:0:1" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
<Grid x:Name="flyout" Width="120" Margin="0" HorizontalAlignment="Right">
<Rectangle Fill="Green"/>
<Label Content="This is some label" Margin="6.038,27,1.006,0" VerticalAlignment="Top"/>
<Button Content="Out" Margin="11.917,58,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="80.083">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="flyout"
Storyboard.TargetProperty="(Grid.Width)"
From="120" To="0" Duration="0:0:1" AutoReverse="False"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Grid>
Please note that button "Out" can be clicked while it's moving. It should be probably disabled. I just did it like this because I wanted to do it simple and all in xaml. Sure you can use mahapps. Or you can just make it as fast as it is in MahApps and it's impossible to click it twice. :) I have looked at MahApps FlyOutDemo and my solution looks much simpler to me. And I don't need third party library.

Button Bounce on PropertyChange

I have a simple button (3 of them - all same except the content binding which is just an integer.
<Button Width="24" Height="24" Style="{StaticResource CircleButton}"
Background="#CC2B2B" Foreground="#FFFFFF"
Content="{Binding PinnedItemsCount,
FallbackValue=0,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
NotifyOnTargetUpdated=True}"
Name="ui_btnPinnedCount" />
How do I make the button boune when the data changes?
The underlying content implements INotifyPropertyChanged and the data bindings are all working, just need the button to bounce 3 times once the data changes....
Thanks!
Use animations with a DataTrigger
http://msdn.microsoft.com/en-us/library/system.windows.media.animation.bounceease.aspx
How to: Trigger an Animation When Data Changes
<Rectangle Name="myRectangle" Width="200" Height="30" Fill="Blue">
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseDown">
<BeginStoryboard>
<Storyboard>
<Storyboard x:Name="myStoryboard">
<DoubleAnimation From="30" To="200" Duration="00:00:3"
Storyboard.TargetName="myRectangle"
Storyboard.TargetProperty="Height">
<DoubleAnimation.EasingFunction>
<BounceEase Bounces="2" EasingMode="EaseOut"
Bounciness="2" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
This makes it fade in and out, replace with any sotryboard animation I imagine.
<Button Width="24" Height="24" Style="{StaticResource CircleButton}" Background="#CC2B2B" Foreground="#FFFFFF"
Content="{Binding PinnedCount, FallbackValue=0, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnTargetUpdated=True}"
Name="ui_btnPinnedCount">
<Button.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard AutoReverse="True">
<DoubleAnimation Storyboard.TargetName="ui_btnPinnedCount" Storyboard.TargetProperty="Opacity" To=".1" Duration="0:0:.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>

WPF - Setting usercontrol width using triggers and mouseenter event

I have a wrap panel full of usercontrols. When I hover the mouse over a usercontrol I want it to expand to show more details.
Some stripped down sample code:
<UserControl x:Class="WPFTestBed.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<UserControl.Resources>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<Setter TargetName="WPFTestBed.UserControl1" Property="Control.Width" Value="200"/>
</EventTrigger.Actions>
</EventTrigger>
</UserControl.Triggers>
<Grid Height="95" Width="123">
<Button Height="23" HorizontalAlignment="Left" Margin="17,30,0,0" Name="button1" VerticalAlignment="Top" Width="75">Button</Button>
</Grid>
</UserControl>
I would appreciate it if someone could point out where I'm going wrong, and set me down the correct path.
Ideally, I want the usercontrol to delay for x seconds when there is a mouseover, before expanding and showing the extra details.
Here is a solution (tested):
Keep in mind that you have to set a Width manually on the UserControl for this to work.
Then add this to your UserControl's body:
<UserControl.Style>
<Style>
<Style.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard BeginTime="0:0:4.0" Storyboard.TargetProperty="Width">
<DoubleAnimation To="200" Duration="0:0:1.0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</UserControl.Style>
It will start after 4 seconds, then animate the width from its current value to 200, over 1 second.
I've managed to get a bit further with what I want:
<UserControl x:Class="WPFTestBed.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="200" Width="170">
<UserControl.Resources>
<Storyboard x:Key="ExpandDisplay">
<DoubleAnimation Storyboard.TargetProperty="(UserControl.Width)"
From="200" To="380" Duration="0:0:0.25" AutoReverse="False"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Width)"
Storyboard.TargetName="mainBorder"
From="190" To="370" Duration="0:0:0.25" AutoReverse="False"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="button2"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="CollapseDisplay">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="button2"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="(UserControl.Width)"
From="380" To="200" Duration="0:0:0.25" AutoReverse="False"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.Width)"
Storyboard.TargetName="mainBorder"
From="370" To="190" Duration="0:0:0.25" AutoReverse="False"/>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseDown">
<BeginStoryboard Storyboard="{StaticResource ExpandDisplay}"/>
</EventTrigger>
<EventTrigger RoutedEvent="Button.Click" SourceName="button2">
<BeginStoryboard Storyboard="{StaticResource CollapseDisplay}"/>
</EventTrigger>
</UserControl.Triggers>
<Border Name="mainBorder" Height="190" Width="160" Background="Black" CornerRadius="20,20,20,20">
<Border.BitmapEffect>
<DropShadowBitmapEffect Color="Black" Direction="320" ShadowDepth="10" Opacity=".5"
Softness="9"/>
</Border.BitmapEffect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Height="23" Width="75" VerticalAlignment="Center" HorizontalAlignment="Center" Name="button1" >Details</Button>
<Button Grid.Row="1" Height="23" Width="23" VerticalAlignment="Center" HorizontalAlignment="Center" Name="button2" Visibility="Collapsed">-</Button>
</Grid>
</Border>
</UserControl>
This expands the usercontrol when I click, rather than mouseover, as I couldn't find a satisfactory way to wait for a second before beginning. I could delay the start and cancel on a mouseleave but this also cancelled the expand whenever the mouseleave was called.
I have a button to collapse the usercontrol, but I would prefer to switch which storyboard the usercontrol onclick event calls, can this be done?

Resources