WPF - ToolTip with multibinding - c#

I want to make a tooltip with multibinding inside a text block, but whatever I try it doesn't work.
Here is what I've tried so far:
<TextBlock Text="{Binding Description, StringFormat='Description : {0}{}'}">
<ToolTipService.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Description : {0}{1}{}">
<Binding Path="FirstDescription" />
<Binding Path="SecondDescription" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTipService.ToolTip>
</TextBlock>
But when I try it, what I see on the tooltip is : System.Windows.Controls.TextBlock.
when i try it without tooltipservice, and only tooltip, like this :
<TextBlock Text="{Binding Description, StringFormat='Description : {0}{}'}">
<ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Description : {0}{1}{}">
<Binding Path="FirstDescription" />
<Binding Path="SecondDescription" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip>
</TextBlock>
The screen just get stuck.

I dont't know wich VS version you are using but:
<TextBlock Text="{Binding Description, StringFormat="Description : {0}{}"}">
does not even compile for me.
Just remove the " and the empty brackets like that:
<TextBlock Text="{Binding Description, StringFormat=Description : {0}">
You could also write it like this if you want the ":
<TextBlock>
<TextBlock.Text>
<Binding Path="Description" StringFormat="Description : {0}" />
</TextBlock.Text>
<ToolTipService.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Description : {0}{1}">
<Binding Path="FirstDescription" />
<Binding Path="SecondDescription" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTipService.ToolTip>
</TextBlock>

I have tried the following code and that worked perfectly:
<TextBlock Margin="20" Foreground="Black" FontSize="20" FontFamily="Century Gothic" Text="{Binding Name1}">
<TextBlock.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="MultiBinded Tooltip : {0}{1}">
<Binding Path="Name1"/>
<Binding Path="Name2"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</TextBlock.ToolTip>
</TextBlock>

Just delete empty brackets. Next code work as expected:
<TextBlock Text="{Binding Description, StringFormat='Description : {0}'}">
<ToolTipService.ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Description : {0}{1}">
<Binding Path="FirstDescription" />
<Binding Path="SecondDescription" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTipService.ToolTip>
</TextBlock>
If the StringFormat starts with a left brace { the XAML parser require you to escape it using a pair of braces {}. Otherwise the parser gets confused because braces also are used in the syntax of markup extensions.
Details are found in the XAML documentation for {} Escape Sequence / Markup Extension.
Also, you can't use double quotes with inline binding but single quotes is available.

Related

WPF Binding in textblock does not work but in its tooltip does

I have a weird issue.
In my application (witten with C# .net framework 4.8 with Microsoft's MVVM toolkit) I have a ListView bound to a BindingList<VisualMachine>, everything works as expected.
Now I wanted to add to the Itemtemplate a DockPanel with data from another BindingList<PreviewParameter> (another property of the original VisualMachine object ).
This is when weirdness starts: In this new ItemTemplate I have a Grid that contains an Image, a TextBlock and a Tooltip. The TextBlock and the Tooltip are bound to the same object, but only the ToolTip actually show data!
I feel like it's some DataContext Issue, but I am not able to pin it... Can anybody give me some advice?
Thanks!
The code:
<ListView Name="MachinesListView" Margin="2" HorizontalContentAlignment="Stretch" BorderThickness="0" DockPanel.Dock="Top" ItemsSource="{Binding Path=Machines}" PreviewMouseRightButtonDown="ListView_PreviewMouseRightButtonDown" SelectedItem="{Binding Path=SelectedMachine}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- Other stuff -->
<DockPanel>
<!--#region PREVIEW PARAMETERS PANEL-->
<WrapPanel HorizontalAlignment="Stretch" DockPanel.Dock="Bottom" Visibility="{Binding Path=PreviewParameters.Count, Converter={StaticResource CountToVisConverter}}">
<ListView ItemsSource="{Binding Path=PreviewParameters}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid MinWidth="50">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto" MinWidth="25"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding Path=Icon, Converter={StaticResource ResourceKey=BmpToBmpImageConverter}}"/>
<TextBlock Grid.Column="1" MaxWidth="100" DataContext="{Binding}">
<TextBlock.Text>
<!-- THIS DOES NOT APPEAR -->
<MultiBinding StringFormat="{}{0} [{1}]}">
<Binding Path="Parameter.VisualizedValue"/>
<Binding Converter="{StaticResource ParamToEnumDescConverter}" Path="Parameter"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<Grid.ToolTip>
<TextBlock MaxWidth="100" TextWrapping="Wrap">
<TextBlock.Text>
<!-- THIS DOES APPEAR -->
<MultiBinding StringFormat="{}{0} [{1}] - {2} TEST:{3} {4}">
<Binding Path="Parameter.Reference"/>
<Binding Path="Parameter.SetupIndex"/>
<Binding Path="Description"/>
<Binding Path="Parameter.VisualizedValue"/>
<Binding Converter="{StaticResource ParamToEnumDescConverter}" Path="Parameter"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Grid.ToolTip>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</WrapPanel>
<!-- Other stuff -->
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What happens:
I found it.
There was a } in the StringFormat property of the TextBlock's MultiBinding.
So instead of
<MultiBinding StringFormat="{}{0} [{1}]}">
it should be
<MultiBinding StringFormat="{}{0} [{1}]">
And BAM! Now it works.
I'll leave the question as the following reminder to anybody: "Write your code, review it, than go take a coffee o chat a little and then come back. You'll be amazed on how blind you could be."

Passing incorrect values into MultiValueConverter by MultiBinding

I've been trying to implement a dynamic ToolTip (WPF) for RadioButton (the ToolTip switches, when IsEnabled of the RadioButton changes). I wanted to achieve this with a MultiValueConverter, which would be sort of a general Converter, that accepts 3 values - the IsEnabled value, enabled ToolTip and disabled ToolTip in this exact order.
But sadly I have encountered an issue, that I haven't been able to solve yet. Basically when the code reaches the Convert Method, the Array of values is filled with DependencyProperty.UnsetValue items.
What I managed to find while googling was, that the problem is propably caused by having a wrong DataContext as mentioned here WPF MultiBinding in Convertor fails ==> DependencyProperty.UnsetValue , but I feel like I have tried every combination of RelativeSources and DataContexts, that I could come up with and nothing helped.
Here is the sample code of the View:
<window.Resources>
<local:BooleanToStringConverter x:Key="BooleanToStringConverter"/>
</window.Resources>
<Grid>
<RadioButton x:Name="RadioButton" ToolTipService.ShowOnDisabled="True"
IsEnabled="{Binding IsRadioButtonEnabled}" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Radio">
<RadioButton.ToolTip>
<ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource BooleanToStringConverter}">
<Binding ElementName="RadioButton" Path="IsEnabled"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type local:MainWindow}}" Path="ViewModel.EnabledToolTip"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type local:MainWindow}}" Path="ViewModel.DisabledToolTip"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip>
</RadioButton.ToolTip>
</RadioButton>
So the result, that I expect from this, is that the correct values will be passed into the Converter (in this case value of IsEnabled and string values of Enabled/Disabled ToolTips).
If anybody has any ideas, I would very much appreciate to hear them :).
Thanks in advance.
I managed to fix this by explicitly setting DataContext on the RadioButton and removing the RelativeSources within the MultiBinding. Though I don't understand why it did not work with the RelativeSources, it works. Here is the code, in case of anyone reading this in the future:
<RadioButton x:Name="RadioButton" ToolTipService.ShowOnDisabled="True"
DataContext="{Binding ViewModel, RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"
IsEnabled="{Binding IsRadioButtonEnabled}" VerticalAlignment="Center" HorizontalAlignment="Center" Content="Radio">
<RadioButton.ToolTip>
<ToolTip>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource BooleanToStringConverter}">
<Binding Path="IsRadioButtonEnabled"/>
<Binding Path="EnabledToolTip"/>
<Binding Path="DisabledToolTip"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ToolTip>
</RadioButton.ToolTip>
</RadioButton>

Partly deactivate xaml Styler plugin (at LineBreak MultiBinding cleanup)

I'm using xaml-Styler Plugin on VS2015. So far I didn't had any problems.
Now I have the problem, that the styler removes linebreaks (I use HTML encoded characters).
xaml (simplified)
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}; Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
after Pressing Save, the xaml styler automatically makes this (html character is removed and LineBreak inserted:
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}; Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
then the text is displayed at one line.
I'm not happy with using html encoded characters at all. Is there maybe a better (simple) way to format strings with linebreaks in a MultiBinding?
For this simple formatting I don't want to use a MultiValueConverter, because it is only an informative string...
If I could tell xaml styler don't style this part/line I would be happy, but didn't found the possibility or a property in options of xaml styler.
You can use the hex representation of the LineFeed character (char 10) :
to get a line break :
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
Min X: {1:F3}
Max X: {2:F3}">
<Binding Path="Area.Name" ... />
<Binding Path="Area.MinX" ... />
<Binding Path="Area.MaxX" ... />
</MultiBinding>
</TextBlock.Text>
</TextBlock>

TextBlock binding format

How could I achieve this behavior in my ComboBox items: (n): Name
Where n and Name are two bindable properties. Right now I have n Name
This is my code:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding n}" />
<Run Text="{Binding Name}" />
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
I think that adding two <Run Text="("/>, etc it can be done but there must be something more elegant in XAML.
Ok it was easy:
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}({0}): - {1}">
<Binding Path="n" />
<Binding Path="Name" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
Another way is using multiple TextBlocks like so:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=...}"></TextBlock>
<TextBlock Text="{Binding Path=...}"></TextBlock>
</StackPanel>
</DataTemplate>
You can replace the StackPanel with a WrapPanel or whatever you like.

How to get a parent value in multibinding

I'm using dataTemplate. This is the template:
<ItemsControl ItemsSource="{Binding RAM.Partitions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Position, StringFormat={}{0}k}"/>
<Grid Grid.Column="1">
<Border>
<Border.Height>
<MultiBinding Converter="{StaticResource MultiplyConverter}">
<Binding ElementName="LayoutRoot" Path="ActualHeight"/>
<Binding Path="Size" />
<Binding Path="RAM.Size" />
</MultiBinding>
</Border.Height>
</Border>
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Can you see this line?
<Binding Path="RAM.Size" />
That line throws me an exception, it should be because RAM.Size is from a parent element. How might I get that value?
Thanks in advance!
So you're trying to get to the RAM.Size value on the same object that your ItemsControl is getting its ItemsSource from?
See if this works:
<MultiBinding Converter="{StaticResource MultiplyConverter}">
<Binding ElementName="LayoutRoot" Path="ActualHeight"/>
<Binding Path="Size" />
<Binding Path="DataContext.RAM.Size"
RelativeSource="{RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}" />
</MultiBinding>
So the binding is going up in through the visual tree to the ItemsControl, then binding to the Ram.Size property of its DataContext.

Categories