MultiBinding with MultiValueConverter does not update - wpf

it seems that I have a problem with my multibinding.
Scenario:
I have a window with two datepickers and a listview.
The listliew contains some data bound elements called "entries". An entry has a property called "date".
I just want my listview to show entries whose date is in between my two datepickes dates.
My xaml code for binding the listview to the entries and dates:
<ListView.ItemsSource>
<MultiBinding Converter="{StaticResource EntriesFilterConv}"
UpdateSourceTrigger="PropertyChanged">
<Binding Path="Entries" UpdateSourceTrigger="PropertyChanged"/>
<Binding ElementName="EntryFromDate" Path="SelectedDate"
UpdateSourceTrigger="PropertyChanged"/>
<Binding ElementName="EntryToDate" Path="SelectedDate"
UpdateSourceTrigger="PropertyChanged"/>
</MultiBinding>
</ListView.ItemsSource>
However, this doesnt work. My converter is called when a SelectedDate changes but its never called when Entries changes.
With normal data binding like this:
<ListView ItemsSource="{Binding Entries}">
...
</ListView>
The listview updates normally.
Any idea?

After searching for hours, I find a simple and decent answer !
Since ObservableCollection doesn't raise PropertyChanged event but CollectionChanged, we just have to bind the collection's Count to fire the event when the list changes :
<MultiBinding Converter="{Resources:ListToStringConverter}">
<Binding Path="List.Count" />
<Binding Path="List" />
</MultiBinding>
Original infos about this perfectly working multibinding here : https://stackoverflow.com/a/10884002/817504

I think the following might cause this: If you bind directly to the Entries the ListView will listen to CollectionChanged events, but if such a binding is inside a MultiBinding the only thing that would cause a reevaluation could be a PropertyChanged notification, which might not exist for the Entries property in your model.
Maybe you can subscribe to the CollectionChanged event of your collection and raise a PropertyChanged event or get the BindingExpression within your MultiBinding to call an update manually.

Related

Dynamic binding to any tab control - WPF

I am trying to set the max width of the grid of a view, however I want to be able to put this view anywhere within any tab control, as the width of the grid is determined by the tab control it's within. I don't want to have to specify the specific tab control by name because I want it to work with any tab control.
Does anyone know how I can change the below XAML code? This is in the WeUserControl view
<Grid.MaxWidth>
<MultiBinding Converter="{StaticResource WeMaxWidthConverter}">
<Binding ElementName="mainWindowTabControl" Path="ActualWidth"/>
</MultiBinding>
</Grid.MaxWidth>
In the view that it is being used in, it is literally just:
<views:WeUserControl Grid.Column="0" Grid.Row="1" />
and that is encapsulated in a tab control, in this case, called mainWindowTabControl
It's just the tabcontrol you're looking for and the grid will be within the visual tree of this.
The relativesource binding would be:
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource AncestorType={x:Type TabControl}}" />
If you add a public property called "TabControl" to the parent window that returns a reference to the TabControl, you should be able to bind to it like this from any child element of the window:
<Binding Path="TabControl.ActualWidth"
RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" />

I can't get the property of the view model in the multi value converter

I have a DataGrid. I want to decide when to collapse a column and when to show it.
This is my code:
<UserControl.Resources>
<ResourceDictionary>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
</ResourceDictionary>
<UserControl.Resources>
<DataGridTextColumn.Visibility>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding Source="{StaticResource ProxyElement}" Path="DataContext.MyPropertyInViewModel" />
<Binding Source="1"/>
</MultiBinding>
</DataGridTextColumn.Visibility>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
//Do the conversion
}
I need the proxy element to access the view model from an element that doesn't belong to the visual tree.
In the MultiBinding, the second binding works. In the converter I receive the value 1, but the problem is with the first element. I don't get the property of the view model, that it is a string. I get a DependencyProperty.UnsetValue.
How can I pass a property of my view model to the multi-value converter?
The ProxyElement will not bind the data context in Resources as it is not part of the visual tree. To make this work, define the FrameworkElement anywhere in the visual tree, e.g. like below in a Grid. The DataContext is inherited, but you can also set it explicitly. Set the Visibility of the proxy to Collapsed, so it is hidden.
<Grid>
<!-- ...grid definitions. -->
<FrameworkElement Grid.Row="42" x:Name="ProxyElement" Visibility="Collapsed"/>
</Grid>
Reference it using x:Reference, since ElementName bindings only work in the visual tree, but columns are not part of it.
<DataGridTextColumn.Visibility>
<MultiBinding Converter="{StaticResource MyMultiValueConverter}">
<Binding Source="{x:Reference ProxyElement}" Path="DataContext.InitialDepositAmount"/>
<Binding Source="1"/>
</MultiBinding>
</DataGridTextColumn.Visibility>
A better way is to use a Freezable as binding proxy. Those can access the data context even outside of the visual tree. See this related post that shows an approach with a custom BindingProxy, that also works in Resources and without x:Reference.

Using CommandParameters and MultiBindings?

Is it possible to use CommandParameter="{Binding}" in a multi binding?
I am trying to do this in a data grid.
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource CDetailConverter}">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
<Binding ConverterParameter="{Binding}"/>
</MultiBinding>
</CheckBox.CommandParameter>
The second Binding throws an error.
In a nutshell, the answer is no.
In your second inner Binding you have set ConverterParameter. There are a couple of problems with this:
First, Binding is its own class separate from MultiBinding with both Converter and ConverterParameter properties. Here you have set the ConverterParameter property without setting the Converter property. Remember that ConverterParameter is passed to the Binding's specified converter regardless if it is used within a MultiBinding or not. If you were to add a Converter here, then the converter would be passed the specified ConverterParameter.
What you probably meant to do was set the ConverterParameter on the outer MultiBinding which also has this property:
<CheckBox.CommandParameter>
<MultiBinding Converter="{StaticResource CDetailConverter}" ConverterParameter="{Binding }">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
</MultiBinding>
</CheckBox.CommandParameter>
If you try this, you will quickly see that ConverterParameter can not be the target of a Binding expression since it is not a DependencyProperty.
Since you can not bind to CommandParameter, the typical workaround is to modify your IMultiConverter to accept an additional value, and supply this value through a binding expression:
<CheckBox.CommandParameter>
<!-- CDetailConverter updated to expect an additional value in the values array -->
<MultiBinding Converter="{StaticResource CDetailConverter}">
<Binding Path ="IsChecked" ElementName="chkSelection"/>
<Binding />
</MultiBinding>
</CheckBox.CommandParameter>
Hope this helps!

Problem with validation and multibinding

In my WPF application I use the following xaml:
...
<TextBox
services:TextBoxService.IsFocused="{Binding Path=IsSelected, Mode=OneWay}"
FocusVisualStyle="{x:Null}">
<MultiBinding
Converter="{StaticResource mconv_operableToString}"
UpdateSourceTrigger="PropertyChanged">
<Binding
Path="Value"
Mode="TwoWay"
NotifyOnValidationError="True" />
<Binding
RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}"
Path="DataContext.Status"
Mode="OneWay" />
</MultiBinding>
The view model class which the first binding uses implements IDataErrorInfo for validation purposes. The problem is that although the error is caught in the property setter, the UI doesn't notice it. I have a style defined with an error template which should be applied when any error occurs in the text box. I suppose that maybe this scenario is not allowed with multi binding because where I use single binding everything works fine.
Thanks in advance.
It seems to me that nobody knows the answer to this but I suppose that this scenario just doesn't work. I'll try to answer it in case somebody will need it. I've tried to bind my View to my View Model class which implements IDataErrorInfo, in xaml I specified a converter and although everything worked fine, the Errors just didn't show up on the UI. So, I removed the converter from the binding and implemented that logic inside the View Model and, voila now everything works fine.

WPF Converter problem

So I have an object that implements INotifyPropertyChanged, and I have a property that when it changes, it call the PropertyChanged event all right, but when I use a converter like this:
<Image Grid.Column="0">
<Image.Source>
<Binding Path="IsInstrumentStatusOk" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<converters:BooleanToImageConverter
ImagePathIfFalse="/Images/InstrumentStatusBar/Instrument_Status_Alarm.png"
ImagePathIfTrue="/Images/InstrumentStatusBar/Instrument_Status_OK.png" />
</Binding.Converter>
</Binding>
</Image.Source>
</Image>
For some reason it doesn't update it, and it doesn't call the converter. If I use it like normally
Source="{Binding MyProperty, Converter={StaticResource MyConverter}}"
It works, but I don't want to use it like that because I have a bunch of converters that I want to use with different images. Any idea why it doesn't update?
Thanks.
You're setting UpdateSourceTrigger="PropertyChanged" in your XAML. This means when the target property changes the value should update back to the source. Obviously nothing is ever changing the Image::Source property.
Just remove the UpdateSourceTrigger setting altogether and you should be fine.

Resources