c# XML 树视图(管道)

本文关键字:管道 视图 XML | 更新日期: 2023-09-27 17:55:49

我正在创建一个XML查看器,它应该能够读取每个XML文件并将其放在树视图中。我的目标是创建一个XMLViewer控件,用户应该能够在自己的实现中更改某些例程。我提供了提供基本功能的默认实现,以便 XML 查看器至少显示默认行为。我正在尝试通过管道和代表来做到这一点。

到目前为止,我拥有的:

MainWindow.xaml

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="30*" />
        <RowDefinition Height="25*" />
        <RowDefinition Height="175*" />
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,5,0,5">
        <TextBlock Text="XML File" VerticalAlignment="Center" />
        <TextBox Name="txtPath" Width="400" IsReadOnly="True" Margin="5,0,5,0"/>
        <Button Content="Open" Name="btnOpen"  />
    </StackPanel>
    <Button Name="btnPlumb" Content="Plumb the code!" Grid.Row="1"/>
    <uc:XMLTreeView x:Name="XMLOutput" Grid.Row="2" />
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        //Events
        btnOpen.Click += new RoutedEventHandler(ClickedOnOpen);
        btnPlumb.Click += new RoutedEventHandler(ClickedOnPlumb);
    }
    private void ClickedOnPlumb(object sender, RoutedEventArgs e)
    {
        plumbCode();
    }
    private void ClickedOnOpen(object sender, RoutedEventArgs e)
    {
        selectXMLFile();
    }
    private void selectXMLFile()
    {
        OpenFileDialog ofd = new OpenFileDialog();
        ofd.Filter = "XML-Files |*.xml";
        ofd.InitialDirectory = "C:''";
        if (ofd.ShowDialog() == true)
        {
            string path = ofd.FileName;
            txtPath.Text = path;
            XMLOutput.processXML(path);
        }
    }
    private void plumbCode()
    {
        XMLOutput.PlumbTheCode();
    }
}

类 XMLTreeView

namespace XMLViewer
{
class XMLTreeView : TreeView
{
    public XmlDocument doc;
    public void processXML(string path)
    {
        XmlDocument document = new XmlDocument();
        this.doc = document;
        doc.Load(path);
        foreach (XmlNode node in doc.ChildNodes)
        {
            XMLTreeViewItem newItem = new XMLTreeViewItem(node);
            this.AddChild(newItem);
        }
    }
    public void PlumbTheCode()
    {
        this.Items.Clear();
        foreach (XmlNode node in doc.ChildNodes)
        {
            XMLTreeViewItem newItem;
            newItem = new XMLTreeViewItem(node);
            newItem._LoadColor = new LoadColorDelegate(newItem.LoadColorPlumbed);
            newItem._LoadColor.Invoke(node);

            this.AddChild(newItem);
        }

    }
}
}

类 XMLTreeViewItem

namespace XMLViewer
{
public delegate void LoadHeaderDelegate(XmlNode node);
public delegate void LoadColorDelegate(XmlNode node);
public delegate void CheckForChildrenDelegate(XmlNode node);
public class XMLTreeViewItem:TreeViewItem
{
   public LoadHeaderDelegate _LoadHeader { get; set; }
   public LoadColorDelegate _LoadColor { get; set; }
   public CheckForChildrenDelegate _CheckForChildren { get; set; }
    public XMLTreeViewItem(XmlNode node)
    {
        _LoadHeader = new LoadHeaderDelegate(LoadHeader);
        _LoadColor = new LoadColorDelegate(LoadColor);
        _CheckForChildren = new CheckForChildrenDelegate(CheckForChildren);
        _LoadHeader.Invoke(node);
        _LoadColor.Invoke(node);
        _CheckForChildren.Invoke(node);
    }
    #region HEADER
    private void LoadHeader(XmlNode RootNode)
    {
        if (RootNode.HasChildNodes == false)
        {
            this.Header = RootNode.InnerText.ToUpper();
        }
        else
        {
            this.Header = RootNode.Name.ToUpper();
        }
        if (RootNode.Attributes != null)
        {
            foreach (XmlAttribute attr in RootNode.Attributes)
            {
                this.Header += " " + attr.Name + " = " + attr.InnerText;
            }
        }
    } 
    #endregion
    #region COLOR
    private void LoadColor(XmlNode node)
    {
        this.Foreground = Brushes.Black;
    }
    public void LoadColorPlumbed(XmlNode node)
    {
        this.Foreground = Brushes.Green;
    } 
    #endregion
    #region CHILDREN
    private void CheckForChildren(XmlNode node)
    {
        if (node.HasChildNodes)
        {
            LoadChildren(node);
        }
    }
    private void LoadChildren(XmlNode RootNode)
    {
        foreach (XmlNode node in RootNode.ChildNodes)
        {
            XMLTreeViewItem newItem = new XMLTreeViewItem(node);
            this.AddChild(newItem);
        }
    } 
    #endregion
}
}

http://oi47.tinypic.com/34o94cw.jpg

我的目标:

http://i46.tinypic.com/29uua83.png

如您所见,我无法正确显示我的树节点。有人有解决这个问题的想法吗?

c# XML 树视图(管道)

好的

,所以你正在尝试实现一个树视图,它有扩展点,为 XML 节点提供自定义颜色/标题。

为此,您为每个 XMLTreeViewItem 添加了多个公共委托,该调用方可以覆盖以提供自己的颜色/标题/等。

当前解决方案的问题在于只有根节点才能获得自定义委托进行着色。构造根 xml 节点时,将通过构造新的 XMLTreeViewItem 来加载所有子节点,这些子节点具有 LoadColor 委托的默认实现。

您需要将委托覆盖复制到每个新创建的节点中,或者保留对根节点的引用,这些根节点已覆盖委托。

另一个问题是整个XMLTreeViewItem树是在构造函数中生成的,并且委托覆盖仅在之后提供:

newItem = new XMLTreeViewItem(node);
newItem._LoadColor = new LoadColorDelegate(newItem.LoadColorPlumbed);
newItem._LoadColor.Invoke(node);

这意味着在你执行_LoadColor.Invoke时,整个树已经构造并初始化了它的颜色。 _LoadColor = new LoadColorDelegate 将覆盖您传递给所有子节点的委托,_LoadColor.Invoke 将只为根节点着色。

我建议如何解决这个问题:

将 LoadHeader/CheckForChildren/LoadColor 方法(您希望允许重写)移动到 XMLTreeView 类,并在那里公开为公共属性:

private void LoadColor(XMLTreeViewItem item, XmlNode node)
{
    item.Foreground = Brushes.Black;
}

修改 XMLTreeViewItem 的构造函数以接受XMLTreeView,并将父引用存储在每个节点中:

public XMLTreeViewItem(XmlNode node, XMLTreeView parentTreeView)
{...}

现在,像这样构造树:

public void PlumbTheCode()
{
    this.Items.Clear();
    this._LoadColor = new LoadColorDelegate(newItem.LoadColorPlumbed);
    foreach (XmlNode node in doc.ChildNodes)
    {
        this.AddChild(new XMLTreeViewItem(node, this));
    }
}

替代解决方案是将新的着色/标头委托直接传递到 XMLTreeViewItem 构造函数中,并以递归方式传递到所有较低的节点。这将使 XMLTreeView 没有着色委托,但可能会使此类用户的自定义复杂化,因为他们需要覆盖每个节点中的委托。