将 child 个节点绑定到 CollectionViewSource

Binding child nodes to CollectionViewSource

所以这是我的数据结构:

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

即ViewModel 有一个名为 DocsObservableCollection,它是 Doc object 的集合,而每个 Doc object 都有一个集合Spec object秒。名为 position 的 属性(在 Doc 和 Spec 类 中均可用)存储每个 doc/spec.

的逻辑位置

我现在需要将此结构绑定到 TreeView。我需要始终保持 Docs 和 Specs 排序(TreeView 支持 drag-n-drop 重新排列节点),因此直接绑定在这里不起作用。

因此我使用 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 显示我的文档已排序。

但从这里开始,事情就变得扑朔迷离了。 How/where 我要为我的规格创建 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 中只列出了 Docs,里面没有 children。我的直觉是 CollectionViewSource 可能不和 parent TreeViewItem.

住在同一个 DataContext

或者这是别的东西?

编辑

这是我的 TreeView 的完整 XAML:

<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>
<CollectionViewSource Source="{Binding Specs}">

Source 上的绑定不知道去哪里寻找 DataContext(没有 "framework mentor")。我已经解决了这个问题。我找不到一个地方来定义 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 属性或一组 SortDescriptions 来变得更有用。您可以将其设为 MarkupExtension。您也可以只在视图模型中创建集合视图 属性。