I have an ObservableCollection bound to a list box and a boolean property bound to a button. I then defined two converters, one that operates on the collection and the other operates on the boolean property. Whenever I modify the boolean property, the converter's Convert method is called, where as the same is not called if I modify the observable collection. What am I missing??
Snippets 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.TargetProp开发者_StackOverflow中文版erty="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 behind snippet
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();
}
}
A multibinding converter can be used to overcome this issue. You can then bind to the Collection.Count
property and the collection at the same time. The count will trigger the binding to get re-evaluated and then you use the second binding to actually transform the values as required
<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>
I think the converter in a Binding
is always called if the Binding
source has been updated and notifies about that update (as a DependencyProperty
or using INotifyPropertyChanged
). However, an ObservableCollection
does not raise the PropertyChanged
event if an item has been added or removed, but it raises the CollectionChanged
event. It does not raise any event at all if an item in the collection is changed. Even if the item itself raises PropertyChanged
, this will not update the Binding
on the collection since the Binding
source is not the item, but the collection.
I fear your approach will not work this way. You could bind directly to ObservableCollection.Count
and add an appropriate math converter to it to perform the inversion and multiplication, but the Count
property does not perform change notification, so this no option. I think you will have to provide another property in your ViewModel or code-behind which handles these cases...
A converter is called when the binding happens or the property changes. So your converter is called for your boolean whenever the value of the boolean changes. Your collection is set once and that is when the binding occurs and the converter is used. When the internals of the collection change (the collection is added to or removed from) the property does not change (i.e. you are not binding a new collection) so your converter does not fire again.
Use a view model and wrap your collection and add another property such as count that implements 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.
精彩评论