如何使用 HierarchicalDataTemplate 显示 XML 元素和属性?

发布于 2024-12-07 22:48:55 字数 3453 浏览 0 评论 0原文

我想在 TreeView 中显示任意 XML,其中包含展开和折叠节点,显示元素名称和属性集及其值。我想我可以用 HierarchicalDataTemplate 来做到这一点。

我已经看到了使用 HierarchicalDataTemplate 显示任意 XML 元素 和文本节点的提示,如下所示:

  <Window.Resources>
    <HierarchicalDataTemplate x:Key="NodeTemplate">
      <TextBlock x:Name="tbName" Text="?" />
      <HierarchicalDataTemplate.ItemsSource>
        <Binding XPath="child::node()" />
      </HierarchicalDataTemplate.ItemsSource>
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
    <XmlDataProvider x:Key="xmlDataProvider">
    </XmlDataProvider>
  </Window.Resources>
  ....

  <TreeView Name="treeView1"
          ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}"
          ItemTemplate= "{StaticResource NodeTemplate}"/>

效果很好。它显示每个元素的元素名称和文本。但我的 XML 使用属性来携带信息。该架构很复杂,而且我没有对其进行正式定义,因此现在我将其视为任意 XML。

最简单的文档如下所示:

<c4soap name="GetVersionInfo" seq="" result="1">
  <versions>
    <version name="Director" 
             version="2.1.0.126418" 
             buildtype="" 
             builddate="Jun  1 2011" buildtime="14:52:43" />
    <version name="MediaManager" 
             version="2.1.0.126418" 
             buildtype="" 
             builddate="Jun  1 2011" 
             buildtime="14:36:17" />
  </versions>
</c4soap>

使用上面的 HierarchicalDataTemplate 定义,我得到这样的显示:

在此处输入图像描述

不完全是我想要什么。对于每个节点,我想显示元素名称和属性集及其值。

我尝试过这个:

  <Window.Resources>
    <HierarchicalDataTemplate x:Key="NodeTemplate">
      <WrapPanel
          Focusable="False">
        <TextBlock x:Name="tbName" Text="?" />
        <TextBlock x:Name="tbAttrs" Text="?" />
      </WrapPanel>
      <HierarchicalDataTemplate.ItemsSource>
        <Binding XPath="child::node()" />
      </HierarchicalDataTemplate.ItemsSource>
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
          <Setter TargetName="tbAttrs" Property="Text" Value="{Binding Path=Attributes}"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
    <XmlDataProvider x:Key="xmlDataProvider">
    </XmlDataProvider>
  </Window.Resources>

...这让我有点接近,但是 Value="{Binding Path=Attributes}" 导致在 TreeView 中显示“(Collection)”。

在此处输入图像描述

除了元素名称之外,如何简单地显示所有实际属性名称和值?

I'd like to display arbitrary XML in a TreeView, with expanding and collapsing nodes, showing both the element name and the set of attributes and their values. I think I can do this with HierarchicalDataTemplate .

I've seen the hints to use HierarchicalDataTemplate to display arbitrary XML elements, and text nodes, like this:

  <Window.Resources>
    <HierarchicalDataTemplate x:Key="NodeTemplate">
      <TextBlock x:Name="tbName" Text="?" />
      <HierarchicalDataTemplate.ItemsSource>
        <Binding XPath="child::node()" />
      </HierarchicalDataTemplate.ItemsSource>
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
    <XmlDataProvider x:Key="xmlDataProvider">
    </XmlDataProvider>
  </Window.Resources>
  ....

  <TreeView Name="treeView1"
          ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}"
          ItemTemplate= "{StaticResource NodeTemplate}"/>

Which works great. It displays the element names and text for each element. But my XML uses attributes to carry information. The schema is complex and I don't have a formal definition of it, so for now I am treating it as arbitrary XML.

The simplest document looks like this:

<c4soap name="GetVersionInfo" seq="" result="1">
  <versions>
    <version name="Director" 
             version="2.1.0.126418" 
             buildtype="" 
             builddate="Jun  1 2011" buildtime="14:52:43" />
    <version name="MediaManager" 
             version="2.1.0.126418" 
             buildtype="" 
             builddate="Jun  1 2011" 
             buildtime="14:36:17" />
  </versions>
</c4soap>

Using the above HierarchicalDataTemplate definition, I get this for a display:

enter image description here

Not quite what I want. For each node I want to display both the element name and the set of attributes and their values.

I tried this:

  <Window.Resources>
    <HierarchicalDataTemplate x:Key="NodeTemplate">
      <WrapPanel
          Focusable="False">
        <TextBlock x:Name="tbName" Text="?" />
        <TextBlock x:Name="tbAttrs" Text="?" />
      </WrapPanel>
      <HierarchicalDataTemplate.ItemsSource>
        <Binding XPath="child::node()" />
      </HierarchicalDataTemplate.ItemsSource>
      <HierarchicalDataTemplate.Triggers>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
          <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
          <Setter TargetName="tbAttrs" Property="Text" Value="{Binding Path=Attributes}"/>
        </DataTrigger>
      </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
    <XmlDataProvider x:Key="xmlDataProvider">
    </XmlDataProvider>
  </Window.Resources>

... which gets me kinda close, but the
Value="{Binding Path=Attributes}" results in a display of "(Collection)" in the TreeView.

enter image description here

How can I simply display all the actual attribute names and values, in addition to the element name?

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

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

发布评论

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

评论(2

鲜血染红嫁衣 2024-12-14 22:48:55

我在模板中添加了一个 ItemsControl ,如下所示:

<Window.Resources>
  <SolidColorBrush x:Key="xmlValueBrush" Color="Blue" />
  <SolidColorBrush x:Key="xmAttributeBrush" Color="Red" />
  <SolidColorBrush x:Key="xmlTagBrush" Color="DarkMagenta" />
  <SolidColorBrush x:Key="xmlMarkBrush" Color="Blue" />
  <DataTemplate x:Key="attributeTemplate">
    <StackPanel Orientation="Horizontal"
                Margin="3,0,0,0"
                HorizontalAlignment="Center">
      <TextBlock Text="{Binding Path=Name}"
                 Foreground="{StaticResource xmAttributeBrush}"/>
      <TextBlock Text="=""
                 Foreground="{StaticResource xmlMarkBrush}"/>
      <TextBlock Text="{Binding Path=Value}"
                 Foreground="{StaticResource xmlValueBrush}"/>
      <TextBlock Text="""
                 Foreground="{StaticResource xmlMarkBrush}"/>
    </StackPanel>
  </DataTemplate>

  <HierarchicalDataTemplate x:Key="nodeTemplate">
    <StackPanel Orientation="Horizontal"
        Focusable="False">
      <TextBlock x:Name="tbName" Text="?" />
      <ItemsControl
          ItemTemplate="{StaticResource attributeTemplate}"
          ItemsSource="{Binding Path=Attributes}"
          HorizontalAlignment="Center">
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
      </ItemsControl>
    </StackPanel>
    <HierarchicalDataTemplate.ItemsSource>
      <Binding XPath="child::node()" />
    </HierarchicalDataTemplate.ItemsSource>
    <HierarchicalDataTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
        <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
      </DataTrigger>
      <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
        <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
      </DataTrigger>
    </HierarchicalDataTemplate.Triggers>
  </HierarchicalDataTemplate>
  <XmlDataProvider x:Key="xmlDataProvider">
  </XmlDataProvider>
</Window.Resources>

现在它显示元素名称​​和属性集及其值,如下所示:

在此处输入图像描述

I added an ItemsControl into the template, like this :

<Window.Resources>
  <SolidColorBrush x:Key="xmlValueBrush" Color="Blue" />
  <SolidColorBrush x:Key="xmAttributeBrush" Color="Red" />
  <SolidColorBrush x:Key="xmlTagBrush" Color="DarkMagenta" />
  <SolidColorBrush x:Key="xmlMarkBrush" Color="Blue" />
  <DataTemplate x:Key="attributeTemplate">
    <StackPanel Orientation="Horizontal"
                Margin="3,0,0,0"
                HorizontalAlignment="Center">
      <TextBlock Text="{Binding Path=Name}"
                 Foreground="{StaticResource xmAttributeBrush}"/>
      <TextBlock Text="=""
                 Foreground="{StaticResource xmlMarkBrush}"/>
      <TextBlock Text="{Binding Path=Value}"
                 Foreground="{StaticResource xmlValueBrush}"/>
      <TextBlock Text="""
                 Foreground="{StaticResource xmlMarkBrush}"/>
    </StackPanel>
  </DataTemplate>

  <HierarchicalDataTemplate x:Key="nodeTemplate">
    <StackPanel Orientation="Horizontal"
        Focusable="False">
      <TextBlock x:Name="tbName" Text="?" />
      <ItemsControl
          ItemTemplate="{StaticResource attributeTemplate}"
          ItemsSource="{Binding Path=Attributes}"
          HorizontalAlignment="Center">
        <ItemsControl.ItemsPanel>
          <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
          </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
      </ItemsControl>
    </StackPanel>
    <HierarchicalDataTemplate.ItemsSource>
      <Binding XPath="child::node()" />
    </HierarchicalDataTemplate.ItemsSource>
    <HierarchicalDataTemplate.Triggers>
      <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
        <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
      </DataTrigger>
      <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
        <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
      </DataTrigger>
    </HierarchicalDataTemplate.Triggers>
  </HierarchicalDataTemplate>
  <XmlDataProvider x:Key="xmlDataProvider">
  </XmlDataProvider>
</Window.Resources>

Now it displays element names and the set of attributes and their values, like this:

enter image description here

山川志 2024-12-14 22:48:55

您还可以对不同的节点类型使用模板选择器,并使用 XPath node()|@* 循环遍历所有类型的节点:

<TreeView
    x:Name="TreeView"
    ItemsSource="{Binding}"
    ItemTemplateSelector="{DynamicResource ResourceKey=NodeTemplateSelector}">
    <TreeView.Resources>
        <HierarchicalDataTemplate x:Key="TextTemplate">
            <Grid>
                <uixml:TextInputControl DataContext="{Binding}" />
            </Grid>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="AttributeTemplate">
            <Grid>
                <uixml:AttributeInputControl DataContext="{Binding}" />
            </Grid>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="NodeTemplate" >
            <TextBlock Text="{Binding Path=Name}" />
            <HierarchicalDataTemplate.ItemsSource>
                <Binding XPath="child::node()|@*" />
            </HierarchicalDataTemplate.ItemsSource>
        </HierarchicalDataTemplate>
        <ui:XmlTemplateSelector
            x:Key="NodeTemplateSelector"
            NodeTemplate="{StaticResource NodeTemplate}"
            TextTemplate="{StaticResource TextTemplate}"
            AttributeTemplate="{StaticResource AttributeTemplate}" />
    </TreeView.Resources>
</TreeView>

和 :

public class XmlTemplateSelector:DataTemplateSelector{
    public DataTemplate NodeTemplate { get; set; }
    public DataTemplate TextTemplate { get; set; }
    public DataTemplate AttributeTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container) {
        XmlNode node = (XmlNode)item;
        switch (node.NodeType) {
            case XmlNodeType.Attribute:
                return AttributeTemplate;
            case XmlNodeType.Element:
                return NodeTemplate;
            case XmlNodeType.Text:
                return TextTemplate;
        }
        throw new NotImplementedException(String.Format("not implemented for type {0}", node.NodeType));
    }
}

you also can use a template selector for the different node types and use the XPath node()|@* to loop thru all types of nodes:

<TreeView
    x:Name="TreeView"
    ItemsSource="{Binding}"
    ItemTemplateSelector="{DynamicResource ResourceKey=NodeTemplateSelector}">
    <TreeView.Resources>
        <HierarchicalDataTemplate x:Key="TextTemplate">
            <Grid>
                <uixml:TextInputControl DataContext="{Binding}" />
            </Grid>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="AttributeTemplate">
            <Grid>
                <uixml:AttributeInputControl DataContext="{Binding}" />
            </Grid>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="NodeTemplate" >
            <TextBlock Text="{Binding Path=Name}" />
            <HierarchicalDataTemplate.ItemsSource>
                <Binding XPath="child::node()|@*" />
            </HierarchicalDataTemplate.ItemsSource>
        </HierarchicalDataTemplate>
        <ui:XmlTemplateSelector
            x:Key="NodeTemplateSelector"
            NodeTemplate="{StaticResource NodeTemplate}"
            TextTemplate="{StaticResource TextTemplate}"
            AttributeTemplate="{StaticResource AttributeTemplate}" />
    </TreeView.Resources>
</TreeView>

and :

public class XmlTemplateSelector:DataTemplateSelector{
    public DataTemplate NodeTemplate { get; set; }
    public DataTemplate TextTemplate { get; set; }
    public DataTemplate AttributeTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container) {
        XmlNode node = (XmlNode)item;
        switch (node.NodeType) {
            case XmlNodeType.Attribute:
                return AttributeTemplate;
            case XmlNodeType.Element:
                return NodeTemplate;
            case XmlNodeType.Text:
                return TextTemplate;
        }
        throw new NotImplementedException(String.Format("not implemented for type {0}", node.NodeType));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文