How to make this style generic? - c#

I have the following DataGridCell style:
<Style TargetType="DataGridCell" x:Key="DateChangeAnimation" >
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Date.ValueChanged}" Value="True" />
<Condition Binding="{Binding Source={StaticResource BindProxy}, Path=Data.Columns.Date.NotifyChange}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation AutoReverse="True" From="#1F1F1F" To="#FFFF88" Duration="0:0:0.2" Storyboard.TargetProperty="Background.Color" FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
This style has the bindings set for one column cell, as I need to apply it to 20 or more columns, is there a way to define the style once in a generic manner and to instantiate it as many times as needed specifying only the variables to bind?

I'm not completely sure what you're asking, but if it's what I think it is then the short answer is No (maybe Yes).
I'm saying this because I think that you're looking to be able to somehow replace the BindingExpressions you wrote without a new style being created upon each variation.
So, why maybe Yes? Well, you could use a DynamicResource and programmatically create the styles, replacing the BindingExpressions where necessary.
As another alternative, you could create a custom control (or UserControl) that exposes dependency properties and then bind your variation of values to those properties, but that might not be worth the trouble.
Here's what I'm guessing you're trying to accomplish by using a simpler example.
<Style x:Key="MyDesiredGenericStyle" x:TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<Border ...>
<StackPanel>
<TextBlock Text="{Binding SomeGenericWay}" />
<ContentPresenter />
</StackPanel>
</Border>
</Setter.Value>
</Setter>
</Style>
vs.
<Style x:Key="MyDesiredStyleA" x:TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<Border ...>
<StackPanel>
<TextBlock Text="{Binding Path=PropA}" />
<ContentPresenter />
</StackPanel>
</Border>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MyDesiredStyleB" x:TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<Border ...>
<StackPanel>
<TextBlock Text="{Binding Path=PropB}" />
<ContentPresenter />
</StackPanel>
</Border>
</Setter.Value>
</Setter>
</Style>

Don't give it key so it will be set to all DataGridCell in the application by default.

Simple, remove the key:
<Style TargetType="DataGridCell">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Date.ValueChanged}" Value="True" />
<Condition Binding="{Binding Source={StaticResource BindProxy}, Path=Data.Columns.Date.NotifyChange}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation AutoReverse="True" From="#1F1F1F" To="#FFFF88" Duration="0:0:0.2" Storyboard.TargetProperty="Background.Color" FillBehavior="Stop" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>

Related

Can I somehow animate foreground color of textblock if foreground is binded to a property?

If I put Foreground="White" in XAML then the foreground animates ok.
But when I put Foreground="{Binding NumberForeground}" then I get: Cannot animate '(0).(1)' on an immutable object instance.
Here is the code:
<TextBlock Text="{Binding NumberText}" Foreground="{Binding NumberForeground}" Visibility="{Binding NumberVisibility}">
<TextBlock.Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource NumberTextBlockStyle}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding EndGame}" Value="True"/>
<Condition Binding="{Binding NumberSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard x:Name="animateNumberTextStoryboard" Storyboard="{StaticResource animateNumberText}" />
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<DataTrigger Binding="{Binding EndGame}" Value="False">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="animateNumberTextStoryboard"/>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding NumberSelected}" Value="False">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="animateNumberTextStoryboard"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
And the animation looks like this:
<Storyboard x:Key="animateNumberText">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(TextBox.Foreground).(SolidColorBrush.Color)"
Duration="0:0:0.45" RepeatBehavior="Forever">
<LinearColorKeyFrame Value="#FFFFCA00" KeyTime="0:0:0.15" />
<LinearColorKeyFrame Value="#FFFF2500" KeyTime="0:0:0.3" />
<LinearColorKeyFrame Value="#FFCEC100" KeyTime="0:0:0.45" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
Since you are animating on a control template, change the binding to a TemplateBinding. Those types of bindings are optimized for template scenarios and act as a one-way type binding.
Forground="{TemplateBinding NumberForeground}"
See TemplateBinding Markup Extension for more information.

Selecting ListBox items is not firing SelectionChanged event [duplicate]

I have added a DataTemplate to a ListBox class to bind my collection to:
<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276"
SelectionChanged="lstEmails_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Visibility="Hidden" Content="{Binding ID}"></Label>
<TextBox Width="200" Text="{Binding EmailAddress}"></TextBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This does exactly what I want it to do. Although when I click on the TextBox, the ListBox does not automatically set the associated ListItem as Selected. I could do this in code, but I would prefer to use this as a component (no surprises there then).
Any ideas on how to achieve this?
That doesn't seem to work, it won't let me click on anything. Have I missed something. Here is my new XAML.
<UserControl.Resources>
<!--<TextBox x:Key="TB" x:Name="TextBoxInsideListBoxItemTemplate">
<TextBox.Style>-->
<Style TargetType="{x:Type TextBox}">
<Setter Property="IsHitTestVisible" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
Value="True">
<Setter Property="IsHitTestVisible" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
<!--</TextBox.Style>
</TextBox>-->
</UserControl.Resources>
<Grid>
<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276" SelectionChanged="lstEmails_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<Label Visibility="Hidden" Content="{Binding ID}"></Label>-->
<TextBox Width="220" Text="{Binding EmailAddress}" >
</TextBox>
<!--<TextBox Width="220" Text="{Binding EmailAddress}" GotFocus="TextBox_GotFocus"></TextBox>-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Width="20" Margin="12,0,0,12" Name="btnAdd" VerticalAlignment="Bottom" Click="btnAdd_Click" Height="23" HorizontalAlignment="Left">+</Button>
<Button Width="20" HorizontalAlignment="Left" Margin="30,0,0,12" Name="btnRemove" VerticalAlignment="Bottom" Click="btnRemove_Click" Height="23">-</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" Name="btnApply" VerticalAlignment="Bottom" Width="49" Click="btnApply_Click">Apply</Button>
</Grid>
I think the click twice bit is good functionality.
You can trigger on the property IsKeyboardFocusWithin in the ItemContainerStyle and set IsSelected to true.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
You could also use a Setter instead of a single frame animation but then the selection will be lost again once the focus leaves the ListBox:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="IsSelected" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
If you have multiple instance of ListBox then you may consider using your custom listbox (by deriving it from ListBox). See the explanation here.
Or, use this hack if you have only 1 (or only small number of) such ListBox and don't want to create a separate class for that:
<TextBox x:Name="TextBoxInsideListBoxItemTemplate" ... >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="IsHitTestVisible" Value="False" />
<Style.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
Value="True">
<Setter Property="IsHitTestVisible" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Note that you'll have to click once again to edit text in the TextBox (which is actually cool according to me).
I had a situation where the selection of a listbox item would change its layout, so the control might have moved away from the cursor before the mouse button is released. I have found no better solution than to use a slight delay in the Storyboard if I want to keep everything in xaml.
More importantly, GotKeyboardFocus seems to work better than IsKeyboardFocusWithin for repeated selections.
<EventTrigger RoutedEvent="GotKeyboardFocus">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
<DiscreteBooleanKeyFrame KeyTime="00:00:00.3" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>

Why is my XAML throwing me a Storyboard object reference error?

So I am trying to create a animation that will run when I click my button.
It's supposed to move "Box" to the right.
However when i try to run the application I get this error.
System.Windows.Markup.XamlParseException: ''Set property
'System.Windows.ResourceDictionary.DeferrableContent' threw an
exception.' Line number '48' and line position '6'.'
Inner Exception InvalidOperationException: Must have a Storyboard
object reference before this trigger action can execute.
I am new to animations so I am not entierly sure why it's throwing that error.
I tried Googleing but I couldnt find any real solutions.
Seems as if it's a scope issue afaik.
Would it be better to create a resource file and use that?
I've heard of people doing so but I'm not sure how to do it.
XAML
<Window x:Class="WooImporter.MainWindow"
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:WooImporter"
mc:Ignorable="d"
Title="WooImporter" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.Resources>
<Storyboard x:Key="slideRight">
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="0" To="100"
Duration="0:0:0.3"/>
</Storyboard>
</Grid.Resources>
<Grid Column="0"
Background="#272727">
<StackPanel>
<ToggleButton Height="30"
Content="Add Products"
FontSize="18"
Foreground="White"
Style="{DynamicResource MenuToggleButtonStyle}"
x:Name="MenuButton1"/>
</StackPanel>
</Grid>
<Grid Column="1">
<StackPanel Width="100"
Height="100"
Background="#212121"
x:Name="Box"/>
</Grid>
</Grid>
<Window.Resources>
<Style TargetType="ToggleButton"
x:Key="MenuToggleButtonStyle">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Orange"></Setter>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=MenuButton1}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{DynamicResource slideRight}"/>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
</Window>
As I suspected it was a scope issue.
I moved the style inside the stackpanel
<Grid Column="1">
<StackPanel Width="100"
Height="100"
Background="#212121"
x:Name="Box">
<StackPanel.Style>
<Style TargetType="StackPanel">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=theMenuButton}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource slideRight}" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
</StackPanel>
</Grid>
Static Resource will do the trick but remember that Storyboard must be higher in resource hierarchy than StackPanel style. I mean you should move Storyboard to Window.Resources or StackPanel style to Grid.Resources. StoryBoard must be before StackPanel style. Then To StackPanel Style add RenderTransform Setter. In StoryBoard.TargetProperty you should add (TransformGroup.Children)[0] to show which element you want to transform in TransformGroup.
<Grid.Resources>
<Storyboard x:Key="slideRight">
<Storyboard>
<DoubleAnimation
AutoReverse="True"
RepeatBehavior="Forever"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(TranslateTransform.X)"
From="0"
To="1000"
Duration="0:0:0.3" />
</Storyboard>
</Storyboard>
<Style TargetType="StackPanel">
<Setter Property="Background" Value="Green" />
<Setter Property="RenderTransform">
<Setter.Value>
<TransformGroup>
<TranslateTransform X="0" Y="0" />
</TransformGroup>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=MenuButton1}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource slideRight}" />
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>

How to animate the width of an element multiple times in xaml?

I'm trying to add a Split View control on my WPF app that looks like the UWP one.
But when I click on the "Expand menu button"(the hamburger button) three times it just doesn't work anymore.
On the first click it expands to 358px. (Ok)
On the second click it returns to 48px (Ok)
On the third click it does nothing... it should expand the panel to 358px again but it doesn't.
I don't have any C# code behind, only this XAML code for the animation:
<Style TargetType="StackPanel" x:Key="expand">
<Style.Triggers>
<!--TO EXPAND-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu}" Value="True"/>
<Condition Binding="{Binding Width, ElementName=menuLateral}" Value="48"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="358" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<!--TO CLOSE-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu}" Value="True"/>
<Condition Binding="{Binding Width, ElementName=menuLateral}" Value="358"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="48" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
And here is the complete XAML code:
<Window x:Class="LojaDeEletronicos.MainWindow"
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:LojaDeEletronicos"
mc:Ignorable="d"
Title="MainWindow" Height="438" Width="640">
<Grid>
<Grid.Resources>
<Style TargetType="StackPanel" x:Key="expand">
<Style.Triggers>
<!--TO EXPAND-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu}" Value="True"/>
<Condition Binding="{Binding Width, ElementName=menuLateral}" Value="48"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="358" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<!--TO CLOSE-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu}" Value="True"/>
<Condition Binding="{Binding Width, ElementName=menuLateral}" Value="358"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="48" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="CleanButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="Black" BorderThickness="1">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="menuButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="#eee"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#ddd"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=btnHome3}" Value="True" >
<Setter Property="Background" Value="#ddd" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="menuButtonExpanded" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="0">
<ContentPresenter HorizontalAlignment="Left" Margin="20,0,0,0" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="#eee"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#ddd"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<!--START OF RELEVANT CONTENT-->
<StackPanel Name="menuLateral" Grid.Row="1" Grid.Column="0" Grid.RowSpan="2" Width="48" Grid.ColumnSpan="2" HorizontalAlignment="Left" Background="#eee" Style="{StaticResource expand}">
<!--#region Home Button -->
<Button Name="btnHome" HorizontalAlignment="Left" FontSize="21" Foreground="#333" Style="{StaticResource menuButton}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Width="48" Height="44" VerticalAlignment="Top" FontFamily="Segoe MDL2 Assets" Content=""/>
<!--#endregion-->
<Separator Width="30" Height="5" Margin="9,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<!--#region Products Button -->
<Button Name="btnProdutos" HorizontalAlignment="Left" Style="{StaticResource menuButton}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Width="48" Height="44" VerticalAlignment="Top">
<Image x:Name="product_icon_png" Tag="fdsf" Source="product_icon.png" RenderOptions.BitmapScalingMode="HighQuality" Width="25" Height="25" Stretch="Fill" />
</Button>
<!--#endregion-->
</StackPanel>
<Rectangle Grid.Column="1" Fill="#FF7B7BFF" Grid.Row="0" />
<Button Name="btnExpandirMenu" FontFamily="Segoe MDL2 Assets" Content="" FontSize="20" Foreground="White" Background="#333" Style="{StaticResource CleanButton}" Click="btnExpandirMenu_Click"/>
<StackPanel Name="MenuExpandido" Grid.Column="1" Background="#eee" Width="310" Visibility="Collapsed" Style="{StaticResource expand}" HorizontalAlignment="Left" Grid.Row="0" Grid.RowSpan="2">
<Button Name="btnHome3" Margin="0,48,0,0" Content="Página Inicial" Foreground="#444" FontSize="16" Style="{StaticResource menuButtonExpanded}" Height="44"/>
</StackPanel>
</Grid>
</Window>
Probably it really has to do something with some kind of floating precision.
The simplest fix i can imagine is the following:
<Style TargetType="StackPanel" x:Key="expand">
<Setter Property="Width" Value="48"></Setter>
<Style.Triggers>
<!--TO EXPAND-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu,PresentationTraceSources.TraceLevel=High}" Value="True" />
<Condition Binding="{Binding Width, ElementName=menuLateral,PresentationTraceSources.TraceLevel=High, UpdateSourceTrigger=PropertyChanged}" Value="48" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="OUT"/>
<BeginStoryboard Name="IN">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="358" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<!--TO CLOSE-->
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsPressed, ElementName=btnExpandirMenu}" Value="True"/>
<Condition Binding="{Binding ActualWidth, ElementName=menuLateral}" Value="358"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="IN"/>
<BeginStoryboard Name="OUT">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width" To="48" Duration="0:00:0.2"/>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
As you can see, i just named the StoryBoards and also used a StopStoryboard before starting the next one.
That should fix your issue.

Style BasedOn attribute failing at run-time

I have a custom button that derives from a Button control. This custom button's (GlyphButton) XAML page declares a style that specifies a control template as follows:
<Button x:Class="Foo.Presentation.Controls.GlyphButton">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_Border"
Padding="1"
Background="Transparent"
BorderThickness="0"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
BorderBrush="Transparent">
<local:VectorImage x:Name="PART_VectorImage"
Path="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GlyphButton}}, Path=Path}"
Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GlyphButton}}, Path=Fill}"
Stretch="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GlyphButton}}, Path=Stretch}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter TargetName="PART_VectorImage"
Property="Effect">
<Setter.Value>
<DropShadowEffect Color="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GlyphButton}}, Path=GlowColor, TargetNullValue='Black'}"
ShadowDepth="0"
BlurRadius="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:GlyphButton}}, Path=GlowRadius}"
Opacity="1.0" />
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
I use this control throughout my application. In one instance, I needed to add a context menu with custom styling to show the menu on a left mouse click so I came up with the following:
<controls:GlyphButton Height="24"
Width="24"
Path="{StaticResource HamburgerMenu4}"
Fill="{StaticResource BlueGradientBrush}">
<controls:GlyphButton.Style>
<Style TargetType="{x:Type controls:GlyphButton}" BasedOn="{StaticResource {x:Type controls:GlyphButton}}">
<Style.Triggers>
<EventTrigger RoutedEvent="Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
<DiscreteBooleanKeyFrame KeyTime="0:0:0"
Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</controls:GlyphButton.Style>
At runtime, I get an exception stating that the Xaml parser cannot find a style named 'GlyphButton' when I include the BasedOn attribute shown above. I've discovered a current workaround by declaring the template inline as opposed to using a style that removed the need to base the lowest level style on anything.
<GlypButton>
<GlyphButton.Template>
<!-- Template goes here -->
</GlyphButton.Template>
</GlypButton>
What am I missing here? Am I not following best practices by declaring the custom control's template through a style and if I am, why does this fail?

Categories

Resources