WPF TreeView 不显示箭头,除非我在运行时修改样式

WPF TreeView doesn't display arrows unless I modify styling during runtime

我有一个在运行时填充的 ObservableCollection,它绑定到 TreeView。更新集合时,集合的根 object 出现在 TreeView 中,无法展开它(见第一张图片)。

我认为这意味着绑定存在问题,但是,删除 TreeView.ItemCotainerStyle 标记会使箭头出现并且一切都按预期工作(参见第二张图片)。此行为也反向工作,如果样式标签不在视图中并且我在更新集合后添加它,那么箭头将出现。

样式标签对于我的项目中的任何功能来说都不是必需的,它们只是我正在处理的示例中遗留下来的。

<TreeView ItemsSource="{Binding CompileMessages}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded"
                    Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected"
                    Value="{Binding IsSelected, Mode=TwoWay}" />
            <Setter Property="FontWeight"
                    Value="Normal" />
        </Style>
    </TreeView.ItemContainerStyle>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type models:CompileMessagesDto}"
                                  ItemsSource="{Binding Path=Children}">
            <StackPanel Orientation="Horizontal">
                <materialDesign:PackIcon Kind="{Binding Path=State}"
                                         Margin="3"
                                         Foreground="White" />
                <TextBlock Text="{Binding Path=Path}"
                           FontWeight="Normal"
                           Foreground="White"
                           FontSize="12"
                           Margin="3" />
                <TextBlock Text="{Binding Path=Description}"
                           FontWeight="Normal"
                           FontSize="12"
                           Foreground="#ff8000"
                           Margin="3" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>
public class CompileMessagesDto
{
    public string State { get; set; } = "";
    public string Path { get; set; } = "";
    public string Description { get; set; } = "";
    public string Parent { get; set; }

    public ObservableCollection<CompileMessagesDto> Children { get; set; } = new ObservableCollection<CompileMessagesDto>();
}

TreeView before modification

TreeView after removing the style tag

用测试值初始化集合会显示箭头,只有在运行时修改集合后,TreeView 才会表现得像这样。如果有帮助,我会使用 MaterialDesignInXaml

编辑(集合的更新方式)

这绝对不是最好的方法,但我遍历了编译器消息的集合并将它们添加到集合中。我只剩下每个 object 和对他们 parent.

的引用
foreach (CompilerResultMessage message in messages)
{
    CompileMessagesDto compileMessage = new CompileMessagesDto { State = message.State.ToString(), Path = message.Path, Description = message.Description, Parent = parent };

    MessageCrawl(message.Messages, message.Path);

    CompileMessages.Add(compileMessage);
}

然后我设置每个 object 的 children,并从集合中删除不是根 object 的每个 object。留下带有 children 树的根。

List<CompileMessagesDto> removeItems = new List<CompileMessagesDto>();

foreach (CompileMessagesDto message in CompileMessages)
{
    message.Children = new ObservableCollection<CompileMessagesDto>(CompileMessages.Where(c => c.Parent == message.Path));

    if (message.Parent != "Root") { removeItems.Add(message); }
}

foreach (CompileMessagesDto message in removeItems)
{
    CompileMessages.Remove(message);
}

您正在覆盖绑定源 CompileMessagesDto.Children:

message.Children = new ObservableCollection<CompileMessagesDto>(...);

由于 CompileMessagesDto 未实现 INotifyProeprtyChangedBinding 将无法识别 属性 更改。

数据绑定的一般规则:如果源是 DependencyObject 的子类,则绑定源必须始终将其属性实现为 DependencyProperty。否则源对象必须实现 INotifyPropertyChanged.
如果不这样做,您将造成潜在的内存泄漏。

要解决您的问题,请让 CompileMessagesDto 实施 INotifyPropertyChanged 并从 CompileMessagesDto.Children 属性 引发 PropertyChanged 事件(推荐的解决方案)。

或者保留当前的 ​​ObservableCollection 实例并使用 AddRemove 对其进行修改。

// Using for-statement allows to get rid of the 'removedItems' collection and the second foreach-statement (improve performance)
for (int index = CompileMessages.Count - 1; index >= 0; index--)
{
  CompileMessages
    .Where(c => c.Parent == message.Path)
    .ToList()
    .ForEach(message.Children.Add);

  if (message.Parent != "Root") 
  { 
    CompileMessages.Remove(message); 
  }
}

另请注意,您的 Style 确实会引发错误。 CompileMessagesDto 既没有 IsExpanded 也没有 IsSelected 属性.