Wpf 在treeview控件中结束xml标记

Wpf 在treeview控件中结束xml标记,wpf,xml,treeview,Wpf,Xml,Treeview,我目前正在开发一个简单的xml查看器控件,它可以显示一些xml文件,并提供简单的导航功能,例如在internet explorer中打开xml文件时 为此,我在msdn论坛中找到了一个不错的控件: <UserControl x:Class="WpfApplication1.CustomControl.Viewer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

我目前正在开发一个简单的xml查看器控件,它可以显示一些xml文件,并提供简单的导航功能,例如在internet explorer中打开xml文件时

为此,我在msdn论坛中找到了一个不错的控件:

<UserControl x:Class="WpfApplication1.CustomControl.Viewer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:xmlstack="clr-namespace:System.Xml;assembly=System.Xml">

    <UserControl.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 Margin="3,0,0,0"
                        HorizontalAlignment="Center"
                        Orientation="Horizontal">
                <TextBlock Foreground="{StaticResource xmAttributeBrush}" Text="{Binding Path=Name}" />
                <TextBlock Foreground="{StaticResource xmlMarkBrush}" Text="=&quot;" />
                <TextBlock Foreground="{StaticResource xmlValueBrush}" Text="{Binding Path=Value}" />
                <TextBlock Foreground="{StaticResource xmlMarkBrush}" Text="&quot;" />
            </StackPanel>
        </DataTemplate>

        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True" />
        </Style>

        <HierarchicalDataTemplate x:Key="treeViewTemplate" ItemsSource="{Binding XPath=child::node()}">
            <StackPanel Margin="3,0,0,0"
                        HorizontalAlignment="Center"
                        Orientation="Horizontal">
                <TextBlock x:Name="startTag"
                           HorizontalAlignment="Center"
                           Foreground="{StaticResource xmlMarkBrush}"
                           Text="&lt;" />

                <TextBlock x:Name="xmlTag"
                           Margin="0"
                           HorizontalAlignment="Center"
                           Foreground="{StaticResource xmlTagBrush}"
                           Text="{Binding Path=Name}" />

                <ItemsControl HorizontalAlignment="Center"
                              ItemsSource="{Binding Path=Attributes}"
                              ItemTemplate="{StaticResource attributeTemplate}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>

                <TextBlock x:Name="endTag"
                           HorizontalAlignment="Center"
                           Foreground="{StaticResource xmlMarkBrush}"
                           Text="&gt;" />
            </StackPanel>

            <HierarchicalDataTemplate.Triggers>
                <DataTrigger Binding="{Binding NodeType}">
                    <DataTrigger.Value>
                        <xmlstack:XmlNodeType>Text</xmlstack:XmlNodeType>
                    </DataTrigger.Value>
                    <Setter TargetName="xmlTag" Property="Text" Value="{Binding InnerText}" />
                    <Setter TargetName="xmlTag" Property="Foreground" Value="Blue" />
                    <Setter TargetName="startTag" Property="Visibility" Value="Collapsed" />
                    <Setter TargetName="endTag" Property="Visibility" Value="Collapsed" />
                </DataTrigger>

                <DataTrigger Binding="{Binding HasChildNodes}" Value="False">
                    <Setter TargetName="endTag" Property="Text" Value=" /&gt;" />
                </DataTrigger>
            </HierarchicalDataTemplate.Triggers>
        </HierarchicalDataTemplate>
    </UserControl.Resources>

    <Grid>
        <TreeView Name="xmlTree"
                  Grid.Row="2"
                  Grid.ColumnSpan="2"
                  ItemTemplate="{StaticResource treeViewTemplate}" />
    </Grid>
</UserControl>

正文
代码隐藏:

using System.Windows.Controls;
using System.Windows.Data;
using System.Xml;

namespace WpfApplication1.CustomControl
{
    /// <summary>
    /// Interaction logic for Viewer.xaml
    /// </summary>
    public partial class Viewer : UserControl
    {
        private XmlDocument _xmldocument;

        public Viewer()
        {
            InitializeComponent();
        }

        public XmlDocument xmlDocument
        {
            get { return _xmldocument; }
            set
            {
                _xmldocument = value;
                BindXMLDocument();
            }
        }

        private void BindXMLDocument()
        {
            if (_xmldocument == null)
            {
                xmlTree.ItemsSource = null;
                return;
            }

            XmlDataProvider provider = new XmlDataProvider();
            provider.Document = _xmldocument;
            Binding binding = new Binding();
            binding.Source = provider;
            binding.XPath = "child::node()";
            xmlTree.SetBinding(TreeView.ItemsSourceProperty, binding);
        }
    }
}
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Xml;
命名空间WPFAApplication1.CustomControl
{
/// 
///Viewer.xaml的交互逻辑
/// 
公共部分类查看器:UserControl
{
私有XmlDocument\u XmlDocument;
公众观众()
{
初始化组件();
}
公共XML文档
{
获取{return\u xmldocument;}
设置
{
_xmldocument=值;
BindXMLDocument();
}
}
私有void BindXMLDocument()
{
如果(_xmldocument==null)
{
xmlTree.ItemsSource=null;
返回;
}
XmlDataProvider provider=新的XmlDataProvider();
provider.Document=\u xmldocument;
绑定=新绑定();
binding.Source=provider;
binding.XPath=“child::node()”;
SetBinding(TreeView.ItemsSourceProperty,binding);
}
}
}
我现在的问题是,我想显示子节点的结束标记,在下面的示例中,用星号标记:

<root>
    <node>Test*</node>*
*</root>*

试验**
**
我不知道如何认识到这一点,有好的建议吗


提前谢谢。

我使用
WebBrowser
控件解决了这个问题

我在
TreeView
中没有找到好的解决方案,但我对这段代码非常满意,因为它是完整的MVVM:

为WebBrowser控件创建名为
BindableXmlData
的依赖项属性:

Public Class AttachedWebBrowserProperties

#Region "BindableXmlDataProperty"

    Public Shared ReadOnly BindableXmlDataProperty As DependencyProperty = _
            DependencyProperty.RegisterAttached("BindableXmlData", _
                                        GetType(String), _
                                        GetType(AttachedWebBrowserProperties), _
                                        New UIPropertyMetadata(Nothing, AddressOf BindableXmlDataPropertyChanged))

    Public Shared Function GetBindableXmlData(ByVal obj As DependencyObject) As ICommand
        Return CType(obj.GetValue(BindableXmlDataProperty), ICommand)
    End Function

    Public Shared Sub SetBindableXmlData(ByVal obj As DependencyObject, ByVal value As String)
        obj.SetValue(BindableXmlDataProperty, value)
    End Sub

    Public Shared Sub BindableXmlDataPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
        Dim browser As WebBrowser = TryCast(d, WebBrowser)

        If browser IsNot Nothing Then
            Dim xmldata As String = TryCast(e.NewValue, String)

            If xmldata IsNot Nothing Then
                browser.NavigateToString(xmldata)
            End If
        End If
    End Sub

#End Region

End Class
然后将名为
XmlToHtmlStylesheet.xslt
的新文件添加到解决方案中,作为包含以下内容的嵌入式资源:

<!--
 |
 | XSLT REC Compliant Version of IE5 Default Stylesheet
 |
 | Original version by Jonathan Marsh (jmarsh@xxxxxxxxxxxxx)
 | http://msdn.microsoft.com/xml/samples/defaultss/defaultss.xsl
 |
 | Conversion to XSLT 1.0 REC Syntax by Steve Muench (smuench@xxxxxxxxxx)
 |
 +-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="no" method="html"/>
  <xsl:template match="/">
    <HTML>
      <HEAD>
        <SCRIPT>
          <xsl:comment>
            <![CDATA[
                  function f(e){
                     if (e.className=="ci") {
                       if (e.children(0).innerText.indexOf("\n")>0) fix(e,"cb");
                     }
                     if (e.className=="di") {
                       if (e.children(0).innerText.indexOf("\n")>0) fix(e,"db");
                     } e.id="";
                  }
                  function fix(e,cl){
                    e.className=cl;
                    e.style.display="block";
                    j=e.parentElement.children(0);
                    j.className="c";
                    k=j.children(0);
                    k.style.visibility="visible";
                    k.href="#";
                  }
                  function ch(e) {
                    mark=e.children(0).children(0);
                    if (mark.innerText=="+") {
                      mark.innerText="-";
                      for (var i=1;i<e.children.length;i++) {
                        e.children(i).style.display="block";
                      }
                    }
                    else if (mark.innerText=="-") {
                      mark.innerText="+";
                      for (var i=1;i<e.children.length;i++) {
                        e.children(i).style.display="none";
                      }
                    }
                  }
                  function ch2(e) {
                    mark=e.children(0).children(0);
                    contents=e.children(1);
                    if (mark.innerText=="+") {
                      mark.innerText="-";
                      if (contents.className=="db"||contents.className=="cb") {
                        contents.style.display="block";
                      }
                      else {
                        contents.style.display="inline";
                      }
                    }
                    else if (mark.innerText=="-") {
                      mark.innerText="+";
                      contents.style.display="none";
                    }
                  }
                  function cl() {
                    e=window.event.srcElement;
                    if (e.className!="c") {
                      e=e.parentElement;
                      if (e.className!="c") {
                        return;
                      }
                    }
                    e=e.parentElement;
                    if (e.className=="e") {
                      ch(e);
                    }
                    if (e.className=="k") {
                      ch2(e);
                    }
                  }
                  function ex(){}
                  function h(){window.status=" ";}
                  document.onclick=cl;
              ]]>
          </xsl:comment>
        </SCRIPT>
        <STYLE>
          BODY {font:x-small 'Verdana'; margin-right:1.5em}
          .c  {cursor:hand}
          .b  {color:red; font-family:'Courier New'; font-weight:bold;
          text-decoration:none}
          .e  {margin-left:1em; text-indent:-1em; margin-right:1em}
          .k  {margin-left:1em; text-indent:-1em; margin-right:1em}
          .t  {color:#990000}
          .xt {color:#990099}
          .ns {color:red}
          .dt {color:green}
          .m  {color:blue}
          .tx {font-weight:bold}
          .db {text-indent:0px; margin-left:1em; margin-top:0px;
          margin-bottom:0px;padding-left:.3em;
          border-left:1px solid #CCCCCC; font:small Courier}
          .di {font:small Courier}
          .d  {color:blue}
          .pi {color:blue}
          .cb {text-indent:0px; margin-left:1em; margin-top:0px;
          margin-bottom:0px;padding-left:.3em; font:small Courier;
          color:#888888}
          .ci {font:small Courier; color:#888888}
          PRE {margin:0px; display:inline}
        </STYLE>
      </HEAD>
      <BODY class="st">
        <xsl:apply-templates/>
      </BODY>
    </HTML>
  </xsl:template>
  <xsl:template match="processing-instruction()">
    <DIV class="e">
      <SPAN class="b">
        <xsl:call-template name="entity-ref">
          <xsl:with-param name="name">nbsp</xsl:with-param>
        </xsl:call-template>
      </SPAN>
      <SPAN class="m">
        <xsl:text>&lt;?</xsl:text>
      </SPAN>
      <SPAN class="pi">
        <xsl:value-of select="name(.)"/>
        <xsl:value-of select="."/>
      </SPAN>
      <SPAN class="m">
        <xsl:text>?></xsl:text>
      </SPAN>
    </DIV>
  </xsl:template>
  <xsl:template match="processing-instruction('xml')">
    <DIV class="e">
      <SPAN class="b">
        <xsl:call-template name="entity-ref">
          <xsl:with-param name="name">nbsp</xsl:with-param>
        </xsl:call-template>
      </SPAN>
      <SPAN class="m">
        <xsl:text>&lt;?</xsl:text>
      </SPAN>
      <SPAN class="pi">
        <xsl:text>xml </xsl:text>
        <xsl:for-each select="@*">
          <xsl:value-of select="name(.)"/>
          <xsl:text>="</xsl:text>
          <xsl:value-of select="."/>
          <xsl:text>" </xsl:text>
        </xsl:for-each>
      </SPAN>
      <SPAN class="m">
        <xsl:text>?></xsl:text>
      </SPAN>
    </DIV>
  </xsl:template>
  <xsl:template match="@*">
    <SPAN>
      <xsl:attribute name="class">
        <xsl:if test="xsl:*/@*">
          <xsl:text>x</xsl:text>
        </xsl:if>
        <xsl:text>t</xsl:text>
      </xsl:attribute>
      <xsl:value-of select="name(.)"/>
    </SPAN>
    <SPAN class="m">="</SPAN>
    <B>
      <xsl:value-of select="."/>
    </B>
    <SPAN class="m">"</SPAN>
  </xsl:template>
  <xsl:template match="text()">
    <DIV class="e">
      <SPAN class="b"> </SPAN>
      <SPAN class="tx">
        <xsl:value-of select="."/>
      </SPAN>
    </DIV>
  </xsl:template>
  <xsl:template match="comment()">
    <DIV class="k">
      <SPAN>
        <A STYLE="visibility:hidden" class="b" onclick="return false" onfocus="h()">-</A>
        <SPAN class="m">
          <xsl:text>&lt;!--</xsl:text>
        </SPAN>
      </SPAN>
      <SPAN class="ci" id="clean">
        <PRE>
          <xsl:value-of select="."/>
        </PRE>
      </SPAN>
      <SPAN class="b">
        <xsl:call-template name="entity-ref">
          <xsl:with-param name="name">nbsp</xsl:with-param>
        </xsl:call-template>
      </SPAN>
      <SPAN class="m">
        <xsl:text>--></xsl:text>
      </SPAN>
      <SCRIPT>f(clean);</SCRIPT>
    </DIV>
  </xsl:template>
  <xsl:template match="*">
    <DIV class="e">
      <DIV STYLE="margin-left:1em;text-indent:-2em">
        <SPAN class="b">
          <xsl:call-template name="entity-ref">
            <xsl:with-param name="name">nbsp</xsl:with-param>
          </xsl:call-template>
        </SPAN>
        <SPAN class="m">&lt;</SPAN>
        <SPAN>
          <xsl:attribute name="class">
            <xsl:if test="xsl:*">
              <xsl:text>x</xsl:text>
            </xsl:if>
            <xsl:text>t</xsl:text>
          </xsl:attribute>
          <xsl:value-of select="name(.)"/>
          <xsl:if test="@*">
            <xsl:text> </xsl:text>
          </xsl:if>
        </SPAN>
        <xsl:apply-templates select="@*"/>
        <SPAN class="m">
          <xsl:text>/></xsl:text>
        </SPAN>
      </DIV>
    </DIV>
  </xsl:template>
  <xsl:template match="*[node()]">
    <DIV class="e">
      <DIV class="c">
        <A class="b" href="#" onclick="return false" onfocus="h()">-</A>
        <SPAN class="m">&lt;</SPAN>
        <SPAN>
          <xsl:attribute name="class">
            <xsl:if test="xsl:*">
              <xsl:text>x</xsl:text>
            </xsl:if>
            <xsl:text>t</xsl:text>
          </xsl:attribute>
          <xsl:value-of select="name(.)"/>
          <xsl:if test="@*">
            <xsl:text> </xsl:text>
          </xsl:if>
        </SPAN>
        <xsl:apply-templates select="@*"/>
        <SPAN class="m">
          <xsl:text>></xsl:text>
        </SPAN>
      </DIV>
      <DIV>
        <xsl:apply-templates/>
        <DIV>
          <SPAN class="b">
            <xsl:call-template name="entity-ref">
              <xsl:with-param name="name">nbsp</xsl:with-param>
            </xsl:call-template>
          </SPAN>
          <SPAN class="m">
            <xsl:text>&lt;/</xsl:text>
          </SPAN>
          <SPAN>
            <xsl:attribute name="class">
              <xsl:if test="xsl:*">
                <xsl:text>x</xsl:text>
              </xsl:if>
              <xsl:text>t</xsl:text>
            </xsl:attribute>
            <xsl:value-of select="name(.)"/>
          </SPAN>
          <SPAN class="m">
            <xsl:text>></xsl:text>
          </SPAN>
        </DIV>
      </DIV>
    </DIV>
  </xsl:template>
  <xsl:template match="*[text() and not (comment() or processing-instruction())]">
    <DIV class="e">
      <DIV STYLE="margin-left:1em;text-indent:-2em">
        <SPAN class="b">
          <xsl:call-template name="entity-ref">
            <xsl:with-param name="name">nbsp</xsl:with-param>
          </xsl:call-template>
        </SPAN>
        <SPAN class="m">
          <xsl:text>&lt;</xsl:text>
        </SPAN>
        <SPAN>
          <xsl:attribute name="class">
            <xsl:if test="xsl:*">
              <xsl:text>x</xsl:text>
            </xsl:if>
            <xsl:text>t</xsl:text>
          </xsl:attribute>
          <xsl:value-of select="name(.)"/>
          <xsl:if test="@*">
            <xsl:text> </xsl:text>
          </xsl:if>
        </SPAN>
        <xsl:apply-templates select="@*"/>
        <SPAN class="m">
          <xsl:text>></xsl:text>
        </SPAN>
        <SPAN class="tx">
          <xsl:value-of select="."/>
        </SPAN>
        <SPAN class="m">&lt;/</SPAN>
        <SPAN>
          <xsl:attribute name="class">
            <xsl:if test="xsl:*">
              <xsl:text>x</xsl:text>
            </xsl:if>
            <xsl:text>t</xsl:text>
          </xsl:attribute>
          <xsl:value-of select="name(.)"/>
        </SPAN>
        <SPAN class="m">
          <xsl:text>></xsl:text>
        </SPAN>
      </DIV>
    </DIV>
  </xsl:template>
  <xsl:template match="*[*]" priority="20">
    <DIV class="e">
      <DIV STYLE="margin-left:1em;text-indent:-2em" class="c">
        <A class="b" href="#" onclick="return false" onfocus="h()">-</A>
        <SPAN class="m">&lt;</SPAN>
        <SPAN>
          <xsl:attribute name="class">
            <xsl:if test="xsl:*">
              <xsl:text>x</xsl:text>
            </xsl:if>
            <xsl:text>t</xsl:text>
          </xsl:attribute>
          <xsl:value-of select="name(.)"/>
          <xsl:if test="@*">
            <xsl:text> </xsl:text>
          </xsl:if>
        </SPAN>
        <xsl:apply-templates select="@*"/>
        <SPAN class="m">
          <xsl:text>></xsl:text>
        </SPAN>
      </DIV>
      <DIV>
        <xsl:apply-templates/>
        <DIV>
          <SPAN class="b">
            <xsl:call-template name="entity-ref">
              <xsl:with-param name="name">nbsp</xsl:with-param>
            </xsl:call-template>
          </SPAN>
          <SPAN class="m">
            <xsl:text>&lt;/</xsl:text>
          </SPAN>
          <SPAN>
            <xsl:attribute name="class">
              <xsl:if test="xsl:*">
                <xsl:text>x</xsl:text>
              </xsl:if>
              <xsl:text>t</xsl:text>
            </xsl:attribute>
            <xsl:value-of select="name(.)"/>
          </SPAN>
          <SPAN class="m">
            <xsl:text>></xsl:text>
          </SPAN>
        </DIV>
      </DIV>
    </DIV>
  </xsl:template>
  <xsl:template name="entity-ref">
    <xsl:param name="name"/>
    <xsl:text disable-output-escaping="yes">&amp;</xsl:text>
    <xsl:value-of select="$name"/>
    <xsl:text>;</xsl:text>
  </xsl:template>
</xsl:stylesheet>
创建视图和视图模型并设置xmldata:

Public Class XYZ
    Private additionalView As AdditionalXmlView
    Private additionalViewModel As AdditionalXmlViewModel

    Private Sub CreateInstances()
        additionalViewModel = New AdditionalXmlViewModel()
        additionalView = New AdditionalXmlView()
        additionalView.DataContext = additionalViewModel
    End Sub

   Private Sub SetXmlDataOfAdditionalView()
        Dim xmlDocument As New XmlDocument()
        xmlDocument.Load("myXmlFile.xml")

        additionalViewModel.LoadXmlData(xmlDocument)
   End Sub
End Class

看看他们是如何做开始标记的(例如,
),然后从那里开始。是的,我知道如何构建结束节点,但我不知道在哪里添加文本块,因此结束标记显示在子节点之后|如果将其放在层次结构的最后一个文本块下,会发生什么情况?然后结束标记直接添加到开始标记之后,但不添加到子节点下。它看起来是这样的:Testi认为它不会与
TreeView
和HierDTs一起工作。。
Imports System.Xml
Imports System.Xml.Xsl
Imports System.Text
Imports System.IO
Imports System.ComponentModel

Public Class AdditionalXmlViewModel
    Implements INotifyPropertyChanged

    Private _XmlData As String
    Public Property XmlData() As String
        Get
            Return _XmlData
        End Get
        Set(ByVal value As String)
            _XmlData = value
            OnPropertyChanged("XmlData")
        End Set
    End Property

    Public Sub LoadXmlData(ByVal xmlDocument As XmlDocument)
        Dim sb As New StringBuilder(2500)
        Dim xslt As New XslCompiledTransform()
        Dim stylesheetStream As Stream = GetType(AdditionalXmlView).Assembly.GetManifestResourceStream("MyApplication.Framework.XmlToHtmlStylesheet.xslt")

        If stylesheetStream IsNot Nothing Then
            Dim xmlReader As XmlReader = xmlReader.Create(stylesheetStream)

            xslt.Load(xmlReader)
            Dim settings As New XmlWriterSettings()
            Dim dest As XmlWriter = XmlWriter.Create(sb, settings)
            xslt.Transform(xmlDocument, dest)
        End If

        XmlData = sb.ToString()
    End Sub


    Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    Public Sub OnPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
End Class
Public Class XYZ
    Private additionalView As AdditionalXmlView
    Private additionalViewModel As AdditionalXmlViewModel

    Private Sub CreateInstances()
        additionalViewModel = New AdditionalXmlViewModel()
        additionalView = New AdditionalXmlView()
        additionalView.DataContext = additionalViewModel
    End Sub

   Private Sub SetXmlDataOfAdditionalView()
        Dim xmlDocument As New XmlDocument()
        xmlDocument.Load("myXmlFile.xml")

        additionalViewModel.LoadXmlData(xmlDocument)
   End Sub
End Class