When the ValueConverter Convert method is called in wpf

I have an ObservableCollection bound to a list and a boolean bound to a button . Then I defined two converters , one of which works with the collection, and the other with the Boolean property. Whenever I change a boolean property, the Convert conversion method is called, where, since it is not called if I change the observable collection. What am I missing?

Fragments for your reference,

xaml snipet,

<Window.Resources> <local:WrapPanelWidthConverter x:Key="WrapPanelWidthConverter" /> <local:StateToColorConverter x:Key="StateToColorConverter" /> </Window.Resources> <StackPanel> <ListBox x:Name="NamesListBox" ItemsSource="{Binding Path=Names}"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel x:Name="ItemWrapPanel" Width="500" Background="Gray"> <WrapPanel.RenderTransform> <TranslateTransform x:Name="WrapPanelTranslatation" X="0" /> </WrapPanel.RenderTransform> <WrapPanel.Triggers> <EventTrigger RoutedEvent="WrapPanel.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="WrapPanelTranslatation" Storyboard.TargetProperty="X" To="{Binding Path=Names,Converter={StaticResource WrapPanelWidthConverter}}" From="525" Duration="0:0:2" RepeatBehavior="100" /> </Storyboard> </BeginStoryboard> </EventTrigger> </WrapPanel.Triggers> </WrapPanel> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.ItemTemplate> <DataTemplate> <Grid> <Label Content="{Binding}" Width="50" Background="LightGray" /> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Button Content="{Binding Path=State}" Background="{Binding Path=State, Converter={StaticResource StateToColorConverter}}" Width="100" Height="100" Click="Button_Click" /> </StackPanel> 

code after fragment

 public class WrapPanelWidthConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ObservableCollection<string> aNames = value as ObservableCollection<string>; return -(aNames.Count * 50); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } public class StateToColorConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { bool aState = (bool)value; if (aState) return Brushes.Green; else return Brushes.Red; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } 
+5
source share
3 answers

I think that the converter in Binding always called if the Binding source has been updated and notifies about this update (like DependencyProperty or using INotifyPropertyChanged ). However, the ObservableCollection does not raise the PropertyChanged event if the item has been added or removed, but it fires the CollectionChanged event. It does not raise any event at all if the item in the collection changes. Even if the element itself raises the value of PropertyChanged , this will not update the Binding in the collection, since the source of the Binding not an element, but a collection.

I'm afraid your approach will not work. You can directly bind it to ObservableCollection.Count and add the appropriate mathematical converter to it to perform inversion and multiplication, but the Count property does not notify about the change, so this parameter is not. I think you will have to provide another property in your ViewModel or code that handles these cases ...

+11
source

To overcome this problem, you can use a multitask converter. Then you can bind the Collection.Count property and the collection at the same time. The counter initiates the binding for re-evaluation, and then you use the second binding to actually convert the values ​​as needed.

  <TextBlock IsHitTestVisible="false" Margin="5,0" TextTrimming="CharacterEllipsis" VerticalAlignment="Center" DockPanel.Dock="Left" > <TextBlock.Text> <MultiBinding Converter="{Resources:ListToStringConverter}"> <Binding Path="List.Count" /> <Binding Path="List" /> </MultiBinding> </TextBlock.Text> </TextBlock> 
+11
source

The converter is called when a binding occurs or a property changes. Thus, your converter is called for your boolean when the boolean value changes. Your collection is installed once, and that's when the binding occurs and the converter is used. When the inside of the collection changes (the collection is added or deleted), the property does not change (i.e. you do not bind a new collection), so your converter does not start again.

Use a view model and wrap your collection and add another property, such as a counter, that implements a change notification. You can use this wrapper class from here , which will wrap your collection, and it will be easy to add a property there.

+2
source

Source: https://habr.com/ru/post/885430/


All Articles