Reputation: 620
Scenario: A ListView is DataBound to an ObservableCollection<CustomClass>
and is displaying it's items through a custom ItemTemplate. The CustomClass
just contains three string properties and one boolean property and already has INotifyPropertyChanged implemented on every of it's four properties. The custom ItemTemplate of the ListView has One-Way bindings on the three string properties and a Two-Way binding on the boolean property, displaying it as a CheckBox.
Problem: I'm looking for the most elegant (in terms of WPF) way to display the count of all checked items in that ListView using a TextBlock - or in other words, all items that have their boolean property set to true
in that collection. I want that TextBlock to immediately update the displayed count if one of the ListView items gets checked/unchecked. I know that there are (rather) ugly ways to achieve this with code behind and eventhandling, but I'd like to know if there's a clever way to do this maybe completely in XAML with arcane DataBinding syntax.
Edit: Just as an example/clarification: The ListView displays 100 items, 90 items have their boolean property set to true
, so the TextBlock will display '90'. If the user unchecks one more item through it's CheckBox and therefore sets it's property to false
through the Two-Way binding, the TextBlock should update to '89'.
Upvotes: 2
Views: 335
Reputation: 620
Thanks for all the answers I've got, these were all applicable solutions but unfortunately not really what I've tried to achieve. So this is how I've solved the problem now:
I've implemented a DependencyProperty on the Window containing the TextBlock:
public static readonly DependencyProperty ActiveItemCountProperty =
DependencyProperty.Register("ActiveItemCount", typeof(int), typeof(CustomControl), new UIPropertyMetadata(0));
On the DataTemplate for the ListView items the CheckBox registered an EventHandler for the Click-Event:
<CheckBox IsChecked="{Binding Active, Mode=TwoWay}" Click="CheckBox_Click" />
The event handler in code behind looks something like this:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
ObservableCollection<CustomClass> sourceCol = listView.DataContext as ObservableCollection<CustomClass>;
if (sourceCol != null)
ActiveItemCount = sourceCol.Count(x => x.Active);
}
And obviously, the TextBlock is just data bound to this DependencyProperty:
<TextBlock Text="{Binding Path=ActiveItemCount, ElementName=ControlRoot}" />
With ControlRoot being the name of the Window.
Upvotes: 0
Reputation: 35544
You could use a Converter to build up a string with the count of the checked items
public sealed class CountToStringConverter : System.Windows.Data.IValueConverter {
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
ObservableCollection<CustomClass> items = value as ObservableCollection<CustomClass>;
int count = 0;
foreach (var item in items) {
if (item.IsChecked) {
count++;
}
}
return count + " Items";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
#endregion
}
Bind the Text-Property of the TextBox to the Collection.
<TextBox Text={Binding Items, Converter={StaticResource countToStringConverter}}/>
UPDATE: This Binding works only if the Property Items fires the PropertyChanged-Event, if the Collection is changed.
Upvotes: 2
Reputation: 11608
Personally I would probably perform this in my ViewModel. Subscribe to the property changed on the items in the ObservableCollection, and then signal the Count property changed on the ViewModel whenever the boolean property changes. In your view simply bind to the Count property.
Upvotes: 2
Reputation: 71573
If it were a simple ASP.NET form, I'd look at using JQuery to count the selected items in the ListBox. That may still be a viable option in WPF:
var count = 0;
$('#multiItemListBox :selected').each(count++);
Plug this code into a JS event handler for the OnChange event of the ListBox. You'll have to know what the ListBox would actually be called in the HTML the client gets, and I'm not sure how WPF mashes them up or how to stick the correct reference into server-side XAML.
Upvotes: 0