Multibinding using Window's DataContext - c#

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.

Related

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>

Obtain ListBox SelectedItem through ContextMenu with Multibinding in Windows.Resource

I'm trying to use multibinding on a context menu stored in Window.Resources and I can't figure out how to get the SelectedItem of the ListBox I attach the menu to.
I think I need to use PlacementTarget, but can't get anything to work. I tried using FindAncestor, but that didn't work. I also tried getting the listbox by the ElementName to no avail.
<Window ...>
<Window.DataContext>
<local:IPViewModel/>
</Window.DataContext>
<Window.Resources>
<sys:Int32 x:Key="Number">0</sys:Int32>
<sys:Int32 x:Key="NumberLetter">1</sys:Int32>
<sys:Int32 x:Key="NumberLetterNumber">2</sys:Int32>
<local:CombineParams x:Key="CombineParams"/>
<ContextMenu x:Key="DetailMenu">
<MenuItem Header = "Number">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SwitchLabelMode}">
<i:InvokeCommandAction.CommandParameter>
<MultiBinding Converter="{StaticResource CombineParams}">
<!-- The next line is where I'm not sure what to write to get to the listbox -->
<Binding Source="{RelativeSource AncestorType={x:Type ListBox}}"/>
<Binding Source="{StaticResource Number}"/>
</MultiBinding>
</i:InvokeCommandAction.CommandParameter>
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
...
</Window.Resources>
...
<ListBox Name="IndexDetailsListBox"
...
ContextMenu="{StaticResource DetailMenu}"
...>
</ListBox>
...
</Window>
I can't get it to give back anything other than unset value.
I'm grateful for any help. None of the other questions I found have the contextmenu in Window.Resources with MultiBinding which seems to be my issue.
Your problem is, that you assign RelativeSource- object to the Source property of the Binding object. RelativeSource- object belongs to the RelativeSource-property.
So you get your List to the multi value converter:
<MultiBinding Converter="{StaticResource CombineParams}">
<Binding Path="PlacementTarget" RelativeSource="{RelativeSource AncestorType={x:Type ContextMenu}}"/>
<Binding Source="{StaticResource Number}"/>
</MultiBinding>

Implementing IValueConverter to get Name from ID

I have a table column called LOCATION_ID. I want to show the LOCATION_NAME which is located in the LOCATION table instead of the ID.
I am trying to implement IValueConverter but can't figure out how to do it. I am using WPF with entity framework.
How would I pass the ID value to this converter?
I have a method name GetLocationNameByID(). Where in the converter would I Call this method? And how would I bind the return value to the datagrid XAML?
Implementing the IValueConverer interface is pretty straightforward. In the XAML, you'd have something like this:
<Window x:Class="CarSystem.CustomControls.AlarmDisplayer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNameSpace"
DataContext="{Binding Path=MyDataContextObject, RelativeSource={RelativeSource Self}">
<Window.Resources>
<local:MyIValueConverter x:Key="Converter" />
</Window.Resoures>
<TextBox Text="{Binding Converter={StaticResource Converter} Path=MyProperty}" />
</Window>
When WPF detects a change in the value of the MyProperty in the MyDataContextObject, it calls the MyIValueConverter object's Convert method, passing the value of the property as the Value parameter. Your implementation of the Convert method does what it has to do & returns the string to be displayed.
you can use multi-binding, have your value converter implement the IMultiValueConverter interface. The converter takes an object array, each of which can be a binding to your XAML.
<TextBox>
<TextBox.Text>
<MultiBinding Converter="{StaticResource MyConverter}">
<MultiBinding.Bindings>
<Binding Path="SomeProperty" />
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding.Bindings>
</MultiBinding>
</TextBox.Text>
</TextBox>

WPF MultiBinding fails in Syncfusion TabItemExt header

I have a subclass of TabItem as follows, for which I'm trying to set the Header property. I've tried this with a MultiBinding:
<DataEditPane x:TypeArguments="MyType" x:Class="MyDataEditPane">
<DataEditPane.Header>
<MultiBinding StringFormat="Hello world {0} {1}">
<Binding Path="BoundVariable1" />
<Binding Path="BoundVariable2" />
</MultiBinding>
</DataEditPane.Header>
</DataEditPane>
But it fails as such:
System.Windows.Data Error: 28 : MultiBinding failed because it has no valid Converter. MultiBindingExpression:target element is 'MyDataEditPane' (Name=''); target property is 'Header' (type 'Object')
System.Windows.Data Error: 28 : MultiBinding failed because it has no valid Converter. MultiBindingExpression:target element is 'MyDataEditPane' (Name=''); target property is 'Header' (type 'Object')
I'd always thought the StringFormat served the role of the converter, but perhaps not?
Wrapping the fields together in some kind of container, like a Label, also doesn't seem to work:
<DataEditPane x:TypeArguments="MyType" x:Class="MyDataEditPane">
<DataEditPane.Header>
<Label>
<Label.Text>
<MultiBinding StringFormat="Hello world {0} {1}">
<Binding Path="BoundVariable1" />
<Binding Path="BoundVariable2" />
</MultiBinding>
</Label.Text>
</Label>
</DataEditPane.Header>
</DataEditPane>
In this case, the .ToString() representation of the label ("System.Windows.Controls.Label") is shown as the header.
Note that a single binding works just fine:
<DataEditPane x:TypeArguments="MyType" x:Class="MyDataEditPane">
<DataEditPane.Header>
<Binding Path="BoundVariable1" />
</DataEditPane.Header>
</DataEditPane>
If it matters, I'm using the Syncfusion TabItemExt as one of my superclasses in the inheritance hierarchy, but as that class doesn't override the Header property I don't think that makes a difference.
What am I doing wrong? I know I can make another property in the ViewModel to act as the Header (and then single-bind that) but I want to learn how to do this properly in XAML.
Try a TextBlock instead of a Label. The following code worked fine for me.
I tried this:
<Window x:Class="ListBox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ListBox" Title="Window1" Height="300" Width="300">
<Window.DataContext>
<local:TextVM/>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Text1}" />
<TextBox Text="{Binding Text2}" />
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="Hello World {0} - {1}">
<Binding Path="Text1" />
<Binding Path="Text2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Window>
I wonder if StringFormat is only valid in cases where a string is expected rather than an object.
There's an example on MSDN here: http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.stringformat.aspx
Multi-Bindings requires a converter, i think that a converter that you may use is the StringFormatConverter, it is a IMultiValueConverter so works for multibindings.
Maybe you should adapt it to your case.
Hope this could be useful for you...

Compound DisplayMemberPath for a combobox

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>

Categories