WPF Converters and ObservableCollections
I'm binding an ObservableCollection to a control which has a converter to change its visibility depending on if the collection has any values or not:
Simplified example:
XAML:
<Window.Resources>
<local:MyConverter x:Key="converter"/>
</Window.Resources>
<Grid x:Name="grid">
<Rectangle Height="100" Width="200" Fill="CornflowerBlue"
Visibility="{Binding Converter={StaticResource converter}}"/>
<Button Content="click"
HorizontalAlignment="Left" VerticalAlignment="Top"
Click="Button_Click"/>
</Grid>
C#:
ObservableCollection<string> strings;
public MainWindow()
{
InitializeComponent();
strings = new ObservableCollection<string>();
grid.DataContext = strings;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
strings.Add("new value");
}
When the collection is bound, th开发者_JAVA百科e Rectangle is visible when there are values and not when the collection is empty. However, if the collection is empty and I add a value at runtime, the Rectangle does not appear (the converter's Convert method isn't even fired). Am I missing something or just trying to ask too much of IValueConverter?
OK, so here's how I got around the problem using a MultiValueConverter
The converter now looks like:
public object Convert(
object[] values,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
ObservableCollection<string> strings =
values[0] as ObservableCollection<string>;
if (strings == null || !strings.Any())
return Visibility.Collapsed;
else
return Visibility.Visible;
}
public object[] ConvertBack(
object value,
Type[] targetTypes,
object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
And the XAML now looks like:
<Rectangle Height="100" Width="200" Fill="CornflowerBlue">
<Rectangle.Visibility>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="."/>
<Binding Path="Count"/>
</MultiBinding>
</Rectangle.Visibility>
</Rectangle>
The C# remains the same :)
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...
best regards,
You must set the DataContext after creating the collection; it is probable that you initialize the "strings"collection to "null", you set the DataContext in the constructor to that value(e.g. null), then you actually create the collection--this way, the DataContext remains null.
You must set the DataContext again after creating the collection.
精彩评论