I have an WPF tooltip defined within a dictionary.xaml that I want to apply to all my items, labels, buttons, etc. I import this dictionary in my view.
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="HorizontalOffset" Value="1" />
<Setter Property="VerticalOffset" Value="1" />
<Setter Property="Background" Value="White" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontFamily" Value="Segoe UI" />
<Setter Property="DataContext" Value="{Binding Path=PlacementTarget.DataContext, RelativeSource={x:Static RelativeSource.Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Canvas Width="225" Height="131">
<Path x:Name="Container"
Canvas.Left="0"
Canvas.Top="0"
Margin="0"
Data="M8,7.41 L15.415,0 L22.83,7.41 L224,7.41 L224,130 L0,130 L0,7.41 L8,7.41"
Fill="{TemplateBinding Background}"
Stroke="Gray">
<Path.Effect>
<DropShadowEffect BlurRadius="10"
Opacity="0.5"
ShadowDepth="4" />
</Path.Effect>
</Path>
<TextBlock Canvas.Left="10"
Canvas.Top="10"
Width="100"
Height="65"
Text="{TemplateBinding Content}"
TextWrapping="WrapWithOverflow" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
so I can use it as below:
<Label x:Name="myLabel"
ToolTip="This is a custom tooltip for my label."
ToolTipClosing="tt_ToolTipClosing"/>
also I have other items:
<Button x:Name="myBtn"
Tooltip="This is a custom tooltip for my button"
ToolTipClosing="tt_ToolTipClosing"/>
Tooltip is working fine, when I hover the mouse on it, the tooltip is shown.
Now I am trying to do below 2 things:
- Implement a tooltip closing event handler that works for all my items (labels, buttons, etc.)
- Keep the tooltip always opened until user clicks on anywhere in the screen with the mouse if a property keepOpened is set to true. Otherwise, if keepOpened is set to false, it behaves as a normal tooltip, it closes automatically when mouse leaves item.
In the code behind now I have below event handler (I have got this code from here):
private void tt_ToolTipClosing(object sender, ToolTipEventArgs e)
{
if (keepOpened)
{
// TODO: Determine who is the sender, a label, a button, etc.
// We suppose in this example it is a label
Label myLabel = sender as Label;
ToolTip tt = myLabel.ToolTip as ToolTip;
if (tt.PlacementTarget == null)
{
tt.PlacementTarget = myLabel;
}
tt.IsOpen = true;
}
}
For first point, I guess I need to use a switch to determine if sender is a button, label, etc. and then get the tooltip by casting it. I do not know if there are any other better way to do it. If so, please tell me.
For second point, KeepOpened would be a property defined in the view model, so I guess I need to use a command instead and move the above event to the view model, right? I know that I can use a popup instead but i don't want to use it as it is always on top of all desktop objects - even if you switch to another program, the popup will be visible and obscure part of the other program.
Also, now I have a problem in above event handler when casting to a Tooltip, tt is getting null. Why? I have set the datacontext in the style that is defined in the dictionary.xaml.
CodePudding user response:
If you want to apply this style as a generic style for multiple controls, you should remove the x:Key part which should be just a string anyway. Change this:
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
to:
<Style TargetType="{x:Type ToolTip}">
Also, I would get rid of that Canvas with fixed size. Use a Border and put a Grid inside of it where you put the Path and the TextBlock. Leave the tooltip size itself to the content. This Canvas Width="225" Height="131" doesn't look nice.
For point 2, to make the tooltip to not close automatically after 5 seconds, but only when the user moves the mouse pointer away from the control, you can add this in your code:
ToolTipService.ShowDurationProperty.OverrideMetadata(typeof(DependencyObject), new FrameworkPropertyMetadata(Int32.MaxValue));
Make sure you call this code only once, for example in App.xaml.cs.
Now your tooltips should stay open several weeks if the user keeps the mouse pointer over the control that displays the tooltip, allowing the user to read the content of it.
CodePudding user response:
I guess I need to use a switch to determine if sender is a button, label, etc. and then get the tooltip by casting it. I do not know if there are any other better way to do it. If so, please tell me.
You could cast the sender
argument to a FrameworkElement
and then access the ToolTip
property:
private void tt_ToolTipClosing(object sender, ToolTipEventArgs e)
{
FrameworkElement fe = (FrameworkElement)sender;
switch (fe.ToolTip)
{
case string s:
//do something with the string s
break;
case ToolTip tt:
//do something with the ToolTip tt
break;
}
}