XAML Avalonia TreeView模板选择器

m3eecexj  于 2023-06-19  发布在  其他
关注(0)|答案(1)|浏览(263)

我尝试过在TreeView中使用模板选择器(请参阅此项目:https://github.com/imekon/AvaloniaTreeViewTemplate
它创建了一个树,但节点不再有箭头,以允许我看到子节点。
这是我使用的XAML:

<TreeView Items="{Binding Things}">
    <TreeView.Items>
        <scg:List x:TypeArguments="vm:ThingViewModel">
            <vm:ThingViewModel Template="Folder"/>
            <vm:ThingViewModel Template="Thing"/>
        </scg:List>
    </TreeView.Items>
    <TreeView.DataTemplates>
        <helpers:ThingTemplateSelector>
            <TreeDataTemplate x:Key="Folder" ItemsSource="{Binding Children}">
                <TextBlock Text="{Binding Name}"/>
            </TreeDataTemplate>
            <TreeDataTemplate x:Key="Thing">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Address}"/>
                </StackPanel>
            </TreeDataTemplate>
        </helpers:ThingTemplateSelector>
    </TreeView.DataTemplates>
</TreeView>

这是选择器:

public class ThingTemplateSelector : IDataTemplate
{
    public bool SupportsRecycling => false;

    [Content]
    public Dictionary<string, IDataTemplate> Templates { get; } = new Dictionary<string, IDataTemplate>();

    public IControl Build(object data)
    {
        return Templates[((ThingViewModel)data).Template].Build(data);
    }

    public bool Match(object data)
    {
        return data is ThingViewModel;
    }
}

如果我使用一个简单的TreeDataTemplate,我可以让一个树视图工作,但是我不能让它为条目类型(“事物”或“文件夹”)选择正确的模板。所有节点都是一种类型。
现在的阿瓦隆尼亚能做到吗?

上图显示了“Thing”节点,但旁边没有箭头。单击它只会选择项目,但不能展开它以查看子节点。

ehxuflar

ehxuflar1#

我最终通过让选择器实现ITreeDataTemplate而不是IDataTemplate来实现这一点。这让我有机会动态调用正确的ItemsSelector:

public class AddressTreeTemplateSelector : ITreeDataTemplate
{
    [Content]
    public Dictionary<string, IDataTemplate> AvailableTemplates { get; } = new Dictionary<string, IDataTemplate>();

    public InstancedBinding ItemsSelector(object item)
    {
        if (item is Address addr)
        {
            // decide which template's ItemSelector to call 
            string key = addr.IsSingleUnit ? "AddressSingle" : "AddressMulti";
            return ((TreeDataTemplate)AvailableTemplates[key]).ItemsSelector(item); 
        }
        else
            return null;
    }

    // Check if we can accept the provided data
    public bool Match(object data)
    {
        return (data is Address);
    }

    // Build the DataTemplate here
    Control? ITemplate<object?, Control?>.Build(object? param)
    {
        string key = param.GetType().Name;
        // decide which template to build and return
        if (param is Address addr)
            key = addr.IsSingleUnit ? "AddressSingle" : "AddressMulti";
        else
            throw new KeyNotFoundException(nameof(AddressTreeTemplateSelector) + ": Invalid key: " + key);

        if (key is null) // If the key is null, we throw an ArgumentNullException
        {
            throw new ArgumentNullException(nameof(param));
        }
        return AvailableTemplates[key].Build(param); // finally we look up the provided key and let the System build the DataTemplate for us
    }
}

使用以下Xaml:

<local:AddressTreeTemplateSelector>
    <TreeDataTemplate x:Key="AddressMulti" DataType="obj:Address" ItemsSource="{Binding Units}">
        <StackPanel Orientation="Horizontal">
            <Image Source="/Assets/tree_Address.png" />
            <TextBlock Margin="5,0,0,0"  Text="{Binding FullAddress}" />
        </StackPanel>
    </TreeDataTemplate>
                            
    <TreeDataTemplate x:Key="AddressSingle" DataType="obj:Address" ItemsSource="{Binding FirstUnitLocations}">
        <StackPanel Orientation="Horizontal">
            <Image Source="/Assets/tree_MiniAddress.png" />
            <TextBlock Margin="5,0,0,0" Text="{Binding FullAddress}"/>
        </StackPanel>
    </TreeDataTemplate>
</local:AddressTreeTemplateSelector>

相关问题