XAML Tool Tip Data Context and Multi Binding - wpf

I have a ListView in my XAML and I am trying to hook up a MultiBinding Converter.
<ListView
Grid.Column="4"
Grid.Row="1"
Grid.RowSpan="5"
Margin="8,0,8,8"
HorizontalAlignment="Stretch"
Name="lvDisplayType"
ItemsSource="{Binding Path=Types}"
SelectedItem="{Binding Path=Current.Opt}"
VerticalAlignment="Stretch"
SelectionChanged="lvType_SelectionChanged"
SelectionMode="Single"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel
HorizontalAlignment="Center">
<TextBlock
Text="{Binding Path=., Converter={StaticResource DisplayConverter}}"
HorizontalAlignment="Center"
Padding="6"
VerticalAlignment="Center"
TextWrapping="Wrap">
<TextBlock.ToolTip>
<ToolTip DataContext="{Binding Path=Current}">
<MultiBinding Converter="{StaticResource OptConverter}">
<Binding Path="Opt" />
<Binding Path="Type" />
</MultiBinding>
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The code not working is:
<TextBlock.ToolTip>
<ToolTip DataContext="{Binding Path=Current}">
<MultiBinding Converter="{StaticResource OptConverter}">
<Binding Path="Opt" />
<Binding Path="Type" />
</MultiBinding>
</ToolTip>
</TextBlock.ToolTip>
At present the Converter is returning an empty string as both 'values[0] == System.Windows.DependencyProperty.UnsetValue' and 'values[1] == System.Windows.DependencyProperty.UnsetValue' return true. These values are never set.
Because of the logical tree (I think) the TextBlock.ToolTip default binding is 'Current.Opt'. For the MultiBinding I also need to refer to 'Type' which is another property of 'Current'. So to get around this I have set 'ToolTip DataContext="{Binding Path=Current}"' - this isn't working as expected - what am I doing wrong?
I know I could do this easily in the Code behind, but we are employing MVVM, so would like to avoid it if possible.
Any help greatly appreciated!
Thank you

Try to do it in this way,
1.Does this give DependencyProperty.UnsetValue in the Converter? Otherwise, what is coming in to the converter?
<TextBlock.ToolTip>
<MultiBinding Converter="{StaticResource OptConverter}">
<Binding RelativeSource="{RelativeSource Self}" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</TextBlock.ToolTip>
2.Does this give DependencyProperty.UnsetValue in the Converter?
<TextBlock.ToolTip>
<MultiBinding Converter="{StaticResource OptConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Current"/>
<Binding RelativeSource="{RelativeSource Self}" Path="Current"/>
</MultiBinding>
</TextBlock.ToolTip>

Related

Binding Combobox does not work when a Converter is used

I'm trying to bind a ComboBox to DataContext.
<ComboBox ItemsSource="{Binding Path=Numbers}"
SelectedValue="{Binding Path=CurrentNumber,Mode=TwoWay}">
</ComboBox>
The above code works, but when I try to change how the items are displayed using a converter implementing IMultiValueConverter and MultiBinding nothing is displayed. I have debugged the method implementing the IMultiValueConverter and it is not getting executed. What could be the problem?
<ComboBox ItemsSource="{Binding Path=Numbers}"
SelectedValue="{Binding Path=CurrentNumber,Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiUnitConverter}" ConverterParameter="{x:Static enumerations:Quantity.Length}" >
<Binding Path="."/>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="DataContext.CurrentUnit"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Update:
I tried the following instead of the ComboBox, the converter is fired and the data is loaded but not displayed!
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiUnitConverter}" ConverterParameter="{x:Static enumerations:Quantity.Length}" >
<Binding Path="CurrentNumber"/>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="DataContext.CurrentUnit"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
The following works though:
<TextBlock>
<TextBlock.Text>
<Binding Path="CurrentNumber"></Binding>
</TextBlock.Text>
</TextBlock>
For all who may get stuck with this in the future and ruin their entire evening here is the solution I found!
It seems adding StringFormat solves the problem!
<ComboBox ItemsSource="{Binding Path=Numbers}" SelectedItem="{Binding Path=Number, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding
Converter="{StaticResource MultiUnitConverter}"
ConverterParameter="{x:Static enumerations:Quantity.Length}"
StringFormat="{}{0:0.###}">
<Binding Path="."/>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="DataContext.CurrentUnit"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Did you define the converter resource somewhere else in your xaml? If not, you should do so. For instance, if your ComboBox lives in a UserControl you could add:
<UserControl.Resources>
<local:MultiUnitConverter x:Key="multiUnitConverter"/>
</UserControl.Resources>
And of course you would need to update your Converter StaticResource to match the case-sensitive Key above.

RelativeSource Sibling

Below tabitem3 is working fine.
I would like to get away from naming the controls and pass the properties by RelativeSource.
The code that is failing is
Binding RelativeSource="{RelativeSource AncestorType={x:Type Expander}}" Path="IsExpanded"
The error in the converter is dependency object not set
The Expander is a sibling not an ancestor.
How can I find that sibling (without an x:Name)?
<TabItem x:Name="tabitem3" IsSelected="False">
<TabItem.Header>
<Expander x:Name="tabexp3" Header="Three" IsHitTestVisible="True"
Expanded="expcolp" Collapsed="expcolp" IsExpanded="False"/>
</TabItem.Header>
<TextBlock Text="Content Three TabItem" Background="LightBlue" >
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource bvc2}" Mode="OneWay">
<Binding ElementName="tabexp3" Path="IsExpanded"/>
<Binding ElementName="tabitem3" Path="IsSelected" />
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
</TabItem>
<TabItem IsSelected="False">
<TabItem.Header>
<Expander Header="Four" IsHitTestVisible="True"
Expanded="expcolp" Collapsed="expcolp" IsExpanded="False"/>
</TabItem.Header>
<TextBlock Text="Content Four TabItem" Background="LightBlue" >
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource bvc2}" Mode="OneWay">
<Binding RelativeSource="{RelativeSource AncestorType={x:Type Expander}}" Path="IsExpanded"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TabItem}}" Path="IsSelected"/>
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
</TabItem>
I am not sure that Expander is a real sibling of the TextBlock. The first one is a child of TabItem's header, the former is a child of TabItem's content.
Anyway if you do not want to use naming (indeed I do not like it too), you can "go up" through the logical tree by looking for a TabItem ancestor and then you can "go down" by using the right path.
The result is this binding:
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TabItem}}" Path="Header.IsExpanded" />
I hope it can help you.
EDIT
To test my binding you can use this simple XAML:
<TabControl>
<TabItem IsSelected="True">
<TabItem.Header>
<Expander Header="One" IsHitTestVisible="True" IsExpanded="False"/>
</TabItem.Header>
<TabItem.Content>
<TextBlock Text="Some contents..." />
</TabItem.Content>
</TabItem>
<TabItem IsSelected="False">
<TabItem.Header>
<Expander Header="Two" IsHitTestVisible="True" IsExpanded="False"/>
</TabItem.Header>
<TabItem.Content>
<TextBlock>
<TextBlock.Text>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TabItem}}" Path="Header.IsExpanded" />
</TextBlock.Text>
</TextBlock>
</TabItem.Content>
</TabItem>
</TabControl>
If you expand/collapse the second Expander, the TextBlock's text will change.
My binding does not work if the TabItem has IsSelected set to true. In this case you can extend my idea in this way:
<Binding RelativeSource="{RelativeSource AncestorType={x:Type TabControl}}" Path="SelectedItem.Header.IsExpanded" />

Get text value from custom ComboBox

I have a ComboBox defined as below:
<ComboBox Width="200" Height="30" Grid.Column="0" x:Name="ExistingSpeciesComboBox"
ItemsSource="{Binding SpeciesColorCollection}" HorizontalAlignment="Left">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Fill="{Binding Path=Brush}" Stroke="Black" StrokeThickness="1" Height="15" Width="30"/>
<w:WTextBlock Text="{Binding Name}" VerticalAlignment="Center"
Foreground="{StaticResource SmallControlForegroundBrush}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
SpeciesColorCollection is an ObservableCollection of type ColorObject
Public Class ColorObject
Public Property Name As String
Public Property Brush As Brush
End Class
The ComboBox displays the items from the collection correctly but my problem is when I try to get the selected text from the ComboBox in a MultiBinding, I receive ColorObject instead of the name. How do I go about getting the value of the "Name" from within the WTextBlock of the ComboBox? The binding that I am using for my command is below. The converter is only returning strings.
<MultiBinding Converter="{StaticResource mySpeciesSetupConverter}">
<MultiBinding.Bindings>
<Binding ElementName="NewSpeciesName" Path="Text" />
<Binding ElementName="ExistingSpeciesComboBox" Path="Text" />
</MultiBinding.Bindings>
</MultiBinding>
<MultiBinding Converter="{StaticResource mySpeciesSetupConverter}">
<MultiBinding.Bindings>
<Binding ElementName="NewSpeciesName" Path="Text" />
<Binding ElementName="ExistingSpeciesComboBox" Path="SelectedItem.Name" />
</MultiBinding.Bindings>
</MultiBinding>

How do I set a Multibinding and Image in Expander Header

perhaps you can help me to solve this problem. I want to display a Text-Multibinding and an image in the header of my expander.
This is my simplified coding of the expander:
<Expander
x:Name="_myExpander">
<Expander.Header>
<MultiBinding
Converter="{StaticResource ExpanderHeaderConverter}">
<Binding
Path="Property1" />
<Binding
Path="Property2" />
<Binding
Path="Property3" />
</MultiBinding>
</Expander.Header>
<local:Content/>
</Expander>
How can I set an image in there?
thanks in advance!
Try this:
<Expander.Header>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ...}"/>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ExpanderHeaderConverter}">
<Binding Path="Property1" />
<Binding Path="Property2" />
<Binding Path="Property3" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Expander.Header>

Does ItemsTemplate+DataTemplate obscure bindings?

At several points in my current application, I have an ItemTemplate such as the following:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ToggleButton Margin="2,0" Content="{Binding}" Tag="{Binding}" Click="ToggleButton_Click">
<ToggleButton.IsChecked>
<MultiBinding Mode="OneWay" Converter="{StaticResource EqualityConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Tag">
</Binding>
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type cc:ToggleButtonPanel}}" Path="SelectedItem">
</Binding>
</MultiBinding>
</ToggleButton.IsChecked>
</ToggleButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
Now, I've stepped through the converter and it returns true and false as expected, but the controls do not change their ischecked state... There are no binding errors, and this only happens when using an ItemsTemplate/DataTemplate combo. Has anyone else seen this behaviour?

Resources