简体   繁体   English

WPF 多绑定到 ObservableCollection 的一部分

[英]WPF MultiBinding to part of ObservableCollection

I need to set a TextBlock's Text to something like "Name (number of items with not null property)".我需要将 TextBlock 的文本设置为“名称(不具有 null 属性的项目数)”之类的内容。 Right now, I'm doing this using the number of items of the entire collection, using ItemsSource.Count.现在,我正在使用 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> 

For that I'm using an IMultiValueConverter:为此,我正在使用 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 is a DataGrid defined below (not showing code here), binded to the collection, which has TrackingData objects. trackingsGrid 是下面定义的 DataGrid(此处未显示代码),绑定到具有 TrackingData 对象的集合。 TrackingData has a property called Tracking. TrackingData 有一个名为 Tracking 的属性。 I need to count only the items in the ObservableCollection that has this property as not null.我只需要计算 ObservableCollection 中具有此属性的项目,而不是 null。 How can I achieve this?我怎样才能做到这一点?

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

Thanks in advance.提前致谢。

Put this logic (... items in the ObservableCollection that has this property as not null) in your ViewModel and bind to this property.将此逻辑(...项目在具有此属性的 ObservableCollection 中具有此属性不为空)在您的 ViewModel 中并绑定到此属性。

Personally, I would add this to the ViewModel, since it's so highly customized.就我个人而言,我会将它添加到 ViewModel 中,因为它是高度定制的。

That being said, you could make this work with a couple of minor tweaks.话虽如此,您可以通过一些小的调整来完成这项工作。 First, change your second binding from ItemsSource.Count to ItemsSource .首先,将您的第二个绑定从ItemsSource.Count更改为ItemsSource This will cause values[1] inside of your IMultiValueConverter to be the entire collection.这将导致IMultiValueConverter中的values[1]成为整个集合。

Once you've done this, your converter could change, so you report:完成此操作后,您的转换器可能会更改,因此您报告:

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() + ")";
}

I would suggest to avoid using MultiBinding unless it's totally necessary.我建议避免使用MultiBinding ,除非它是完全必要的。 It's hard to draw the line when it's necessary but usually you know when there are no other options to achieve desired behavior or alternative implementation requires significant efforts.在必要时很难划清界限,但通常您知道什么时候没有其他选择可以实现所需的行为,或者替代实现需要付出巨大的努力。 My gut tells me MultiBinding not only less efficient in terms of performance but it's also harder to read, test and maintain.我的直觉告诉我, MultiBinding不仅在性能方面效率较低,而且还更难阅读、测试和维护。

That said you could achieve your desired behavior through a property in your ViewModel (as @polishchuk suggests), or with binding to the whole view model and single converter that returns formatted string based on view model.也就是说,您可以通过 ViewModel 中的属性(如@polishchuk 建议的那样)或绑定到整个视图 model 和基于视图 model 返回格式化字符串的单个转换器来实现所需的行为。 Among two options I would prefer the first one if you don't need advanced text formatting, and the second one otherwise.在两个选项中,如果您不需要高级文本格式,我更喜欢第一个,否则,我更喜欢第二个。

As a couple of people have pointed out I would move this logic into the ViewModel.正如一些人指出的那样,我会将这个逻辑移到 ViewModel 中。 Here's one easy way to do so that doesn't require you to attach a bunch of event handlers and write custom logic:这是一种简单的方法,不需要您附加一堆事件处理程序并编写自定义逻辑:

One easy way to implement this in the ViewModel is to create an ICollectionView to wrap your source collection and applying a filter to it to include only values whose property is not null在 ViewModel 中实现这一点的一种简单方法是创建一个ICollectionView来包装您的源集合并对其应用过滤器以仅包含属性不是 null 的值

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

Then you could expose this ICollectionView through your ViewModel as a proprerty, say TrackedItems然后你可以通过你的 ViewModel 公开这个 ICollectionView 作为一个属性,比如TrackedItems

Then in XAML you can databind to TrackedItems.Count .然后在 XAML 中,您可以将数据绑定到TrackedItems.Count The ICollectionView will stay in sync as your TrackingData object properties change随着您的 TrackingData object 属性更改, ICollectionView将保持同步

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM