Get text value from custom ComboBox - wpf

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>

Related

Styling the MultiBinding TextBlock in WPF

I'm trying to Bold only one of the TextBlocks in multibinding.
The Multibinding code is,
<TextBlock TextWrapping="Wrap" Padding="2 0 0 0">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}{1}">
<Binding Path="Value" Mode="OneWay"/>
<Binding Path="Status" Mode="OneWay" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
In the above block, I want to bold the second binding alone. Something like this
<Binding Path="Status" Mode="OneWay" FontWeight="Bold"/>
But there is no FontWeight property for the Binding Control.
Is there any other property to add style to the Binding tag?
or
Is there any other way that I can add style only to a particular TextBlock in MultiBinding?
Binding isn't a control and can not have a Style
for TextBlock you can declare Inlines
<TextBlock TextWrapping="Wrap" Padding="2 0 0 0">
<Run Text="{Binding Value, Mode=OneWay}"/>
<Run Text="{Binding Status, Mode=OneWay}" FontWeight="Bold"/>
</TextBlock>

WPF - access a property value from the StringFormat binding property in XAML

Is it possible to access a property value from the StringFormat binding property in XAML? I mean, this is my XAML:
<TextBox Name="costBlock" Grid.Row="4" Grid.Column="1" Margin="4" IsEnabled="False"
Text="{Binding DataContext.CalculatedCost, Mode=OneWay, StringFormat={}{0} €}"></TextBox>
I need to replace the "€" symbol in the StringFormat bindingby the symbol of the selected currency, which is a property in a static class: Settings.SelectedCurrencySymbol.
How can I do it?
Thanks to Clemens reccommendation I found this solution:
<TextBlock Name="costBlock" Grid.Row="4" Grid.Column="1" Margin="4"
IsEnabled="False">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="DataContext.CalculatedCost" />
<Binding Path="(shared:Settings.SelectedCurrencySymbol)" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>

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" />

XAML Tool Tip Data Context and Multi Binding

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>

WPF Data Binding Error in ListBox

I have a ListBox:
<ListBox x:Name="HistogramListBox" Grid.Column="1" Margin="8,2,8,0"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Template="{StaticResource HistogramListBoxControlTemplate}"
ItemContainerStyle="{StaticResource HistogramListBoxItem}"
ItemTemplate="{DynamicResource BucketTemplate}" />
That uses a DataTemplate that in turn uses a ValueConverter to determine the height of the ListBoxItem:
<DataTemplate x:Key="BucketTemplate">
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<Rectangle Grid.Row="0" StrokeThickness="1" VerticalAlignment="Bottom"
Stroke="{Binding ElementName=MainElement, Path=BucketStroke}"
Fill="{Binding ElementName=MainElement, Path=BucketFill}" >
<Rectangle.Height>
<MultiBinding Converter="{StaticResource HistogramValueToPercentageConverter}">
<Binding Mode="OneWay" Path="ItemCount" />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:Histogram}}" />
</MultiBinding>
</Rectangle.Height>
</Rectangle>
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
The ListBox ItemsSource is an int[].
When I execute the code it says it can't find 'ItemCount' on an Int32. I thought it got the item count from the ListBox (I'm obviously wrong).
Can someone tell me how I can get my ValueConverter to know what item I am on.
Thanks
Dan
Assuming your first converter parameter is intended to be the actual value being charted and the second the Histogram object:
<Rectangle.Height>
<MultiBinding Converter="{StaticResource HistogramValueToPercentageConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:Histogram}}" />
</MultiBinding>
</Rectangle.Height>
This is because the DataContext is the integer itself, at least that appears to be the case from the error message you gave.
By the way, you would normally set the ListBox's ItemsSource using a binding, not from code-behind. This leads to much cleaner separation of UI and code. I noticed no ItemsSource= was shown in your example code so I thought I should mention this.
The data context of the items in the data template is the data item itself, which is an int. If you want to a property on the ListBox, you'll need to reach outside of your current context to do so. You can use a RelativeSource to do this:
{Binding Items.Count, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}
You can try this for your Binding:
<Binding Path="Items.Count">
<Binding.RelativeSource>
<RelativeSource AncestorType="{x:Type ListBox}" />
</Binding.RelativeSource>
</Binding>

Resources