WPF ToolTip disappears on mouse down - wpf

I've got tooltip on an element that I want to stay open even when the user clicks or holds the mouse button down while over my element.
Is there anyway to do this?

There is a StaysOpen tooltip property, but according to this book you are better off using a Popup control (just make it look like a tool tip).
Here is a quote from the book:
Has no effect in practice. The
intended purpose of this property is
to allow you to create a tooltip that
remains open until the user clicks
somewhere else. However, the
ToolTipService.ShowDuration property
overrides the StaysOpen property. As a
result, tooltips always disappear
after a configurable amount of time
(usually about 5 seconds) or when the
user moves the mouse away. If you want
to create a tooltip-like window that
stays open indefinitely, the easiest
approach is to use the Popup control.

The simplest way is to use Popup. Look to the code sample.
<!--Your ToolTip-->
<Popup x:Name="InfoPopup" PlacementTarget="{Binding ElementName=yourElement}" AllowsTransparency="True" StaysOpen="False" Placement="Mouse" PopupAnimation="Fade">
<Border BorderBrush="White" BorderThickness="1" Background="#FFFFFFFF" >
<Label Content="Your text here" />
</Border>
</Popup>
<!--Your element. Border, Button etc..-->
<Border x:Name="yourElement" Background="#FFFFFF" MinWidth="20" Height="20">
<Border.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseDown">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Duration="0:0:0:0" Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="InfoPopup">
<DiscreteBooleanKeyFrame Value="True"></DiscreteBooleanKeyFrame>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseUp">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Duration="0:0:0:0" Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="InfoPopup">
<DiscreteBooleanKeyFrame Value="False"></DiscreteBooleanKeyFrame>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
</Border>

Related

Adding content/text in rectangle WPF

This is my code for rectangle :
<Rectangle x:Name="rect1" Grid.Column="1" Fill="#FF5C626C" HorizontalAlignment="Left" Height="50" Margin="36,171,0,0" StrokeThickness="2" VerticalAlignment="Top" Width="358" RadiusX="30" RadiusY="50">
<Rectangle.Triggers>
</Rectangle.Triggers>
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF767C84" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Rectangle.MouseLeave">
<BeginStoryboard>
<Storyboard>
<ParallelTimeline >
<ColorAnimation Storyboard.TargetProperty="Fill.Color" To="#FF5C626C" />
</ParallelTimeline>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
My question is how do i add a text/content in the rectangle ?
One might suggest using a code block, but if u go through my code, youu'll notice that the rectangle changes it's color on mouseover.So if i put a textblock over the rectangle,the mouseover doesn't work properly(as the textblock covers the entire rectangle).
Another suggestion would be to use a border.But i am not sure about this as i need to find the code to apply mouse over effect on a border.
The next suggestion might be to use a button instead.I would've but my rectangle has corner radius and is a bit round-shaped which, if i use a button, would be hard to achieve.
So how do i add content/text inside the rectangle?
If you feel you definitely have to use a rectangle, put it in a grid and add a TextBlock element above it.
By setting the TextBlock's IsHitTestVisible property to False all hit-testing (mouse events) will be ignored on it and fall through to your rectangle.
<Grid>
<Rectangle (...your attributes here...)>
(...your rectangle code here...)
</Rectangle>
<TextBlock Text="Hello World!" IsHitTestVisible="False" />
</Grid>

Expander getting stuck after IsExpanded set to true by storyboard

So I have an expander that I want to have the normal functionality (open and close with its own button) but I also want a different button to expand it when pressed (this button is in the header of the expander). I'm using a storyboard in an event trigger for the Button.Click which works, but after it is expanded this way the normal button doesn't work, it just stays expanded. My xaml is below, I would really prefer to keep this all in the xaml, I could come up with a way to do it in the codebehind/viewmodel myself.
<Expander x:Name="IndexExpander" IsExpanded="True" Grid.Row="4" Grid.ColumnSpan="5" Margin="10" MaxHeight="150">
<Expander.Triggers>
<EventTrigger SourceName="btnAddIndex" RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="IndexExpander" Storyboard.TargetProperty="IsExpanded" BeginTime="0:0:0.25" Duration="0:0:0.20" >
<DiscreteBooleanKeyFrame KeyTime="0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Expander.Triggers>
<Expander.Header>
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
<TextBlock Text="Indexes" FontWeight="Bold"/>
<!-- Add/Delete Buttons-->
<Grid Margin="10,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50*"/>
<ColumnDefinition Width="50*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btnAddIndex" Command="{Binding AddIndexCommand}" Template="{StaticResource AddButtonTemplate}" IsEnabled="{Binding IsEditable}" Margin="0,0,5,0" />
</Grid>
</StackPanel>
</Expander.Header>
Alright, so for anyone following in my footsteps here's what I did. I got the idea from here, and adapted it until it worked correctly.
<Expander.Triggers>
<EventTrigger SourceName="btnAddCol" RoutedEvent="Button.Click">
<BeginStoryboard x:Name="ColumnExpanderStory">
<Storyboard>
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="ColumnExpander" Storyboard.TargetProperty="IsExpanded">
<DiscreteBooleanKeyFrame KeyTime="0" Value="True" />
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="ToggleButton.PreviewMouseUp">
<RemoveStoryboard BeginStoryboardName="ColumnExpanderStory" />
</EventTrigger>
</Expander.Triggers>
<Expander.Header>
The problem was that the storyboard overrides any other bindings to the IsExpanded property, so it has to be removed to restore them (read more here). The suggestion was to use the ToggleButton.Checked event to remove the storyboard, but that didn't work for me, only the "Preview" events seemed to have the right timing. I started with PreviewMouseDown, but it would remove the storyboard, then on mouse up toggle the expander, meaning the first click would just flip states back and forth quickly. Using PreviewMouseUp got around that issue.

Creating button content with centered text and animated border

The following XAML code creates a button with a border as its content. The border has a TextBlock as it's child. When you CLICK on the button, the border width gradually grows.
Since the text block is inside the border it is not seen until you click the button.
Now my requirements are:
There should be a text displayed on the button even before you click it.
Even after you click the button, only the border should animate while the button text remains in its center position.
<Button Name="button5" Width="100" Margin="10" HorizontalContentAlignment="Left">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="myBorder" Storyboard.TargetProperty="Width" From="0" To="94" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
<Button.Content>
<Border Background="Gray" Width="0" Name="myBorder">
<TextBlock>Search</TextBlock>
</Border>
</Button.Content>
</Button>
I will appreciate if anyone is able to provide answers with working XAML code.
I've modified your XAML only slightly:
<Button Name="button5" Width="100" Margin="10" HorizontalContentAlignment="Left">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="myRectangle" Storyboard.TargetProperty="Width" From="0" To="94" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
<Button.Content>
<Grid>
<Rectangle x:Name="myRectangle" Fill="Gray" Width="0" HorizontalAlignment="Left" />
<TextBlock Text="Search" />
</Grid>
</Button.Content>
</Button>
For the Button's content, you could use a Grid which contains your Border and the TextBlock. Since no columns or rows are specified, the TextBlock and the Border are drawn on top of each other. It situations like this where the Border does not have content, I prefer to use a Rectangle instead since it is bit lighter. Hope this helps!

Scale transform in xaml (in a controltemplate) on a button to perform a "zoom"

I've got a button with an image in it and it's being styled by the following:
<ControlTemplate x:Key="IconButton" TargetType="Button">
<Border>
<ContentPresenter Height="80" Width="80" />
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="1" To="0.5" Duration="0:0:0.5" />
<DoubleAnimation From="0.5" To="1" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard TargetProperty="Width">
<DoubleAnimation From="80" To="95" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Button is as follows:
<Button Template="{StaticResource IconButton}" Name="btnExit">
<Image Source="Images/Exit.png" />
</Button>
The problem is that the width doesn't change when my mouse goes over. (Or at least - the width of the image does not...)
I believe there is a "scale" transform I can use to enlarge the button and all it's contents? how would I do that here...?
Thanks.
Your template seems to be pretty minimal but I'm assuming your only just getting started on it, however this will help you get started with using a ScaleTransform as opposed to animating the width.
The ScaleTransform can be applied to the RenderTransform property of either the Button itself or just the Border of your template. This could be a TransformGroup if you want to do more than just Scale (i.e. a composite transform consisting of other tranforms such as Translate, Rotate, Skew) but to keep it simple and for examples sake something like the following applies a single ScaleTransform value to the Button:
<Button Template="{StaticResource IconButton}" Name="btnExit">
<Button.RenderTransform>
<ScaleTransform ScaleX="1.0" ScaleY="1.0"></ScaleTransform>
</Button.RenderTransform>
<Image Source="Images/Exit.png" />
</Button>
or this to apply to the Border of the ControlTemplate:
<ControlTemplate x:Key="IconButton" TargetType="Button">
<Border Background="Blue" x:Name="render">
<Border.RenderTransform>
<ScaleTransform ScaleX="1.0" ScaleY="1.0"></ScaleTransform>
</Border.RenderTransform>
<ContentPresenter Height="80" Width="80" />
</Border>
...
...
Next you will want to change your MouseEnter trigger to target that property and for width you will want to target the ScaleX property of the ScaleTransform. The following Storyboard will scale the Button 2.5 times in the X direction (add TargetName="render" to <Storyboard... if you have chosen to apply the Transform to the Border as opposed to the Button).
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<BeginStoryboard>
<Storyboard TargetProperty="RenderTransform.ScaleX">
<DoubleAnimation To="2.5" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
If you were to use a TransformGroup with a number of transforms you would change the TargetProperty value to something like RenderTransform.(TransformGroup.Children)[0].ScaleX assuming the ScaleTransform is the first child of the group.
This should get you up and running with what you need and you can take it where you want from there...
HTH

Validation adorner does not completely disappear in Animation

I have a WPF Window that contains a ContentPresenter that has Height and Width set to 0 by default.
When a user clicks a button, I run an animation to transform the ContentPresenter's Height and Width properties to 896,1024 (actually it does 3 rotations whilst its growing, too) and this is all good...
The DataContext for the User control implements IDataErrorInfo and if the user does not click the 'I have read and understand these Health & Safety instructions" checkbox, then a red border is shown around the checkbox...
My problem is that if the user clicks 'Cancel', and I run the animation that shrinks the Height & Width back down to 0,0, then the UserControl shrinks as required, but the red border does not completely disappear - it leaves a single red pixel in the middle of my Window
Anybody any ideas what I'm doing wrong? The 'red-border', I'm assuming is just an Adorner being rendered by WPF for me, so I'm not sure how to change this behaviour...
All help much appreciated!
Update - I tried Abe's excellent suggestion, but unfortunately it didn't work, but it did get me trying other stuff... So now I have (temporarily) commented out the 'shrinking' animations, and simply set the visibility to Collapsed at KeyTime="0:0:0.9"... when I press cancel, just less than a second later, the UserControl disappears but the red adorner stubbornly remains :(
As an extra bit of info (not sure if relevant?) the UserControl being shown in the ContentPresenter also contains a ContentPresenter to render a UserControl, and its the inner content that contains the validation adorner...
code sample:
<Button
Name="signInButton"
Grid.Row="0" Grid.Column="0"
Margin="30"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Style="{StaticResource LargeButtonStyle}"
Content="Sign In"
Command="{Binding SignInCommand}">
<Button.Triggers>
<EventTrigger
RoutedEvent="Button.Click">
<BeginStoryboard
Storyboard="{DynamicResource openViewAnimation}" />
</EventTrigger>
</Button.Triggers>
</Button>
<ContentPresenter
Name="mainView"
Grid.RowSpan="2" Grid.ColumnSpan="2"
HorizontalAlignment="Center" VerticalAlignment="Center"
Opacity="0.9"
Content="{Binding CurrentContent}">
<ContentPresenter.RenderTransform>
<RotateTransform
Angle="0" />
</ContentPresenter.RenderTransform>
</ContentPresenter>
<Storyboard x:Key="closeViewAnimation">
<DoubleAnimation
Storyboard.TargetName="mainView" Storyboard.TargetProperty="Height"
From="896" To="0" Duration="0:0:0.9"
AutoReverse="False" RepeatBehavior="1x" />
<DoubleAnimation
Storyboard.TargetName="mainView" Storyboard.TargetProperty="Width"
From="1024" To="0" Duration="0:0:0.9"
AutoReverse="False" RepeatBehavior="1x" />
</Storyboard>
Thanks, Ian
If you add an ObjectAnimationUsingKeyFrames that sets the Visibility of the element to Collapsed at the time that the other animations complete, the adorner will go away also.
<Storyboard x:Key="closeViewAnimation">
<DoubleAnimation
Storyboard.TargetName="mainView" Storyboard.TargetProperty="Height"
From="896" To="0" Duration="0:0:0.9"
AutoReverse="False" RepeatBehavior="1x" />
<DoubleAnimation
Storyboard.TargetName="mainView" Storyboard.TargetProperty="Width"
From="1024" To="0" Duration="0:0:0.9"
AutoReverse="False" RepeatBehavior="1x" />
<ObjectAnimationUsingKeyFrames
Storyboard.TargetName="mainView"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}"
KeyTime="0:0:0.9" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
Obviously, you would need to do the reverse operation at KeyTime 0 for the openViewAnimation.

Resources