HierarchicalDataTemplate 内的 DataTemplate

发布于 2024-09-08 18:07:42 字数 3729 浏览 7 评论 0原文

我需要构建一个自定义树视图作为用户控件。我将其称为 TreeViewEx 是为了示例 TreeViewEx :

<UserControl x:Class="WpfApplication4.TreeViewEx"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="root">
    <Grid>
        <TreeView ItemsSource="{Binding Path=ItemsSource, ElementName=root}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Node : "/>
                        <ContentControl Content="{Binding Path=AdditionalContent, ElementName=root}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</UserControl>

其想法是拥有 ItemTemplate 内容的固定部分和可自定义的部分。

当然,我在 TreeViewEx 类上创建了两个依赖属性:

public partial class TreeViewEx
{
    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
        "ItemsSource", typeof(IEnumerable), typeof(TreeViewEx));

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty AdditionalContentProperty = DependencyProperty.Register(
        "AdditionalContent", typeof(object), typeof(TreeViewEx));

    public object AdditionalContent
    {
        get { return GetValue(AdditionalContentProperty); }
        set { SetValue(AdditionalContentProperty, value); }
    }

    public TreeViewEx()
    {
        InitializeComponent();
    }
}

有一个像这样的简单节点类:

public class Node
{
    public string Name { get; set; }
    public int Size { get; set; }
    public IEnumerable<Node> Children { get; set; }
}

我将提供树视图。我将 TreeViewEx 的实例放在 WPF 测试项目的 MainWindow 上:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfApplication4">
    <Grid>
        <local:TreeViewEx x:Name="tree">
            <local:TreeViewEx.AdditionalContent>
                <TextBlock Text="{Binding Name}"/>
            </local:TreeViewEx.AdditionalContent>
        </local:TreeViewEx>
    </Grid>
</Window>

最后提供它:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        var dummyData = new ObservableCollection<Node>
        {
            new Node
            {
                Name = "Root", 
                Size = 3,
                Children = new ObservableCollection<Node>
                {
                    new Node{
                        Name="Child1",
                        Size=2,
                        Children = new ObservableCollection<Node>{
                            new Node{
                                Name = "Subchild", 
                                Size = 1
                            }

                        }
                    }

                }
            }
        };

        tree.ItemsSource = dummyData;
    }
}

但是它没有按预期工作,即首先 ContentControl 具有数据,但当我展开节点时,它不显示 ContentControl 的内容。

我真的不明白..我应该使用 DataTemplate 还是其他东西?

I needed to build a custom treeview as a user control. I called it for the sake of the example TreeViewEx :

<UserControl x:Class="WpfApplication4.TreeViewEx"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="root">
    <Grid>
        <TreeView ItemsSource="{Binding Path=ItemsSource, ElementName=root}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="Node : "/>
                        <ContentControl Content="{Binding Path=AdditionalContent, ElementName=root}"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</UserControl>

The idea is to have a fixed part of the content of the ItemTemplate and a customizable part of it.

Of course, I created two dependency properties on the TreeViewEx class :

public partial class TreeViewEx
{
    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
        "ItemsSource", typeof(IEnumerable), typeof(TreeViewEx));

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty AdditionalContentProperty = DependencyProperty.Register(
        "AdditionalContent", typeof(object), typeof(TreeViewEx));

    public object AdditionalContent
    {
        get { return GetValue(AdditionalContentProperty); }
        set { SetValue(AdditionalContentProperty, value); }
    }

    public TreeViewEx()
    {
        InitializeComponent();
    }
}

Having a simple node class like so :

public class Node
{
    public string Name { get; set; }
    public int Size { get; set; }
    public IEnumerable<Node> Children { get; set; }
}

I would feed the treeview. I place an instance of TreeViewEx on the MainWindow of a WPF test project :

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfApplication4">
    <Grid>
        <local:TreeViewEx x:Name="tree">
            <local:TreeViewEx.AdditionalContent>
                <TextBlock Text="{Binding Name}"/>
            </local:TreeViewEx.AdditionalContent>
        </local:TreeViewEx>
    </Grid>
</Window>

And finally feed it :

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        var dummyData = new ObservableCollection<Node>
        {
            new Node
            {
                Name = "Root", 
                Size = 3,
                Children = new ObservableCollection<Node>
                {
                    new Node{
                        Name="Child1",
                        Size=2,
                        Children = new ObservableCollection<Node>{
                            new Node{
                                Name = "Subchild", 
                                Size = 1
                            }

                        }
                    }

                }
            }
        };

        tree.ItemsSource = dummyData;
    }
}

However it doesn't work as expected namely at first the ContentControl has the data but as I expand the nodes it does not display the ContentControl's content.

I don't really get it.. I should use a DataTemplate or something else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笨死的猪 2024-09-15 18:07:42

问题是您将内容设置为控件的实例,并且该控件只能有一个父级。当您展开树并将其添加到第二个节点时,会将其从第一个节点中删除。

正如您所怀疑的,您想要向 TreeViewEx 提供 DataTemplate 而不是控件。您可以使用 ContentPresenter 在树的每个级别实例化模板:

将 AnotherContentProperty 替换为:

public static readonly DependencyProperty AdditionalContentTemplateProperty = DependencyProperty.Register(
    "AdditionalContentTemplate", typeof(DataTemplate), typeof(TreeViewEx));

public DataTemplate AdditionalContentTemplate
{
    get { return (DataTemplate)GetValue(AdditionalContentTemplateProperty); }
    set { SetValue(AdditionalContentTemplateProperty, value); }
}

将 UserControl 的 XAML 中的 HierarchicalDataTemplate 更改为:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="Node : "/>
    <ContentPresenter ContentTemplate="{Binding Path=AdditionalContentTemplate, ElementName=root}"/>
</StackPanel>

并将 MainWindow 更改为:

<local:TreeViewEx x:Name="tree">
    <local:TreeViewEx.AdditionalContentTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </local:TreeViewEx.AdditionalContentTemplate>
</local:TreeViewEx>

The problem is that you're setting the content to an instance of a control, and that control can only have one parent. When you expand the tree and it adds it to the second node, it removes it from the first one.

As you suspected, you want to supply a DataTemplate to TreeViewEx instead of a control. You can use a ContentPresenter to instantiate the template at each level of the tree:

Replace the AdditionalContentProperty with:

public static readonly DependencyProperty AdditionalContentTemplateProperty = DependencyProperty.Register(
    "AdditionalContentTemplate", typeof(DataTemplate), typeof(TreeViewEx));

public DataTemplate AdditionalContentTemplate
{
    get { return (DataTemplate)GetValue(AdditionalContentTemplateProperty); }
    set { SetValue(AdditionalContentTemplateProperty, value); }
}

change the HierarchicalDataTemplate in your UserControl's XAML to:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="Node : "/>
    <ContentPresenter ContentTemplate="{Binding Path=AdditionalContentTemplate, ElementName=root}"/>
</StackPanel>

and change MainWindow to:

<local:TreeViewEx x:Name="tree">
    <local:TreeViewEx.AdditionalContentTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </local:TreeViewEx.AdditionalContentTemplate>
</local:TreeViewEx>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文