WPF MultiBinding к части ObservableCollection - PullRequest
1 голос
/ 04 июля 2011

Мне нужно установить TextBlock's Text на что-то вроде «Имя (количество элементов с ненулевым свойством)». Прямо сейчас я делаю это, используя количество элементов всей коллекции, используя 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, у которых это свойство не равно нулю. Как мне этого добиться?

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

Заранее спасибо.

Ответы [ 4 ]

2 голосов
/ 04 июля 2011

Поместите эту логику (... элементы в ObservableCollection, у которых это свойство имеет ненулевое значение) в вашу ViewModel и привяжите к этому свойству.

1 голос
/ 04 июля 2011

Лично я бы добавил это в ViewModel, так как он очень сильно настроен.

При этом, вы можете сделать это с помощью нескольких незначительных настроек.Сначала измените второе связывание с ItemsSource.Count на ItemsSource.Это заставит values[1] внутри вашего 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" />    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() + ")";
}
0 голосов
/ 05 июля 2011

Как отметили несколько человек, я бы переместил эту логику во ViewModel. Вот один простой способ сделать это, не требуя, чтобы вы прикрепляли кучу обработчиков событий и писали собственную логику:

Один из простых способов реализовать это во ViewModel - создать ICollectionView, чтобы обернуть исходную коллекцию и применить к ней фильтр, включающий только значения, свойство которых не равно нулю

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

Тогда вы можете представить этот ICollectionView через вашу ViewModel как свойство, скажем TrackedItems

Затем в XAML вы можете привязать данные к TrackedItems.Count. ICollectionView будет синхронизироваться при изменении свойств объекта TrackingData

0 голосов
/ 04 июля 2011

Я бы посоветовал избегать использования MultiBinding, если это не является абсолютно необходимым.Трудно провести черту, когда это необходимо, но обычно вы знаете, когда нет других вариантов для достижения желаемого поведения, или альтернативная реализация требует значительных усилий.Мой инстинкт подсказывает, что MultiBinding не только менее эффективен с точки зрения производительности, но и труднее читать, тестировать и поддерживать.

При этом вы можете достичь желаемого поведения с помощью свойства в вашей ViewModel (как @polishchukпредлагает), или с привязкой ко всей модели представления и одному конвертеру, который возвращает отформатированную строку на основе модели представления.Среди двух вариантов я бы предпочел первый, если вам не нужно расширенное форматирование текста, и второй вариант в противном случае.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...