Using a Storyboard on a ToolTip WPF - c#

I am trying to create a storyboard, so when a user clicks on a textbox, its copies the text to their clipboard and shows a tooltip saying copied, which then fades away.
Here is my attempt:
xaml:
<TextBox Name="PolyValue" Text="{Binding .}" IsReadOnly="True" BorderThickness="0" Background="White"
VerticalAlignment="Center" PreviewMouseDown="CopyTextBox" >
<TextBox.ToolTip>
<ToolTip Style="{StaticResource TooltipPopupFadeAway}" IsOpen="True" Opacity="0" Background="Transparent" BorderThickness="0">
<Border Background="White" BorderBrush="Black" BorderThickness="1" CornerRadius="3" >
<Label Content="Copied" Padding="5, 2" />
</Border>
</ToolTip>
</TextBox.ToolTip>
</TextBox>
Here is the Storyboard:
<Style x:Key="TooltipPopupFadeAway" TargetType="ToolTip">
<Style.Triggers>
<DataTrigger Binding="{Binding Opacity, RelativeSource={RelativeSource Self}}" Value="1">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="ClosePopupStoryBoard">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="00:00:01" From="3" To="0" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
Code behind:
private void CopyTextBox(object sender, MouseButtonEventArgs e)
{
if(sender is TextBox textBox)
{
Clipboard.SetText(textBox.Text);
(textBox.ToolTip as ToolTip).IsOpen = false;
(textBox.ToolTip as ToolTip).IsOpen = true; //this recalculates the position
(textBox.ToolTip as ToolTip).Opacity = 1;
}
}
This works exactly how I want it to, however it only works once, after it has been shown and the user clicks again nothing happens.
After setting a break point in the CopyTextBox method, the of the ToolTip opacity is 0 even after programmatically setting it to 1.
I am not sure what I am doing wrong?

This is the sort of approach I mean.
Just binding the text property means you need no code.
I'm not sure this does exactly what you want because you seem to have previewmousedown showing the tooltip. Which is a bit odd for a tooltip since mouseover shows them.
<Window.Resources>
<ControlTemplate x:Key="TooltipPopupFadeAway" TargetType="ToolTip">
<Border Background="Yellow">
<TextBlock Text="{Binding PlacementTarget.Text, RelativeSource={RelativeSource AncestorType={x:Type ToolTip}}}"
Name="TheText"
/>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="ToolTip.Opened">
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="1.0" To="0" Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<TextBox>
<TextBox.ToolTip>
<ToolTip Template="{StaticResource TooltipPopupFadeAway}"/>
</TextBox.ToolTip>
</TextBox>
</Grid>
And you could set that template and tooltip etc via style if it suited you better. I used a yellow background so I can see it easy. The tooltip probably doesn't exactly match what you had.

You should trigger directly on the IsOpen property. Make sure to set the default Opacity to 0, and do not explicitly set it to 1 afterwards.
<Style x:Key="TooltipPopupFadeAway" TargetType="ToolTip">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Opacity" Value="0"/>
<Setter Property="IsOpen" Value="False"/>
<Style.Triggers>
<Trigger Property="IsOpen" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
Duration="0:0:1" From="3" To="0"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
In code behind, do not to set the Opacity:
private void CopyTextBox(object sender, MouseButtonEventArgs e)
{
if (sender is TextBox textBox)
{
Clipboard.SetText(textBox.Text);
((ToolTip)textBox.ToolTip).IsOpen = false;
((ToolTip)textBox.ToolTip).IsOpen = true;
}
}

Related

Storyboard label style how to apply background when datatrigger false?

I have a simple for with a set of labels on a grid, i have added a label style storyboard for flashing when NodeFlash is set to true and this works fine, however when NodeFlash set to false the label remains white background / white text and not the background color set in NodeStatus ( ie green, red etc ). where would i need to force the background color setting in the exit actions or else where?
heres the view.xaml
<Grid>
<ItemsControl ItemsSource = "{Binding Path = CIs}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Label
Content = "{Binding Path = NodeName, Mode = OneWay}"
Background = "{Binding Path = NodeStatus, Mode = OneWay}"
Tag="{Binding Path = Nodeid, Mode = OneWay}"
Foreground="White"
FontFamily="Arial Black"
HorizontalContentAlignment="Center"
BorderBrush="Black"
BorderThickness="1,1,1,1">
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Resources>
<Storyboard x:Key="flashAnimation" >
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" AutoReverse="True" Duration="0:0:0.5" RepeatBehavior="Forever" />
</Storyboard>
</Style.Resources>
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding NodeFlash}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<DataTrigger.EnterActions>
<BeginStoryboard Name="flash" Storyboard="{StaticResource flashAnimation}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="flash"/>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Thanks again
found it i think? i need to change this:
<Setter Property="Visibility" Value="Hidden" />
to
<Setter Property="Visibility" Value="Visible" />
think it was hiding all non styled labels?
Thanks

How can i make a custom made textbox appear when hovering over a button in wpf

I am trying to make something like this:
Basically, I made the email button, and I want to make a custom textbox with text in it that slowly fades in when the mouse enters the Email button.
Now, I made the custom box like this:
<Style x:Key="AppearingTextbox" TargetType="{x:Type TextBox}">
<Setter Property="Cursor" Value="Arrow"/>
<Setter Property="Foreground" Value="#3E82C4"/>
<Setter Property="Background" Value="#0F1C2B"/>
<Setter Property="Opacity" Value="0.4"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Path Data="M0 0 30 0 50 -15 70 0 100 0 100 30 0 30z" Fill="#0F1C2B"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And I am using it in the window like this:
<TextBox Style="{DynamicResource AppearingTextbox}" Height="30" Width="100" FontSize="14">
aaaaaaaaaa
</TextBox>
However, all I get is the box filled with this grayish/black color and when I try to write in it nothing happens. I am a bit new to all of this so not sure what I'm doing wrong.
Also how would i make it appear or disappear on hover of another button?
I was thinking maybe of making a on mouseover effect on the Email button and link it somehow to the TextBox opacity... don't know how to do it yet..
Any help or insight would be appreciated.
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Ikona, Path=IsMouseOver}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard >
<Storyboard TargetProperty="Opacity" Duration="00:00:00.3" AutoReverse="False">
<DoubleAnimation From="0" To="1" Duration="00:00:00.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard >
<Storyboard TargetProperty="Opacity" Duration="00:00:00.3" AutoReverse="False">
<DoubleAnimation From="1" To="0" Duration="00:00:00.3"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
By adding this below the last closing of <Setter> tag in above code I managed to get the fade in and fade out animation on hover over the button.
I still have the issue of nothing being writen in my custom made box. Do i need to enable or change some property to get it to work? I have a feeling that the "Fill" is the problem here..but do not know what to do about it.
This code will do what you want:
<Grid>
<Button Width="100" Height="50" VerticalAlignment="Top" x:Name="SomeButton"></Button>
<TextBox Width="200" Height="200" Background="Red" Opacity="0" Text="Some TextBox">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=SomeButton, Path=IsMouseOver}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard >
<Storyboard TargetProperty="Opacity" Duration="00:00:01" AutoReverse="True">
<DoubleAnimation From="0" To="1" Duration="00:00:01"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
The TextBox's Style simply says to watch for the Button's IsMouseOver property and when it is set to true to fade in in 1s. When the condition is false the TextBox fades out in 1s (AutoReverse="True")
Just another option to describe what I meant by tooltip, you could do something like this. Just thrown together quick in notepad so you'll probably want to tweak it if you decide to go this route.
<Button Content="Blah" HorizontalAlignment="Center" VerticalAlignment="Center" ToolTip="Blah Blah Blah" ToolTipService.Placement="Center">
<Button.Resources>
<Style TargetType="{x:Type ToolTip}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}">
<Grid Margin="0,60,0,0">
<Path Data="M0 0 30 0 50 -15 70 0 100 0 100 30 0 30z" Fill="#3E82C4" Stretch="Fill"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,8"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Resources>
</Button>

Wpf button with both result datatrigger storyboard and mouseover background

I'm looking to implement this functionality: A button, bound to a command, that can signal back wether the command was successful in form of a red or green flash. At the same time, I want the button to look like other buttons.
This is the code I have now:
<Button IsEnabled="{Binding EmptyingAllowed}" Content="Töm lista" Foreground="#555555" FontWeight="SemiBold" Height="20" Width="65" Command="{Binding EmptyListCommand}" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border BorderBrush="#BBBBBB" Padding="1" BorderThickness="0,0,1,1" Background="#DDDDDD">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ClearedOk}" Value="Ok">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation AccelerationRatio="0.2" DecelerationRatio="0.01" AutoReverse="True" Duration="0:0:1" To="LawnGreen" Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding ClearedOk}" Value="Error">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation AccelerationRatio="0.2" DecelerationRatio="0.01" AutoReverse="True" Duration="0:0:1" To="Red" Storyboard.TargetProperty="(Button.Background).(SolidColorBrush.Color)"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
When the command is executed, ClearedOk is set to "Ok" or "Error" and then to "Empty", this causes the flash I'm looking for, unfortunately, the usual mouseOver-effect is lost for some reason, and if I add a mouseOver-trigger, it always takes precedence over the flashing effect, meaning the flash is only visible of the button isn't mouseOver:ed.
Is there a solution to this?
Try to make datatemplate and model with properties of state and then binding in template to this properties.
<DataTemplate x:Key="DataTemplate">
<Grid >
<Ellipse Stroke="White"
StrokeThickness="5"
Fill="{Binding State, Converter={StaticResource CheckToColorConverter}}"/>
</Grid>
</DataTemplate>

In WPF, how to do when EventTrigger Source is outside a page's resources but Storyboard.TargetName is in a treeview datatemplate?

I have a TreeView whose <ItemTemplate> is defined in HierarchicalDataTemplate
<HierarchicalDataTemplate ItemsSource="{Binding}"
x:Key="TreeTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Name="TextBlockProperty" Text="{Binding Name}" Width="110" Foreground="#FF3C3C3C" >
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ModifyType}" Value="AutoDetect">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="LightGreen"></SolidColorBrush>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ModifyType}" Value="Prerequisite">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="LightSkyBlue"></SolidColorBrush>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ModifyType}" Value="AutoCheckFailed">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Red"></SolidColorBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ContentControl Name="ContentCtrl" Content="{Binding}">
</ContentControl>
</StackPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding ControlType}" Value="Text">
<Setter TargetName="ContentCtrl" Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBox Width="130" Text="{Binding Value}" BorderThickness="0" Background="#FFF8F8F8"></TextBox>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ControlType}" Value="Choice">
<Setter TargetName="ContentCtrl" Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<ComboBox Width="130" IsEditable="True" ItemsSource="{Binding ChoiceItems}" Text="{Binding Value}" BorderThickness="0" >
</ComboBox>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ControlType}" Value="Group">
<Setter TargetName="ContentCtrl" Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
I have also defined 2 <Buttons> ShowDefault and HideDefault outside the <Page.Resources> to shorten/widen the width of the TextBlockProperty <TextBlock> in the <HierarchicalDataTemplate> by using Storyboard. But I don't know how to do it.
Because it is a TreeView, the Items are actually several columns and rows, more like a form, binded in the <HierarchicalDataTemplate>. But the 2 Buttons are defined in a Grid outside the <Page.Resources>...In order to do the Width shortening/widening, I use Storyboard in <Page.Resources>.
<Storyboard x:Key="ShowDefault">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="GroupList">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="PropertyTree">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="270"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="DefaultTree">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="182"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="HideDefault">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="GroupList">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="152"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="PropertyTree">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="299"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="Width" Storyboard.TargetName="DefaultTree">
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
And call the Storyboard like this:
<Page.Triggers>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="ShowDefaultValue">
<BeginStoryboard Storyboard="{StaticResource ShowDefault}"/>
</EventTrigger>
<EventTrigger RoutedEvent="ButtonBase.Click" SourceName="HideDefaultValue">
<BeginStoryboard Storyboard="{StaticResource HideDefault}"/>
</EventTrigger>
</Page.Triggers>
A little complicated, but hope you get it right.
Any help or suggestions will be appreciated. :)
I'm not sure what are you trying to achieve, so I must guess what you meant :).
To get the reference to the TextBlock you can attached to its Loaded event like this:
<TextBlock Loaded="TextBoxLoaded"></TextBlock>
private TextBlock _textBlock;
private void TextBoxLoaded(object sender, RoutedEventArgs e)
{
_textBlock = sender as TextBlock;
}
and then when the button is clicked, changed the properties of the TextBlock.
Normally, the button should be in the template as well for each item of your child template.
OK, I eventually solve the problem by adding a <ScrollView> outside the <StackPanel> of two <TreeView>s. No need to change the DataBinding or anything else.

Reset the animation of user control when mouse leave

I want to display a user control on a rectangle with some animation when mouse move over the rectangle, reset the animation and collapse the user control when mouse leave.
My question is how should I "reset" the animation as my current approached is just collapses the user control when mouse leave. Below is my demo code.
EDITTED:
ControlLibrary.xaml
<UserControl.Style>
<Style>
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Name="opacityStoryBoard">
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="00:00:10" From="0" To="2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.MouseLeave">
<SeekStoryboard BeginStoryboardName="opacityStoryBoard" Offset="00:00:00"> </SeekStoryboard>
</EventTrigger>
<Trigger Property="FrameworkElement.Visibility" Value="Collapsed">
<Setter Property="FrameworkElement.Opacity" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Style>
<StackPanel Orientation="Vertical">
<Label Content="Welcome" HorizontalAlignment="Stretch" VerticalAlignment="Top"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Foreground="White" Background="Transparent" FontSize="25" Height="300" Margin="10,0" />
<!--<Image Height="300" x:Name="qr" Margin="10,0" />-->
</StackPanel>
mainWindow.xaml
<myToolTip:UserControl1 Visibility="Collapsed"
x:Name="customToolTip" />
<Rectangle Fill="Transparent" HorizontalAlignment="Left" Height="322" Stroke="Black"
VerticalAlignment="Top" Width="518" MouseMove="Rectangle_MouseMove_1" MouseLeave="Rectangle_MouseLeave_1">
</Rectangle>
mainWindow.cs
private void Rectangle_MouseMove_1(object sender, MouseEventArgs e)
{
customToolTip.Visibility = System.Windows.Visibility.Visible;
}
private void Rectangle_MouseLeave_1(object sender, MouseEventArgs e)
{
customToolTip.Visibility = System.Windows.Visibility.Collapsed;
}
Please guide me..Thank you.
Use the SeekStoryBoard class to reset the animation time when the mouse leaves the rectangle.
For example:
<Style.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Name="opacityStoryBoard">
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Opacity" Duration="00:00:10" From="0" To="2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="FrameworkElement.Visibility" Value="Collapsed">
<Setter Property="FrameworkElement.Opacity" Value="0"/>
<Trigger.EnterActions>
<SeekStoryboard BeginStoryboardName="opacityStoryBoard" Offset="00:00:00"></SeekStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>

Categories

Resources