TransferValue — неявный преобразователь, созданный в элементе TreeView ItemsSource

#c# #wpf #mvvm #treeview #reactiveui

Вопрос:

По какой-то причине значение создается правильно, а затем отклоняется каким-то «неявным преобразователем», и я не могу понять, почему. Вот краткий обзор кода, но сначала сообщения о диагностике:

 System.Windows.Data Warning: 95 : BindingExpression (hash=63646052): Got PropertyChanged event from MainViewModel (hash=17472816)
System.Windows.Data Warning: 101 : BindingExpression (hash=63646052): GetValue at level 0 from MainViewModel (hash=17472816) using RuntimePropertyInfo(TestNodeRoot): HierarchicalTestNode (hash=53650690)
System.Windows.Data Warning: 80 : BindingExpression (hash=63646052): TransferValue - got raw value HierarchicalTestNode (hash=53650690)
System.Windows.Data Warning: 84 : BindingExpression (hash=63646052): TransferValue - implicit converter produced <null>
System.Windows.Data Warning: 89 : BindingExpression (hash=63646052): TransferValue - using final value <null>
 

Далее идет привязка древовидного представления. Трассировка включена, как вы можете видеть:

     <TreeView ItemsSource="{Binding TestNodeRoot, diag:PresentationTraceSources.TraceLevel=High}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type models:HierarchicalTestNode}" ItemsSource="{Binding Children, diag:PresentationTraceSources.TraceLevel=High}">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
 

TestNodeRoot Привязка выполняется к ObservableAsPropertyHelper<HierarchicalTestNode?> модели представления, которая связана с изменением Solution свойства (обратите внимание, что это работает, потому что привязка получает это значение, как показано выше).:

     readonly ObservableAsPropertyHelper<HierarchicalTestNode?> testNodeRoot;
    public HierarchicalTestNode? TestNodeRoot => testNodeRoot.Value;

    this.WhenAnyValue(x => x.Solution).Select(s => s is null ? null : HierarchicalTestNode.Create(s.TestNodes!))
        .ToProperty(this, x => x.TestNodeRoot, out testNodeRoot);
 

И , наконец HierarchicalTestNode , это простое ReactiveObject , содержащее свойства (обратите Children внимание, что свойство является наблюдаемой коллекцией, как и ожидалось в XAML HierarchicalDataTemplate , хотя я туда не попал):

 public class HierarchicalTestNode : ReactiveObject
{
    string name;
    public string Name { get => name; set => this.RaiseAndSetIfChanged(ref name, value); }

    bool cloak;
    public bool Cloak { get => cloak; set => this.RaiseAndSetIfChanged(ref cloak, value); }

    int displayIndex;
    public int DisplayIndex { get => displayIndex; set => this.RaiseAndSetIfChanged(ref displayIndex, value); }

    TestNodeType nodeType;
    public TestNodeType NodeType { get => nodeType; set => this.RaiseAndSetIfChanged(ref nodeType, value); }

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

    // other stuff for creating it from a flat database, this also works
}
 

Итак, есть идеи, что пытается сделать этот внутренний конвертер? Я не думаю TreeView , что он ожидает какого-либо определенного класса из того, что я видел в Интернете, и я не передаю интерфейсы (я читал, что это может вызвать проблемы), так в чем дело?

Комментарии:

1. Привязка ItemsSource ожидает свойство источника, которое является IEnumerable или может быть преобразовано в IEnumerable. Верно ли это для HierarchicalTestNode, т. Е. для привязки ItemsSource к просмотру дерева? Или вы намеревались написать ItemsSource="{Binding TestNodeRoot.Children}" ?

2. О, чувак, я знал, что это должно быть что-то глупое… Нет, идея состояла в том, чтобы иметь дерево с одним корневым узлом. Позвольте мне быстро попробовать, но вы, скорее всего, правы.

Ответ №1:

Как отметил Клеменс в своем комментарии, проблема в том, что, хотя у меня есть только один корневой узел, ItemsSource свойство ожидает перечисления. Преобразование корня в массив из одного элемента решило мою проблему.