Reputation: 11
This has been marked as a duplicate of this question, which solves a different problem and does not mention anywhere how to solve the Binding problems I had. They were trying to bind ToolTip to another element's value, I was binding it to a public Property declared in the code-behind. In my case it's sufficient to set just the Binding Path, without PlacementTargets like they did. It also doesn't mention the ToolTip's initialization problems I had (UnsetValue).
I changed the title to make it more relevant to the issues I had. Not sure if this will stay here, but there must be other people out there who are losing hours to both try to hide an empty ToolTip while also having the ability to disable it with a boolean.
I initially had a "can't cast MS.Internal.NamedObject to [x]" error. From what I understood, the error fires because the Binding can't find the property specified; however, I tried to use 2 Textblocks to debug and see whether the bindings were giving me something, and they seem to work properly. I've been grasping for straws for hours, I just can't find what's wrong.
Basically, I have a ToolTip which I don't want to see when it's either empty or set as "hidden" by a boolean.
Here's the partial XAML:
<UserControl x:Class="TidyDesk.UserControls.BoxButton"
[...]
xmlns:local="clr-namespace:TidyDesk.UserControls"
xmlns:conv="clr-namespace:TidyDesk.Converters"
mc:Ignorable="d"
Width="{Binding BtnSize}"
Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}"
Name="ThisUserControl"
d:DesignHeight="100" d:DesignWidth="100">
<UserControl.Resources>
[...]
<conv:ToolTipVisibilityMultiConverter x:Key="TTVisConv"/>
</UserControl.Resources>
<StackPanel>
<TextBlock Text="{Binding ShowToolTip}"/>
<TextBlock Text="{Binding ToolTipText}"/>
<Image Name="img" Stretch="Fill"
Source="{Binding ImgPath}"
Width="{Binding ImgSize}"
Height="{Binding RelativeSource={RelativeSource Self}, Path=Width}"
>
<Image.ToolTip>
<ToolTip Content="{Binding ToolTipText}" ToolTipService.InitialShowDelay="10">
<ToolTip.Visibility>
<MultiBinding Converter="{StaticResource TTVisConv}">
<Binding Path="DataContext.ShowToolTip" ElementName="ThisUserControl"/>
<Binding Path="DataContext.ToolTipText" ElementName="ThisUserControl" />
</MultiBinding>
</ToolTip.Visibility>
</ToolTip>
</Image.ToolTip>
[...]
</Image>
[...]
</StackPanel>
</UserControl>
Here's the partial code-behind for the UserControl:
namespace TidyDesk.UserControls
{
public partial class BoxButton : UserControl
{
public BoxButton()
{
InitializeComponent();
DataContext = this;
[...]
}
[...]
public string ToolTipText { get; set; } = "";
public bool ShowToolTip { get; set; } = true;
}
}
And here's the converter:
namespace TidyDesk.Converters
{
public class ToolTipVisibilityMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!(bool)values[0] || String.IsNullOrEmpty((string)values[1]))
return Visibility.Collapsed;
else
return Visibility.Visible;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
So far I've tried:
<Binding Path="DataContext.ShowToolTip" ElementName="ThisUserControl"/>
<Binding Path="ShowToolTip" ElementName="ThisUserControl"/>
<Binding Path="ShowToolTip" RelativeSource="{RelativeSource FindAncestor, AncestorType=local:BoxButton}"/>
<Binding Path="ShowToolTip" RelativeSource="{RelativeSource FindAncestor, AncestorType=UserControl}"/>
<Binding Path="DataContext.ShowToolTip" RelativeSource="{RelativeSource FindAncestor, AncestorType=Image}"/>
These all work in the Textblocks, aside from the last one which I can only try inside the ToolTip. But whatever I do, when I try to bind stuff in the ToolTip, I get this:
System.InvalidCastException: 'Unable to cast object of type 'MS.Internal.NamedObject' to type 'System.Boolean'.'
I found out that this could be a ToolTip problem, which isn't yet initalized and returns some UnsetValue that I could filter out like in this case with something like:
if (values[0] != DependencyProperty.UnsetValue && values[1] != DependencyProperty.UnsetValue)
return Visibility.Collapsed;
But then the ToolTip is always collapsed and the binding still "can't find the origin". What's the issue here? Am I missing something obvious?
Upvotes: 1
Views: 78
Reputation: 11
This code works:
<Image.ToolTip>
<ToolTip Content="{Binding ToolTipText}" ToolTipService.InitialShowDelay="10">
<ToolTip.Visibility>
<MultiBinding Converter="{StaticResource TTVisConv}">
<Binding Path="ShowToolTip"/>
<Binding Path="ToolTipText" />
</MultiBinding>
</ToolTip.Visibility>
</ToolTip>
</Image.ToolTip>
On this post suggested in the comments, they explain that ToolTip/Popup/ContextMenu are drawn on another window that shows on top of the main one, thus having a different visual tree; this means that ElementName and RelativeSource can't be used in this case, as they'd search the ToolTip's visual tree and not the main one, finding nothing. That's why it wouldn't work.
I'm not sure why the ToolTip can still access the main windows's DataContext despite being on a different window, but I'll leave that for another question.
Upvotes: 0