WPF storyboard animation changes multiple UI objects instead of one - wpf

The issue
Moving styles file injection from App.xaml to view breaks animations. Instead of changing a specific element, it changes all the items with the same datatemplate.
Setup
Style.xaml:
<ResourceDictionary .....>
<Style x:Key="Style"
TargetType="{x:Type Path}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Viewbox}}}"
Value="True">
<Setter Property="Fill" Value="Orange" /> <----- works as expected, changes the object that is hovered
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard> <----- not as expected, changes all DataModel datatemplates there is
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX"
Duration="0:0:0.2"
To="2.33" />
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY"
Duration="0:0:0.2"
To="2.33" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<!-- omitted, returns the default value -->
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type DataModel}">
<Viewbox>
<Canvas Width="{Binding InitialWidth}"
Height="{Binding InitialHeight}">
<Canvas>
<Path Opacity="0.2"
x:Name="circle"
RenderTransform="{StaticResource DefaultScale}"
Style="{StaticResource Style}"> <---- the style in question
<Path.Data>
<EllipseGeometry RadiusX="{Binding Radius}"
RadiusY="{Binding Radius}" />
</Path.Data>
</Path>
<Canvas>
</Canvas>
</Viewbox>
</DataTemplate>
</ResourceDictionary>
MyView.xaml where style is used is UserControl all DataModel objects are under ItemsControl if that makes any difference.
<UserControl>
<ItemsControl VerticalAlignment="Center"
HorizontalAlignment="Center"
ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left"
Value="{Binding LeftOffset}" />
<Setter Property="Canvas.Top"
Value="{Binding TopOffset}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</UserControl>
The sole change
The issue appears when moving <ResourceDictionary Source="Style.xaml" /> from App.xaml:
<Application>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
to MyView.xaml
<UserControl>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Style.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
</UserControl>

Related

How get the click event of a ListBoxItem whilst using ItemTemplate

<Window.Resources>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<EventTrigger RoutedEvent="PreviewGotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames
Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Opacity" Value="1.0" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
Color="Blue"/>
</Style.Resources>
<Setter Property="Background" Value="Red" />
<Setter Property="MaxHeight" Value="75" />
</Style>
<DataTemplate x:Key="dtTeamInGame">
<WrapPanel >
<TextBox x:Name="txtPath" Text="{Binding Path = Number, Mode=TwoWay}" MinWidth="35" ></TextBox>
<TextBox x:Name="txtPath2" Text="{Binding Path = KnownName, Mode=TwoWay}" MinWidth="125" ></TextBox>
</WrapPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="listBox" ItemTemplate="{DynamicResource dtTeamInGame}" HorizontalAlignment="Left" Height="100" Margin="29,184,0,0" VerticalAlignment="Top" Width="381">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDownHome" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="335,108,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/>
</Grid>
I have a Listbox which contains Textboxes in the item and I would like for when I click the textbox the item the textbox is in should be selected. Before adding:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDownHome" />
</Style>
</ListBox.ItemContainerStyle>
the list box item would be selected if I clicked the textbox within an item. If I remove the container style above it works as intended but I need the container style because I would like to carry out some tasks if the user clicks an item that is already selected.
It sounds like you want to keep behavior from the default ListBoxItem style, but you also want to add your own stuff to it. That's easy: Use the BasedOn property of the style to inherit from the existing default style.
<ListBox.ItemContainerStyle>
<Style
TargetType="ListBoxItem"
BasedOn="{StaticResource {x:Type ListBoxItem}}"
>
<!-- Your stuff -->

How to change tile background on mouse over in WPF?

Using the code provided in this post:
lighten background color on button click per binding with converter
I have written the following code to change the background of a MahApps Tile on MouseOver:
<local:ColorLightConverter x:Key="colorLightConverter" />
<Style x:Key="aaa" TargetType="mah:Tile">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding Path=Background.Color, RelativeSource={RelativeSource TemplatedParent}, Mode=OneTime, Converter={StaticResource colorLightConverter}}" />
</Trigger>
</Style.Triggers>
</Style>
The color light converter is the same as written in the post mentioned and the style is used on the Mahapps Metro Tile. The code does not work, because the tile flickers on MouseOver. Also, placing a breakpoint inside the converter, I saw that it is not reached.
What am I doing wrong?
I could reproduce the problem with the Tile control. It never enters the Converter code because TemplatedParent is null. When I changed the RelativeSource to AncestorType={x:Type StackPanel} as it was in my case, the flickering went away and the breakpoint in the converter was reached. You can check if this is the case with you by adding to the Binding FallbackValue=Red in which case the color on mouse over will be Red for a faulty binding.
Here is my working XAML:
<Window.Resources>
<local:ColorLightConverter x:Key="colorLightConverter" />
<Style x:Key="aaa" TargetType="{x:Type Control}">
<Setter Property="Background" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding Path=Background.Color, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Converter={StaticResource colorLightConverter},FallbackValue=Red}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Background="DarkGoldenrod">
<mah:Tile Title="Hello!" Style="{StaticResource aaa}"
TiltFactor="2"
Width="100" Height="100"
Count="1" x:Name="tile">
</mah:Tile>
<TextBox Width="100" Height="100" Style="{StaticResource aaa}">Test</TextBox>
</StackPanel>
OK. So this is the MainWindow.xaml:
<mah:MetroWindow
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"
xmlns:local="clr-namespace:NQR_GUI_WPF"
xmlns:prop="clr-namespace:NQR_GUI_WPF.Properties"
xmlns:Custom="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="NQR_GUI_WPF.MainWindow"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
mc:Ignorable="d" Height="600" Width="800" ResizeMode="CanResizeWithGrip" WindowStartupLocation="CenterScreen" TitlebarHeight="28"
GlowBrush="{DynamicResource AccentColorBrush}" ShowIconOnTitleBar="False" Icon="Pictures/icon.ico"
>
<Window.Resources>
<local:ColorLightConverter x:Key="colorLightConverter" />
<Style x:Key="aaa" TargetType="{x:Type Control}">
<Setter Property="Background" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{Binding Path=Background.Color, Mode=OneTime, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Converter={StaticResource colorLightConverter}}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Background="DarkGoldenrod">
<mah:Tile Title="Hello!" Style="{StaticResource aaa}"
TiltFactor="2"
Width="100" Height="100"
Count="1" x:Name="tile">
</mah:Tile>
<TextBox Width="100" Height="100" Style="{StaticResource aaa}">Test</TextBox>
</StackPanel>
This is the App.xaml
<Application x:Class="NQR_GUI_WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NQR_GUI_WPF"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<BitmapImage x:Key="settingsIcon" UriSource="Pictures/settings1_unpressed.png" />
<ResourceDictionary.MergedDictionaries>
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<!-- Accent and AppTheme setting -->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
This is the color converter code:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Color color = (Color)value;
System.Drawing.Color darkColor = System.Windows.Forms.ControlPaint.Dark(System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B), 0.1f);
return System.Drawing.Color.FromArgb(darkColor.A, darkColor.R, darkColor.G, darkColor.B);
}
I am using MahApps 1.2.4.0.

Best practice to pipe WPF animation trigger from one ControlTemplate element to another

After reading several SO posts (here, here, and here) I still can't find any way to solve my problem... Basically, I redefined Button layout, and packed it up in a style. The new Button ControlTemplate contains a Rectangle I want to animate on Button click. Which TargetProperty do I have to use in my animation? Following is what I done :
UserControl x:Class="OfficeTourismeBrantome.Views.MainMenuView"
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"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="300">
<UserControl.Resources>
<Style x:Key="MenuItemButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="35" />
<Setter Property="FontFamily" Value="Segoe" />
<Setter Property="Foreground" Value="#FFEBEDEA" />
<!--<Setter Property="Height" Value="{Binding MenuLayout.MenuItemSize.Height}" />-->
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Canvas HorizontalAlignment="Stretch">
<ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Rectangle
Name="test"
Width="0"
Height="3"
Fill="Aqua"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
<!-- Which targetProperty should I use to animate ControlTemplate Rectangle ?-->
From="0.0"
To="10.0"
Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<ItemsControl Name="menuButtonContainer" ItemsSource="{Binding Items}" Margin="{Binding MenuLayout.MenuMargin}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ResourceKey=MenuItemButtonStyle}"
Margin="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemMargin}"
Height="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemSize.Height}"
Content="{Binding Text}"
Command="{Binding ElementName=menuButtonContainer,
Path=DataContext.ChangeThemeCommand}"
CommandParameter="{Binding Id}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I may be wrong in my implementation, still trying to understand WPF subtilities... What's the best way to achieve my goal?
Many thanks for your answers !
Which target property you want to animate is the question you have to ask yourself ! Do you want to change the rectangle's Width ? Its Opacity ? ...
Best practice... I don't know, but that's one way to do it :
<ControlTemplate TargetType="Button">
[...]
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard TargetName="test" TargetProperty="Width">
<DoubleAnimation From="0.0" To="10.0" Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>

WPF ListItem Template - Button to Fade In

I have a ListBox with an ItemTemplate (shown below) that when the mouse is over an item, a button is displayed that will fire a Delete Command.
This works, but what I'd like is for the button to "fade in" after the mouse has been over the listitem for a couple of seconds. How can I achieve this?
<ListBox.ItemTemplate>
<DataTemplate d:DesignSource="{d:DesignInstance quizCompanion:Question}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"></ColumnDefinition>
<ColumnDefinition Width="16"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Number}"></TextBlock>
<Button
Content="x" Grid.Column="1"
Command=MyDeleteCommand>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Hidden"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
Try using a DataTrigger with a RelativeSource for the Binding.
Here's a sample ... mouse over anywhere on the StackPanel for 2 seconds or more and the hidden button will fade in. It'll disappear when the mouse is moved off. Hopefully it'll work within your ListBox ItemTemplate:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel Height="100" Background="Yellow">
<TextBlock Text="Mouse over the yellow area to see the button"/>
<Button Width="250" Height="50" HorizontalAlignment="Left" Opacity="0">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="Fade">
<Storyboard>
<DoubleAnimationUsingKeyFrames Duration="0:0:3" Storyboard.TargetProperty="Opacity">
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="0"/>
<LinearDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="Fade"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
</Page>

ComboBox selection change breaks DataTrigger

I am trying to set the selected value of a combobox from a style trigger.It works as long as we dont manually change any value in the combobox.But it stops working altogether after manually changing the selection.How can i solve this.A sample code is attached.Please do help
<Window x:Class="InputGesture.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InputGesture"
Title="Window2" Height="300" Width="300" Name="Sample">
<Window.Resources>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ComboBox.SelectedValue" Value="1"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=chk,Path=IsChecked}" Value="True">
<Setter Property="ComboBox.IsEnabled" Value="False"/>
<Setter Property="ComboBox.SelectedValue" Value="2"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="chk" Height="23"/>
<ComboBox Name="cmb" Height="23" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=Sample,Path=DT}">
</ComboBox>
<Button Height="23" Click="Button_Click"/>
</StackPanel>
</Window>
I have found a Quick but Dirty Solutuin i guess..If anyone has a better Idea Please..
<Window x:Class="InputGesture.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InputGesture"
Title="Window2" Height="300" Width="300" Name="Sample">
<Window.Resources>
<Style TargetType="{x:Type ComboBox}">
<Style.Resources>
<Storyboard x:Key="valueStoryBoard" >
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
FillBehavior="HoldEnd"
Storyboard.TargetProperty="SelectedValue">
<DiscreteObjectKeyFrame KeyTime="00:00:00"
Value="{x:Null}" />
<!--<DiscreteObjectKeyFrame KeyTime="00:00:00"
Value="2" />-->
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</Style.Resources>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=chk}"
Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="stb" Storyboard="{StaticResource valueStoryBoard}" />
</DataTrigger.EnterActions>
<Setter Property="ComboBox.IsEnabled" Value="False"/>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="stb" />
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="chk" Height="23"/>
<ComboBox Name="cmb" Height="23" DisplayMemberPath="Name"
SelectedValuePath="Id" ItemsSource="{Binding ElementName=Sample,Path=DT}">
</ComboBox>
<Button Height="23" Click="Button_Click"/>
</StackPanel>
</Window>

Resources