Reputation: 599
As this MSDN page suggests you should be able to use data binding to set a placement target on a tooltip.
In my UWP app I have the following XAML and code behind:
<Button x:Name="MyButton">
<ToolTipService.ToolTip>
<ToolTip PlacementTarget="{Binding ElementName=MyButton}"
Loaded="FunkyMethod">
<Border Width="150"
Height="50"
CornerRadius="10"
Background="DeepSkyBlue">
<TextBlock Text="This is a tooltip"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="White"/>
</Border>
</ToolTip>
</ToolTipService.ToolTip>
<Button.Content>Button with ToolTip</Button.Content>
</Button>
private void FunkyMethod(object sender, RoutedEventArgs e)
{
var tooltip = sender as ToolTip;
var button = tooltip?.PlacementTarget as Button; // always returns NULL for the placement target
if (tooltip != null && button != null)
{
// do something funcky here.
}
}
But the placement target never gets set and I always get NULL. Does anyone know why?
For context, I am trying to write code that would compute the horizontal/vertical offset needed to place a tooltip to the right of its parent and vertically centered. Something like this:
But I haven't been able to find a way of achieving this (Placement=Right or Top didn't work). So What I'm trying to do is to do it in code behind at runtime, by a) set Placement=Mouse, b) figure out the parent control via PlacementTarget, c) find out the mouse position relative to the parent control, d) compute the horizontal/vertical offset and set it for the tooltip
Upvotes: 1
Views: 1272
Reputation: 599
So I still haven't heard back from Microsoft on this. As Justin XL pointed out x:Bind would work cleanly in some scenarios. But I was able to find a workaround that works for my scenarios. Here are the snippets:
<Style x:Key="ToolTipStyle1"
TargetType="ToolTip">
<Setter Property="Placement"
Value="Mouse" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Grid x:Name="LayoutRoot"
MaxWidth="300"
MinHeight="36"
MaxHeight="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Polygon Fill="#FF1589EE"
Width="10"
Height="12"
VerticalAlignment="Center"
Points="0,6 10,0 10,12" />
<Border Grid.Column="1"
Background="#FF1589EE">
<TextBlock Margin="20,5,5,5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="White"
FontSize="16"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
Text="{TemplateBinding Content}" />
</Border>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="OpenStates">
<VisualState x:Name="Closed">
<Storyboard>
<FadeOutThemeAnimation TargetName="LayoutRoot" />
</Storyboard>
</VisualState>
<VisualState x:Name="Opened">
<Storyboard>
<FadeInThemeAnimation TargetName="LayoutRoot" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Width="150"
Height="100"
PointerMoved="MyButton_OnPointerMoved"
PointerExited="MyButton_OnPointerExited"
Content="Parent Control">
<ToolTipService.ToolTip>
<ToolTip Loaded="MyToolTip_OnLoaded"
Style="{StaticResource ToolTipStyle1}"
Content="This is a tooltip" />
</ToolTipService.ToolTip>
</Button>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private PointerPoint _devicePointer;
private FrameworkElement _elementContainingDevicePointer;
private void MyButton_OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
_elementContainingDevicePointer = sender as FrameworkElement;
_devicePointer = e.GetCurrentPoint(_elementContainingDevicePointer);
}
private void MyButton_OnPointerExited(object sender, PointerRoutedEventArgs e)
{
_devicePointer = null;
_elementContainingDevicePointer = null;
}
private void MyToolTip_OnLoaded(object sender, RoutedEventArgs e)
{
var tooltip = sender as ToolTip;
if (_devicePointer != null && _elementContainingDevicePointer != null && tooltip != null)
{
var x = _elementContainingDevicePointer.ActualWidth - Math.Max(0, _devicePointer.Position.X);
var y = _elementContainingDevicePointer.ActualHeight / 2 - Math.Max(0, _devicePointer.Position.Y) - tooltip.ActualHeight / 2;
tooltip.HorizontalOffset = x + 5;
tooltip.VerticalOffset = y - 10;
}
}
}
Upvotes: 0
Reputation: 39006
Try changing the traditional binding to PlacementTarget="{x:Bind MyButton}"
. Note the default Mode
of this is OneTime
but I think it's OK for your case.
Upvotes: 2