I'm trying to make VisualBrush that automatically fades in/out when set, but unfortunately it doesn't work as it should. Instead of actually fading it disappears or appears right away totally ignoring storyboard - or I'm trying to catch wrong event.
<VisualBrush x:Key="CustomHatchBrush" TileMode="None" Viewport="0,0,100,100" ViewportUnits="Absolute" Viewbox="0,0,100,100" ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Canvas>
<Canvas.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" From="0" To="1" Storyboard.TargetProperty="(Canvas.Opacity)" RepeatBehavior="1x" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" From="1" To="0" Storyboard.TargetProperty="(Canvas.Opacity)" RepeatBehavior="1x" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Rectangle Canvas.Top="0" Canvas.Left="0" Width="100" Height="100" Fill="Orange" />
<Rectangle Canvas.Top="0" Canvas.Left="0" Width="100" Height="100" Fill="{DynamicResource CaretBrush}" />
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
I generally want to use it inside Template of ListBoxItem as BorderBrush, something like that:
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="ca" BorderThickness="3" SnapsToDevicePixels="true" Padding="0">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="4" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="true" Padding="0">
<ContentPresenter HorizontalAlignment="Stretch" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Border>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Prop1}" Value="true"/>
<Condition Binding="{Binding Prop2}" Value="true"/>
</MultiDataTrigger.Conditions>
<Setter Property="BorderBrush" TargetName="ca" Value="{DynamicResource CustomHatchBrush}"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Prop1}" Value="true"/>
<Condition Binding="{Binding Prop2}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="BorderBrush" TargetName="ca" Value="{DynamicResource CustomHatchBrush2}"/>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Prop1}" Value="false">
<Setter Property="BorderBrush" TargetName="ca" Value="Transparent"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I tried many ways of applying storyboard, for example inside bindings, but it always finishes instantly completely ignoring Storyboard duration.
What am I missing? This control works fine in general (objects have name and have multiple instances, so something could go wrong), I just can't create visual effect that I would want to achieve.
Related
How can I change Fill color of Ellipse when mouse is over another Ellipse?
I want to change the color of "inner" Ellipse when mouse is over "outer" Ellipse. What is the way yo achieve this behavior?
<Canvas
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="50" Height="50">
<Ellipse x:Name="inner" Width="50"
Height="50"
Fill="White"
Canvas.ZIndex="0"
HorizontalAlignment="Center"
VerticalAlignment="Center" Stroke="Black">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="Black" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="0" Value="White" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse x:Name="outter" Width="44"
Height="44"
Fill="Blue"
Canvas.ZIndex="1"
Canvas.Left="3"
Canvas.Top="3">
</Ellipse>
</Canvas>
You may use a DataTrigger with a Binding to the IsMouseOver property of the other Ellipse:
<Canvas>
<Ellipse Width="50" Height="50">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="White"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, ElementName=outer}"
Value="True">
<Setter Property="Fill" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Ellipse x:Name="outer" Canvas.Left="3" Canvas.Top="3"
Width="44" Height="44" Fill="Blue"/>
</Canvas>
I'm setting extra ToolTip for a field with errors in ResourceDictionary
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
I also defined special style for this tooltip, which simulate the one on red triangle in right upper corner
<Style TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="HasDropShadow" Value="True"/>
<Setter Property="Placement" Value="Right"/>
<Setter Property="HorizontalOffset" Value="5"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Border Name="Border"
Background="Red"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<ContentPresenter Margin="5 2 5 3"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Everything works, but now ALL ToolTips have this style.
Is it possible to achieve that ToolTip style take his part only if Validation.HasError occurs? I can as x:Key, but how to apply that to Style.Triggers part?
Because I have this ToolTip defined also on other controls I wouldn't like to copy all this code multiple times, but if only that is a solution I will do so :(
After another couple of hours of Googling I try the solution provided here
https://social.msdn.microsoft.com/Forums/vstudio/en-US/10d2ecbf-9e6e-4414-b57e-79dd02e0944e/changing-style-of-tooltip-in-textbox
and it works!
A created ToolTip style
<ToolTip x:Key="ErrorToolTip"
Placement="Right"
Background="Red"
Foreground="White"
BorderThickness="0"
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
<ToolTip.Content>
<Binding Path="(Validation.Errors)[0].ErrorContent"/>
</ToolTip.Content>
<ToolTip.Triggers>
<EventTrigger RoutedEvent="ToolTip.Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ToolTip.Triggers>
</ToolTip>
and changed Style.Triggers to
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{StaticResource ErrorToolTip}" />
</Trigger>
</Style.Triggers>
Need to do some more styling, but it's OK for now.
You can set the property Validation.ErrorTemplate on the TextBox style:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Validation.ErrorTemplate"
Value="{StaticResource ValidationTemplate}" />
<Style.Triggers>
<Trigger Property="Validation.HasError"
Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
However, this way you can't work with a ToolTip style, but you have to work with a template and a x:Key.
<ControlTemplate x:Key="ValidationTemplate">
<Border Name="Border"
Background="Red"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<ContentPresenter Margin="5 2 5 3"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Opened">
<BeginStoryboard>
<Storyboard TargetProperty="HorizontalOffset">
<DoubleAnimation From="0" To="5" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I have been for 2 days now trying to develop my own WPF textbox for no avail.
My initial try was inheriting from a control and then adding a template with all the stuff I wanted (a border and an asterisk in the outside).
Generic.xaml file:
<Style TargetType="{x:Type local:BdlTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BdlTextBox">
<Grid x:Name="ContentGrid">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="Tbl" Text="*" Foreground="Red" FontSize="15" Margin="0,-4,0,0"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:BdlTextBox}},
Path=IsRequired, Converter={StaticResource myBoolToVisibilityConverter}}"/>
<Rectangle Grid.Column="1" x:Name="Bg" Fill="Red" Opacity="0"/>
<TextBox Grid.Column="1" x:Name="Tb" Margin="1,1,1,1"/>
</Grid>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="flashAnimation">
<DoubleAnimation Storyboard.TargetName="Bg" Storyboard.TargetProperty="Opacity" From="0" To="1" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="2x" />
<DoubleAnimation Storyboard.TargetName="Bg" Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:0.5" BeginTime="0:0:2"/>
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=HasValidationError}" Value="True" >
<DataTrigger.EnterActions>
<BeginStoryboard Name="flash" Storyboard="{StaticResource flashAnimation}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="flash"/>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=HasValidationError}" Value="False" >
<Setter TargetName="Bg" Property="Opacity" Value="0"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The problem is: I cannot use the control as a Textbox (the reason is obvious). I can't even properly use the Text property. So I was wondering what could be done to solve this problem.
Dependency Properties are also a problem. I have tried to "clone" the Text property from the Textbox "Tb", but failed too.
I'm trying to bind to a property from my control style to a property defined in the control. The control inherits from TextBox and is called ChangeTextBoxWithRangeUnits. I'm trying to bind to them from a ValidationRule class that I created. Here is the Setter for where I'm trying to validate the text
<Setter Property="Text">
<Setter.Value>
<Binding RelativeSource="{RelativeSource Self}"
Path="Text"
NotifyOnValidationError="True">
<Binding.ValidationRules>
<basic:DoubleValidationRule>
<basic:DoubleValidationRule.MinMaxDependencyObject>
<basic:MinMaxDependencyObject Minimum="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithRangeUnits}}, Path=MinimumValue}"
Maximum="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithRangeUnits}}, Path=MaximumValue}" />
</basic:DoubleValidationRule.MinMaxDependencyObject>
</basic:DoubleValidationRule>
</Binding.ValidationRules>
</Binding>
</Setter.Value>
</Setter>
I don't understand why it says that the source binding cannot be found. Here is the error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Frasca.Simplicity.Controls.UnitControls.ChangeTextBoxWithRangeUnits', AncestorLevel='1''. BindingExpression:Path=MinimumValue; DataItem=null; target element is 'MinMaxDependencyObject' (HashCode=16320155); target property is 'Minimum' (type 'Double')
EDIT Complete XAML
<Style x:Key="ChangeTextBoxWithRangeUnits"
TargetType="{x:Type local:ChangeTextBoxWithRangeUnits}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate"
Value="{x:Null}" />
<Setter Property="Height"
Value="64" />
<Setter Property="FontSize"
Value="22" />
<Setter Property="Margin"
Value="5" />
<Setter Property="Background"
Value="LightGray" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter Property="AllowDrop"
Value="true" />
<Setter Property="ScrollViewer.PanningMode"
Value="VerticalFirst" />
<Setter Property="Stylus.IsFlicksEnabled"
Value="False" />
<Setter Property="Text">
<Setter.Value>
<Binding RelativeSource="{RelativeSource Self}"
Path="Text"
NotifyOnValidationError="True">
<Binding.ValidationRules>
<basic:DoubleValidationRule>
<basic:DoubleValidationRule.MinMaxDependencyObject>
<basic:MinMaxDependencyObject Minimum="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithRangeUnits}}, Path=MinimumValue}"
Maximum="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithRangeUnits}}, Path=MaximumValue}" />
</basic:DoubleValidationRule.MinMaxDependencyObject>
</basic:DoubleValidationRule>
</Binding.ValidationRules>
</Binding>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ChangeTextBoxWithUnits}">
<Grid>
<Border Name="bg"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Width="{TemplateBinding Width}"
CornerRadius="15"
SnapsToDevicePixels="true">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal"
Grid.Row="0"
Name="mValueStackPanel"
VerticalAlignment="Bottom"
HorizontalAlignment="Center">
<ScrollViewer x:Name="PART_ContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<TextBox Name="PART_UnitTextBlock"
Style="{DynamicResource InlineTextBox}"
Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithUnits}}, Path=Units}"
FontSize="14"
Margin="3,0,0,0"
Foreground="{TemplateBinding Foreground}" />
</StackPanel>
<StackPanel Orientation="Horizontal"
Grid.Row="2"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithUnits}}, Path=Label}"
FontSize="14"
Foreground="{TemplateBinding Foreground}" />
</StackPanel>
<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ChangeTextBoxWithUnits}}, Path=DisabledText}"
Foreground="{TemplateBinding Foreground}"
Grid.Row="0"
FontSize="14"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Visibility="Collapsed"
x:Name="mDisabledTextBlock" />
<!-- Horizontal line -->
<Rectangle Height="1"
Margin="10,0"
Grid.Row="1"
Opacity="0.15"
SnapsToDevicePixels="True"
Fill="{TemplateBinding Foreground}" />
<!-- Object which flashes when the textbox is selected -->
<Border Grid.RowSpan="3"
Background="White"
Name="FlashObject"
CornerRadius="15"
Opacity="0">
<Border.Effect>
<BlurEffect Radius="20" />
</Border.Effect>
</Border>
<!-- Object which flashes when the textbox has a validation error-->
<Border Grid.RowSpan="3"
Grid.ColumnSpan="2"
Background="Red"
Name="ErrorFlashObject"
CornerRadius="15"
Opacity="0">
<Border.Effect>
<BlurEffect Radius="20" />
</Border.Effect>
</Border>
</Grid>
</Border>
<!-- Object which glows when the user makes a change to the text value. -->
<Border Width="{Binding ElementName=bg, Path=ActualWidth}"
Height="{Binding ElementName=bg, Path=ActualHeight}"
CornerRadius="15"
Background="#FFF066"
Name="ChangeGlowObject"
Panel.ZIndex="-1"
Visibility="Collapsed">
<Border.Effect>
<BlurEffect Radius="20" />
</Border.Effect>
</Border>
</Grid>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasChangedValue"
Value="True" />
<Condition Property="IsEnabled"
Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Visibility"
TargetName="ChangeGlowObject"
Value="Visible" />
</MultiTrigger>
<Trigger Property="IsEnabled"
Value="False">
<Setter Property="Background"
Value="#686868" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsEnabled"
Value="False" />
<!--<Condition Property="ShowTextWhenDisabled"
Value="False" />-->
</MultiTrigger.Conditions>
<Setter Property="Visibility"
TargetName="mDisabledTextBlock"
Value="Visible" />
<Setter Property="Visibility"
TargetName="mValueStackPanel"
Value="Collapsed" />
</MultiTrigger>
<!-- trigger to flash the object when the textbox has an error -->
<Trigger Property="Validation.HasError"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.2"
From="0"
To="1"
Storyboard.TargetName="ErrorFlashObject"
Storyboard.TargetProperty="Opacity">
<DoubleAnimation.EasingFunction>
<PowerEase Power="2"
EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation BeginTime="00:00:00.2"
Duration="00:00:00.5"
From="1"
To="0"
Storyboard.TargetName="ErrorFlashObject"
Storyboard.TargetProperty="Opacity">
<DoubleAnimation.EasingFunction>
<PowerEase Power="2"
EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
<!-- trigger to flash the object when the textbox is selected -->
<EventTrigger RoutedEvent="FocusManager.GotFocus">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation BeginTime="00:00:00"
Duration="00:00:00.2"
From="0"
To="1"
Storyboard.TargetName="FlashObject"
Storyboard.TargetProperty="Opacity">
<DoubleAnimation.EasingFunction>
<PowerEase Power="2"
EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation BeginTime="00:00:00.2"
Duration="00:00:00.5"
From="1"
To="0"
Storyboard.TargetName="FlashObject"
Storyboard.TargetProperty="Opacity">
<DoubleAnimation.EasingFunction>
<PowerEase Power="2"
EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
RelativeSource bindings don't walk up your XML, they walk up the Visual Tree. That means you can only use it whenever the element you are binding is within that tree.
In this case, your DoubleValidationRule is not a UIElement, and it is not in the visual tree, so RelativeSouce bindings on this rule will fail.
Unfortunately, without knowing the implementation or purpose of your DoubleValidationRule.MinMaxDependencyObject, its hard to say what you should do. You might be able to get around this limitation by altering the implementation of the validation rule.
One way that will work is that you can refer to an element in the tree by its x:Name value
Minimum="{Binding MinimumValue, ElementName=TheMinimumTarget}
But that probably means you can't do this using a Style, as each use will (probably) be bound to a different element on your form.
Looking at your edit... Wat? You're binding the text of the control to the text of the control in order to attach a validation rule? That's... I don't even.
I'd suggest subclassing the control in order to add validation logic (e.g., override the property metadata for the Text dependency property), and then apply your template to this new type.
I'm new to WPF, and I would like to know how to reuse some annoying xaml I have to avoid duplicating.
<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi!" Focusable="False" IsTabStop="False"/>
<Button Cursor="Hand" HorizontalAlignment="Left" Margin="0,0,0,0" x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Width="286" Content="hi 2!" Focusable="False" IsTabStop="False"/>
I'd really like to use something like this template:
<Style TargetType="{x:Type Button}" x:Key="ButtonTemplate">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="btGrid">
<Path Cursor="Hand" HorizontalAlignment="Left" Stretch="Fill" Stroke="{x:Null}" Opacity="0" x:Name="path"/>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True" Visibility="Hidden" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top"/>
</Grid>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonDown">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard SlipBehavior="Slip" BeginTime="00:00:00">
<MediaTimeline Source="{Binding StringFormat={}, Path=Name}" Storyboard.TargetName="{Binding StringFormat={}_wma, Path=Name}"/>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>
Visible
</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.PreviewMouseLeftButtonUp">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="{Binding StringFormat=key{}, Path=Name}" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>
Hidden
</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<Trigger Property="IsFocused" Value="True"/>
<Trigger Property="IsDefaulted" Value="True"/>
<Trigger Property="IsMouseOver" Value="True"/>
<Trigger Property="IsPressed" Value="True"/>
<Trigger Property="IsEnabled" Value="False"/>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I'd like the {Binding StringFormat={}, Path=Name} to point button's name, e.g. "MyButton", "MyButton2", etc.
When I run this code I get the error "Cannot freeze this Storyboard timeline tree for use across threads." :/ I understand this is because I use binding in a storyboard, correct? I don't know what to do to make this work.
Also, I'd like to make the ToggleVisibility of the image a template as well, that accepts once "Visible" and once "Hidden" values.
Thanks in advance!
You could always define properties other than Template in your style too.
<Style TargetType="{x:Type Button}"
x:Key="ButtonTemplate">
<Setter Property="Cursor" Value="Hand" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Width" Value="286" />
<Setter Property="Focusable" Value="False" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Which makes your code look like
<Button x:Name="MyButton" Style="{StaticResource ButtonTemplate}" Content="hi!" />
<Button x:Name="MyButton2" Style="{StaticResource ButtonTemplate}" Content="hi 2!" />
Yeah creating a style with target type to as button would do the trick.
Tip:It is always a good practice to write all the styling informations such as border, background, templates, etc., under the resource section of your code and apply them on the controls. It'll give good readability.
HTH :)