HierarchicalDataTemplate and HeaderedItemsControl

2019-03-22 06:32发布

I can get this pattern to work with Menu and TreeView but I must be missing something when I make an attempt with HeaderedItemsControl:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>

    <HierarchicalDataTemplate x:Key="MenuItemTemplate" ItemsSource="{Binding XPath=foo}">
        <AccessText Text="{Binding XPath=@a}" />
    </HierarchicalDataTemplate>

    <Style TargetType="HeaderedItemsControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
                    <StackPanel>
                        <ContentPresenter ContentSource="Header"/>
                        <ItemsPresenter Margin="10,0,0,0" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <XmlDataProvider x:Key="RootXml" XPath="/root/foo">
        <x:XData>
            <root xmlns="">
                <foo a="one">
                    <foo a="two" b="wow, two" />
                    <foo a="three" b="wow, three" />
                    <foo a="four" b="wow, four" />
                </foo>
                <foo a="one again">
                    <foo a="two others" b="wow, two others" />
                    <foo a="three the hard way" b="wow, three again" />
                </foo>
            </root>
        </x:XData>
    </XmlDataProvider>

</Page.Resources>

<StackPanel>
    <HeaderedItemsControl
        Header="My Foo List"
        ItemTemplate="{Binding Source={StaticResource MenuItemTemplate}}"
        ItemsSource="{Binding Source={StaticResource RootXml}}">
    </HeaderedItemsControl>
</StackPanel>
</Page>

In XamlPadX, this shows:

My foo list
    one
    one again

Do I need to do something with the ControlTemplate to get the data to display correctly? Or do I need a more elaborate (or an additional) HierarchicalDataTemplate? Also: how do we show the foo/@b data?

3条回答
Explosion°爆炸
2楼-- · 2019-03-22 06:47

This seems to be the deal:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>

    <XmlDataProvider x:Key="RootXml" XPath="/root/foo">
        <x:XData>
            <root xmlns="">
                <foo a="one" b="test1">
                    <foo a="two" b="wow, two" />
                    <foo a="three" b="wow, three" />
                    <foo a="four" b="wow, four" />
                </foo>
                <foo a="one again" b="test2">
                    <foo a="two others" b="wow, two others" />
                    <foo a="three the hard way" b="wow, three again" />
                </foo>
            </root>
        </x:XData>
    </XmlDataProvider>

    <Style TargetType="HeaderedItemsControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type HeaderedItemsControl}">
                    <StackPanel>
                        <ContentPresenter ContentSource="Header"/>
                        <ItemsPresenter Margin="10,0,0,0" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <HierarchicalDataTemplate x:Key="NestedFooItemTemplate">
        <AccessText Text="{Binding XPath=@b}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="FooItemTemplate">
        <StackPanel>
            <AccessText Text="{Binding XPath=@a}" />
            <HeaderedItemsControl
                Header="My Nest"
                ItemTemplate="{Binding Source={StaticResource NestedFooItemTemplate}}"
                ItemsSource="{Binding XPath=./foo}"
                Margin="10,0,0,0" />
        </StackPanel>
    </HierarchicalDataTemplate>

</Page.Resources>

<StackPanel>
    <HeaderedItemsControl
        Header="My Foo List"
        ItemTemplate="{Binding Source={StaticResource FooItemTemplate}}"
        ItemsSource="{Binding Source={StaticResource RootXml}}">
    </HeaderedItemsControl>
</StackPanel>
</Page>
查看更多
爷、活的狠高调
3楼-- · 2019-03-22 06:55

Here is a late answer. Been trying to figure this out as well, but was not satisfied with the reasoning in the above answer and/or the linked answer, as the XAML pattern should be the same between all controls.

After a bit of time with jetbrains dotPeek, and combing thought the TreeView Control the answer is finally quite simple. The TreeView and TreeViewItem override IsItemItsOwnContainerOverride and GetContainerForItemOverride to the control which will hold the children (TreeViewItem in the TreeView Case). You can create two simple custom controls to handle this.

Your HeaderedItemControl class would be something like this:

public class MyHierarchicalViewItem : HeaderedItemsControl
{
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is MyHierarchicalViewItem;
    }

    protected override DependencyObject GetContainerForItemOverride()
    {
        return (DependencyObject)new MyHierarchicalViewItem();
    }
}

Your ItemControl (Equivalent to the TreeView or Menu) would be this:

public class MyHierarchicalView:ItemsControl 
{
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is MyHierarchicalViewItem;
    }

    protected override DependencyObject GetContainerForItemOverride()
    {

        return (DependencyObject) new MyHierarchicalViewItem();
    }
}

Your XAML would be largely the same, just putting referencing the correct control and adding the appropriate namespace (my case xmlns:myControls="clr-namespace:").

<UserControl.Resources>

        <HierarchicalDataTemplate x:Key="MenuItemTemplate" ItemsSource="{Binding XPath=foo}">
            <AccessText Text="{Binding XPath=@a}" />
        </HierarchicalDataTemplate>

        <Style TargetType="{x:Type myControls:MyHierarchicalViewItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type myControls:MyHierarchicalViewItem}">
                        <StackPanel>
                            <ContentPresenter ContentSource="Header"/>
                            <ItemsPresenter Margin="10,0,0,0" />
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <XmlDataProvider x:Key="RootXml" XPath="/root/foo">
            <x:XData>
                <root xmlns="">
                    <foo a="one">
                        <foo a="two" b="wow, two" />
                        <foo a="three" b="wow, three" />
                        <foo a="four" b="wow, four" />
                    </foo>
                    <foo a="one again">
                        <foo a="two others" b="wow, two others" />
                        <foo a="three the hard way" b="wow, three again" />
                    </foo>
                </root>
            </x:XData>
        </XmlDataProvider>

        </UserControl.Resources>

    <StackPanel>
        <myControls:MyHierarchicalViewItem
        Header="My Foo List"
        ItemTemplate="{Binding Source={StaticResource MenuItemTemplate}}"
        ItemsSource="{Binding Source={StaticResource RootXml}}">
        </myControls:MyHierarchicalViewItem>
    </StackPanel>

</UserControl>
查看更多
Ridiculous、
4楼-- · 2019-03-22 07:00

HierarchicalDataTemplate is for tree views which have automatic child element expansion. In your case you can simply use a normal DataTemplate.

查看更多
登录 后发表回答