2012-03-13 108 views
0

我目前正在使用簡單的xml查看器控件來顯示一些帶有簡單導航可能性的xml文件,例如當您在Internet Explorer中打開xml文件時。在treeview控件中結束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); 
     } 
    } 
} 

我現在的問題是,我想顯示的子節點的結束標籤,在以下示例中標有星號:

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

我不知道如何實現這個,有沒有好的建議離子?

預先感謝您。

+0

看看他們是如何做的開放標籤(例如'')並從那裏開始.. – 2012-03-13 15:47:48

+0

是的,我知道如何構建結尾節點,但我不知道它在哪裏添加文本塊,因此結尾標記顯示在子節點之後。 :| – 2012-03-13 15:52:09

+0

如果將它放在HierDT的最後一個TextBlock中,會發生什麼? – 2012-03-13 16:07:50

回答

0

我使用WebBrowser控件解決了這個問題。

我發現沒有很好的解決辦法與TreeView,但我完全滿意這個代碼,因爲它是全MVVM:

創建一個名爲BindableXmlData的web瀏覽器控件依賴屬性:

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 ([email protected]) 
| http://msdn.microsoft.com/xml/samples/defaultss/defaultss.xsl 
| 
| Conversion to XSLT 1.0 REC Syntax by Steve Muench ([email protected]) 
| 
+--> 
<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> 

創建一個新的窗口(或在我的情況下,用戶控件):

<UserControl x:Class="AdditionalXmlView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:ui="clr-namespace:MyApplication.Framework"> 
    <WebBrowser ui:AttachedWebBrowserProperties.BindableXmlData="{Binding XmlData}" /> 
</UserControl> 

像這樣創建一個視圖模型:

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 

創建視圖並視圖模型,並設置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