如何以最优雅的方式将DataBind绑定到ItemsControl中的特定项属性?

时间:2010-09-08 22:07:28

标签: c# .net wpf silverlight

场景: ListView是DataBound到ObservableCollection<CustomClass>,并通过自定义ItemTemplate显示它的项目。 CustomClass只包含三个字符串属性和一个布尔属性,并且已经在其四个属性中的每一个上实现了INotifyPropertyChanged。 ListView的自定义ItemTemplate在三个字符串属性上具有单向绑定,在布尔属性上具有双向绑定,将其显示为CheckBox。

问题:我正在寻找最优雅的(就WPF而言)使用TextBlock显示该ListView中所有已检查项目的计数 - 或换句话说,所有项目将其布尔属性设置为该集合中的true。如果其中一个ListView项被选中/取消选中,我希望TextBlock立即更新显示的计数。我知道有一些(相当)丑陋的方法可以通过代码隐藏和事件处理实现这一点,但我想知道是否有一种聪明的方法可以完全在XAML中使用神秘的DataBinding语法来实现这一点。

编辑:作为示例/澄清:ListView显示100个项目,90个项目的布尔属性设置为true,因此TextBlock将显示“90”。如果用户通过它的CheckBox取消选中另一个项目,并因此通过双向绑定将其属性设置为false,则TextBlock应更新为'89'。

4 个答案:

答案 0 :(得分:2)

您可以使用转换器构建一个包含已检查项目数的字符串

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
}

将TextBox的Text-Property绑定到Collection。

<TextBox Text={Binding Items, Converter={StaticResource countToStringConverter}}/>

<强>更新 仅当属性项触发PropertyChanged-Event时,如果更改了Collection,此Binding才有效。

答案 1 :(得分:2)

我个人可能会在我的ViewModel中执行此操作。订阅ObservableCollection中项目更改的属性,然后每当布尔属性更改时,都会在ViewModel上发送更改的Count属性。在您的视图中,只需绑定到Count属性。

答案 2 :(得分:0)

如果它是一个简单的ASP.NET表单,我会看看使用JQuery来计算ListBox中的选定项。这可能仍然是WPF中可行的选择:

var count = 0;
$('#multiItemListBox :selected').each(count++);

将此代码插入到ListBox的OnChange事件的JS事件处理程序中。您将不得不知道客户端获取的HTML实际上会调用ListBox,我不确定WPF如何将它们混淆或如何将正确的引用粘贴到服务器端XAML中。

答案 3 :(得分:0)

感谢我所得到的所有答案,这些都是适用的解决方案,但不幸的是,这并不是我试图实现的目标。所以这就是我现在解决问题的方法:

我在包含TextBlock的窗口上实现了DependencyProperty:

public static readonly DependencyProperty ActiveItemCountProperty =
        DependencyProperty.Register("ActiveItemCount", typeof(int), typeof(CustomControl), new UIPropertyMetadata(0));

在ListView项的DataTemplate上,CheckBox为Click-Event注册了一个EventHandler:

<CheckBox IsChecked="{Binding Active, Mode=TwoWay}" Click="CheckBox_Click" />

代码隐藏中的事件处理程序如下所示:

    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);
    }

显然,TextBlock只是绑定到此DependencyProperty的数据:

<TextBlock Text="{Binding Path=ActiveItemCount, ElementName=ControlRoot}" />

使用ControlRoot作为Window的名称。