Привязка дочерних узлов к CollectionViewSource - PullRequest
0 голосов
/ 15 мая 2019

Итак, вот моя структура данных:

MyViewModel
  Docs (ObservableCollection<Doc>)
    Specs (ObservableCollection<Spec>)

т.е. ViewModel имеет ObservableCollection с именем Docs, который является коллекцией Doc объектов, и в свою очередь каждый Doc объект имеет коллекцию Spec объектов. Свойство с именем position (доступно в классах Doc и Spec) сохраняет логическую позицию каждого документа / спецификации.

Теперь мне нужно связать эту структуру с TreeView. Мне нужно постоянно сортировать и Документы, и Спецификации (TreeView поддерживает перестановку узлов методом перетаскивания), поэтому прямая привязка здесь не работает.

Поэтому я использую CollectionViewSource для выполнения сортировки во время выполнения.

<CollectionViewSource x:Key="DocumentsCVS" Source="{Binding Docs}">
  <CollectionViewSource.SortDescriptions>
    <componentmodel:SortDescription PropertyName="position" />
  </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

и используйте его в моем TreeView:

<TreeView ItemsSource="{Binding Source={StaticResource DocumentsCVS}}">

Пока все хорошо. TreeView показывает мои документы отсортированы.

Но с этого момента все становится запутанным. Как / где я могу создать CollectionViewSource для моих спецификаций? Я попытался сделать это в моем HierarchicalDataTemplate:

<HierarchicalDataTemplate>
  <HierarchicalDataTemplate.ItemsSource>
    <Binding>
      <Binding.Source>
        <CollectionViewSource Source="{Binding Specs}">
          <CollectionViewSource.SortDescriptions>
            <componentmodel:SortDescription PropertyName="position" />
          </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
      </Binding.Source>
    </Binding>
  </HierarchicalDataTemplate.ItemsSource>
</HierarchicalDataTemplate>    

Но это не работает. В TreeView указаны только документы, без детей внутри. У меня такое ощущение, что CollectionViewSource, вероятно, не живет в том же DataContext, что и родитель TreeViewItem.

Или это что-то еще?

Редактировать

Вот полный XAML моего TreeView:

<TreeView ItemsSource="{Binding Source={StaticResource DocumentsCVS}}" 
           PresentationTraceSources.TraceLevel="High">

  <TreeView.ItemTemplate>
    <HierarchicalDataTemplate DataType="{x:Type vm:DocumentVM}">
      <HierarchicalDataTemplate.ItemsSource>
        <Binding>
          <Binding.Source>
            <CollectionViewSource Source="{Binding Specs}">
          <CollectionViewSource.SortDescriptions>
            <componentmodel:SortDescription PropertyName="position" />
          </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
          </Binding.Source>
        </Binding>
      </HierarchicalDataTemplate.ItemsSource>
      <HierarchicalDataTemplate.ItemTemplate>
        <DataTemplate DataType="{x:Type vm:SpecVM}">
          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <fa:ImageAwesome Grid.Column="0" Icon="PuzzlePiece" Width="16" Margin="3,3,6,3" Foreground="Orange" />
            <Label Grid.Column="1" Content="{Binding name}" />
          </Grid>
        </DataTemplate>
      </HierarchicalDataTemplate.ItemTemplate>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <fa:ImageAwesome Icon="FileWordOutline" Height="16" Margin="3,3,6,3" Foreground="Crimson" />
        <Label Grid.Column="1" Content="{Binding name}" />
      </Grid>
    </HierarchicalDataTemplate>
  </TreeView.ItemTemplate>
</TreeView>

1 Ответ

1 голос
/ 15 мая 2019
<CollectionViewSource Source="{Binding Specs}">

Привязка к источнику не знает, где искать DataContext (без «наставника фреймворка»).Я пнул это немного.Я не могу найти место для определения CollectionViewSource, где он наследует DataContext из шаблона.

Я нашел решение.

C #

public class SortConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var view = CollectionViewSource.GetDefaultView(value);
        view.SortDescriptions.Add(new SortDescription((string)parameter, ListSortDirection.Ascending));
        return view;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML

<HierarchicalDataTemplate 
    DataType="{x:Type vm:DocumentVM}" 
    ItemsSource="{Binding Specs, Converter={StaticResource SortConverter}, ConverterParameter=position}"
    >

Это можно сделать более полезным, предоставив конвертеру несколько свойств PropertyName / SortDirection или коллекцию SortDescription.Вы можете сделать это MarkupExtension.Вы также можете просто создать представление коллекции в свойстве viewmodel.

...