WPF多重绑定到ObservableCollection的一部分

本文关键字:ObservableCollection 一部分 绑定 WPF | 更新日期: 2023-09-27 18:01:12

我需要将TextBlock的Text设置为类似"Name(非null属性的项数("的内容。现在,我使用整个集合的项数,使用ItemsSource.Count.

<TextBlock x:Name="textBlockHeader" >
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource headerCreator}" x:Name="multiBinder">
            <Binding ElementName="trackingTable" Path="Name" />
            <Binding ElementName="trackingsGrid" Path="ItemsSource.Count" />
        </MultiBinding>
    </TextBlock.Text>
</TextBlock> 

为此,我使用了一个IMultiValueConverter:

internal class HeaderCreator : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // Based on this xaml
        ////<Binding ElementName="trackingTable" Path="Name" />                 values[0]
        ////<Binding ElementName="trackingsGrid" Path="ItemsSource.Count" />    values[1]
        return values[0] + " (" + values[1] + ")";
    }

trackingsGrid是下面定义的DataGrid(此处不显示代码(,绑定到具有TrackingData对象的集合。TrackingData有一个名为Tracking的属性。我只需要将ObservableCollection中具有此属性的项计数为非null。我怎样才能做到这一点?

public class TrackingData : INotifyPropertyChanged
{
    public Model.ITracking Tracking { get; set; }
    ...
}

提前谢谢。

WPF多重绑定到ObservableCollection的一部分

将此逻辑(…ObservableCollection中具有非null属性的项(放入ViewModel中并绑定到此属性。

就我个人而言,我会将其添加到ViewModel中,因为它是高度定制的。

话虽如此,你可以通过一些小的调整来实现这一点。首先,将第二个绑定从ItemsSource.Count更改为ItemsSource。这将导致IMultiValueConverter中的values[1]成为整个集合。

一旦你这样做了,你的转换器可能会改变,所以你报告:

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    // Based on this xaml
    ////<Binding ElementName="trackingTable" Path="Name" />                 values[0]
    ////<Binding ElementName="trackingsGrid" Path="ItemsSource" />    values[1]
    IEnumerable<TrackingData> tracking = values[1] as IEnumerable<TrackingData>;
    if(tracking == null)
       return values[0] + " (0)"; // Put some reasonable value here?
    return values[0] + " (" + tracking.Where(t => t.Tracking != null).Count() + ")";
}

我建议避免使用MultiBinding,除非完全必要。在必要的时候很难划清界限,但通常你知道什么时候没有其他选择来实现所需的行为,或者替代实施需要付出巨大的努力。我的直觉告诉我MultiBinding不仅在性能方面效率较低,而且更难阅读、测试和维护。

也就是说,你可以通过ViewModel中的一个属性(正如@polishchuk所建议的(,或者通过绑定到整个视图模型和单个转换器来实现你想要的行为,该转换器返回基于视图模型的格式化字符串。在两个选项中,如果你不需要高级文本格式,我更喜欢第一个,否则我更喜欢第二个。

正如一些人所指出的,我将把这个逻辑移到ViewModel中。这里有一种简单的方法,不需要附加一堆事件处理程序和编写自定义逻辑:

在ViewModel中实现这一点的一个简单方法是创建一个ICollectionView来包装源集合,并对其应用过滤器以仅包括属性不是null 的值

IList<T> source = ...
ListCollectionView customView = new ListCollectionView(source);
customView.Filter = obj => ((TrackingData)obj).Tracking != null;

然后,您可以通过ViewModel将此ICollectionView作为proprerty公开,例如TrackedItems

然后在XAML中,您可以数据绑定到TrackedItems.Count。当TrackingData对象属性更改时,ICollectionView将保持同步