Compound DisplayMemberPath for a combobox - c#

I need to create a DisplayMemberPath that is a compound of a few properties (ie object.category.Name+" -> "+object.description) I'm pretty sure I can do this by creating a dynamic data type that encapsulates the object and also adds a new property called displayField that is what I need but I'm wondering if there is a more proper way to do this that does not involve creating a new object. Any ideas?

DisplayMemberPath is just a "shortcut" for when you don't need a complex template for items. If you need more control, use ItemTemplate instead:
<ComboBox ItemsSource="{Binding Items}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} -> {1}">
<Binding Path="Category.Name" />
<Binding Path="Description" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Related

WPF object binding from parent itemscontrol

I have Groups collection property in my viewmodel and each group has its Teams collection.
I want to remove a team from group with a button click. How can I bind the group in which the team is to the command parameter? This solution is not working:
<ItemsControl ItemsSource="{Binding Groups}" Name="gSource" Tag="{Binding .}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Teams}" Name="tSource">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Path=DataContext.RemoveTeamFromGroupCommand, ElementName=gSource}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource ObjectsConverter}">
<Binding Path="."/>
<Binding Path="Tag.Value" RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It binds the team properly, but instead of group it binds MS.Internal.NamedObject with unset value.
#Tam Bui is perfectly right about using the DataContext of the parent ItemsControl.
But besides "RelativeSource AncestorType", you can name the UI elements inside the DataTemplate (you assigned the tSource) and use them.
You used a similar binding to bind the command.
Also, Binding by default provides a link to the current data context.
It is not necessary to give it Path.
Alternative solution:
<Button Command="{Binding Path=DataContext.RemoveTeamFromGroupCommand, ElementName=gSource}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource ObjectsConverter}">
<Binding/>
<Binding Path="DataContext" ElementName="tSource"/>
</MultiBinding>
</Button.CommandParameter>
</Button>
The Tag is unnecessary if you want the Group to be the 2nd binding of your MultiBinding. Instead, just bind it to the DataContext of the relative ancestor ItemsControl. I tested this and it worked.
<MultiBinding Converter="{StaticResource ObjectsConverter}">
<Binding Path="."/>
<Binding Path="DataContext" RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
</MultiBinding>

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>

Updating the source of a Listbox with a multibinding

I'm trying to get a multi-bound listbox to call the convert back method when items inside it change. Specifically I have a datatemplate that maps each entry to a checkbox and I'd like the source to be updated whenever a box is checked.
<ListBox x:Name="listBoxEdit" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3" Height="100" >
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource selectedLoadsConverter}" >
<Binding Path="AvailableLoads"/>
<Binding Path="CurrentUnit"/>
</MultiBinding>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Item1}" IsChecked="{Binding Item2}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I know the problem lies in the fact that I'm binding to to the ItemsSource property which is never actually being updated by the checkbox changing, but I can't figure out a good way to push the updates up to the source.

ComboBox.ItemTemplate not displaying selection properly

In the question c# wpf - cannot set both DisplayMemberPath and ItemTemplate, I have read that you can replace the DisplayMemberPath to combine multiple data items in a ComboBox.
I set up my Combobox using ItemTemplate and it is successfully populated. But when I select an item in my ComboBox, I get Data.MaterialNumber displayed instead of the actual text I selected.
MaterialNumbers is an ObservableCollection<>
Can someone tell me why my ComboBox is not displaying the item correctly after it is selected?
// Binding from my ViewModel, which retrieves material numbers correctly.
ObservableCollection<MaterialNumber> MaterialNumbers = GetMaterialNumbers();
<ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding MaterialNumbers}"
SelectedItem="{Binding MaterialNumber}"
Validation.Error="View_Validator" Validation.ErrorTemplate="{StaticResource ErrorTemplateBorder}"
IsEnabled="{Binding IsEnabled}" IsEditable="True" IsReadOnly="True" Margin="0,10,0,0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}: {1}">
<Binding Path="Program.Name" />
<Binding Path="MaterialNumberString" />
<Binding UpdateSourceTrigger="PropertyChanged" />
<Binding NotifyOnValidationError="True" />
<Binding ValidatesOnDataErrors="True" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Thanks to this article http://www.shujaat.net/2010/08/wpf-editable-combobox-with-datatemplate.html, I was able to figure out why my ComboBox did not display correctly when an item was selected. It is because my ComboBox was set to IsEditable="True". Apparently, when using a ComboBox.ItemTemplate and having MultiBinding set, the ComboBox cannot determine which item to display so it displays the class instead.

Multibinding using Window's DataContext

I'm trying to create drag adorner based on whether the Customer DependancyProperty of a Window is null. I have this in the Window's resources. The first part of the binding is set (the item being dragged), but the second (the DependancyProperty on the WIndow) shows as UnsetValue.
The property is definitely initialized as it's used as the window's datacontext.
<Window x:Name="root"
...
>
<Window.Resources>
<DataTemplate x:Key="DragAdorner">
<StackPanel Orientation="Horizontal">
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource vehicleDragConverter}">
<Binding/>
<Binding Path="Customer" ElementName="root"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</DataTemplate>
customer is not a direct property of element window.
use <Binding Path="DataContext.Customer"..../>
or you can also use RelativeSource=FindControl Window in binding.

Categories