草庐IT

c# XML Treeview (Plumbing) 收藏

coder 2024-07-02 原文

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

我目前拥有的:

主窗口.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>

主窗口.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

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

最佳答案

好的,所以你正在尝试实现一个 TreeView ,它有扩展点, 为 xml 节点设置自定义颜色/ header 。

为此,您为每个 XMLTreeViewItem 添加了几个公共(public)委托(delegate),调用者 可以覆盖以提供自己的颜色/标题/等。

当前解决方案的问题是只有根节点获得用于着色的自定义委托(delegate)。 构造根 xml 节点时,通过构造新的 XMLTreeViewItem 加载所有子节点,这些节点具有 LoadColor 委托(delegate)的默认实现。

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

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

newItem = new XMLTreeViewItem(node);

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

这意味着在您执行 _LoadColor.Invoke 时,整个树已经构建并且其颜色已初始化。 _LoadColor = new LoadColorDelegate 会覆盖您传递给所有子节点的委托(delegate),而 _LoadColor.Invoke 只会为根节点着色。

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

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

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));
    }
}

替代解决方案是将新的着色/ header 委托(delegate)直接传递到 XMLTreeViewItem 构造函数,然后递归传递到所有较低节点。这将使 XMLTreeView 保持干净的着色委托(delegate),但可能会使此类用户的自定义变得复杂,因为他们需要覆盖每个节点中的委托(delegate)。

关于c# XML Treeview (Plumbing) 收藏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14500376/

有关c# XML Treeview (Plumbing) 收藏的更多相关文章

  1. ruby-on-rails - 建模收藏夹 - 2

    我希望将Favorite模型添加到我的User和Link模型。业务逻辑用户可以有多个链接(即可以添加多个链接)用户可以收藏多个链接(他们自己的或其他用户的)一个链接可以被多个用户收藏,但只有一个所有者我对如何为这种关联建模以及在模型就位后如何创建用户收藏夹感到困惑?classUser 最佳答案 下面的数据模型怎么样:classUser:destroyhas_many:favorite_links,:through=>:favorites,:source=>:linkendclassLink:destroyhas_many:favor

  2. ruby - 与 Roar 的关联和收藏 - 2

    假设我们有这样的东西:classCompanyincludeMongoid::Documenthas_many:usersfield:name,type:StringendclassUserincludeMongoid::Documentbelongs_to:companyfield:name,type:StringendmoduleCompanyRepresenterincludeRoar::Representer::JSONproperty:nameendmoduleUserRepresenterincludeRoar::Representer::JSONproperty:name

  3. 科研中论文常见数学符号及其含义(科研必备,建议收藏) - 2

    论文常见数学符号及其含义(科研必备)返回论文和资料目录数学符号在数学领域是非常重要的。在论文中,使用数学符号可以使得论文更加简洁明了,同时也能够准确地描述各种概念和理论。在本篇博客中,我将介绍一些常见的数学符号及其含义(省去特别简单的符号),希望能够帮助读者更好地理解数学论文。高等数学∑i=1nxi\sum_{i=1}^nx_i∑i=1n​xi​(求和符号):表示将x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x2​,…,xn​中的所有数相加,例如∑i=1nxi\sum_{i=1}^nx_i∑i=1n​xi​表示将x1,x2,…,xnx_1,x_2,\dots,x_nx1​,x

  4. QT 设计一个串口调试工具,用一个工程就能轻松解决,外加虚拟串口工具模拟调试,在日常工作中可类比模块间通信,非常详细建议收藏 - 2

    QT串口调试工具第一节虚拟串口工具安装第二节QT创建一个基于QWidget的项目第三节UI界面设计第三节项目头文件widget.h第四节项目实现文件widget.cpp第五节main函数第六节编译结果重点第七节使用QT打包程序,不安装QT的电脑可使用第一节虚拟串口工具安装-----------------------------------------下载所需工具---------------------------------------------------------------------链接:https://pan.baidu.com/s/1QkT36S4EnH2HEAhZ1TZ8

  5. 一文带你通俗理解23种软件设计模式(推荐收藏,适合小白学习,附带C++例程完整源码) - 2

    作者:翟天保Steven版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处一、设计模式是什么?    设计模式是为了解决在软件开发过程中遇到的某些问题而形成的思想。同一场景有多种设计模式可以应用,不同的模式有各自的优缺点,开发者可以基于自身需求选择合适的设计模式,去解决相应的工程难题。    良好的软件设计和架构,可以让代码具备良好的可读性、可维护性、可扩展性、可复用性,让整个系统具备较强的鲁棒性和性能,减少屎山代码出现的概率。    想要熟练运用设计模式,提高自己的编程能力和架构能力,只有在自己工作中,结合自身工作内容,多思考多实践。本文只能通过举一些通俗的例子,来

  6. javascript - Meteor.js 我怎么知道我的收藏在客户端准备好了 - 2

    当集合在客户端完成加载后,我需要执行特定的渲染任务。了解数据何时在客户端的集合中可用的最佳策略是什么。我想出了这个解决方案:Meteor.subscribe('alldrawings',myRendering);functionmyRendering(){//dosomeno-markupstuffwiththedata//(i'mcreatingcanvasobjsanddrawingonthem)}是这样吗?除了这个还有推荐的方法吗? 最佳答案 你可以自己设置一个react变量:alldrawingsReady=newReact

  7. javascript - 如何保留添加到收藏夹列表的组件的状态 - 2

    我尝试在三个全局View中保存状态。我有组件MovieRow,它在Popular、Favorite和Search组件中调用。目标是组件MovieRow在此View中调用时保留其状态(Popular...)例如,如果我有2部电影,我检查了其中一部电影以添加到收藏夹,这部电影应该保持状态。现在,如果我在单击并更改全局View时将电影添加到收藏夹列表,组件MovieRow将再次挂载并重置状态。我尝试了很多不同的方法。将具有条件渲染的状态一个全局变量存储到我的MovieRow和其他。编辑:您可以在此处查看完整代码https://codesandbox.io/s/lpjp0oxmmq编辑2:我成

  8. javascript - Mongoose Model.remove(callback) 不会从我的收藏中删除任何东西 - 2

    我正尝试从我的Mongoose数据库中删除所有内容,但似乎没有任何效果。我试过了#CoffeeScriptMyModel.find().remove((err)->console.log('purgecallback'))#JavaScriptMyModel.find().remove(function(){console.log('purgecallback')})和#CoffeeScriptMyModel.find().remove({},(err)->console.log('purgecallback'))#JavaScriptMyModel.find().remove({},

  9. 去收藏列表,如何将列表传递给函数? - 2

    packagemain//Youaregiventwolinkedlistsrepresentingtwonon-negativenumbers.Thedigitsarestoredinreverseorderandeachoftheirnodescontainasingledigit.Addthetwonumbersandreturnitasalinkedlist.//Input:(2->4->3)+(5->6->4)//Output:7->0->8import("container/list""fmt")funcmain(){l1:=list.New()l1.PushBack(4)

  10. 无刷直流电机最强科普(收藏版) - 2

    无刷直流电机(BLDC:BrushlessDirectCurrentMotor),也被称为电子换向电机(ECM或EC电机)或同步直流电机,是一种使用直流电(DC)电源的同步电机。无刷直流电机实质上为采用直流电源输入,并用逆变器变为三相交流电源,带位置反馈的永磁同步电机。电机有各式各样的种类,而无刷直流电机是当今最理想的调速电机。它集直流电机与交流电机的优点于一身,既有直流电机良好的调整性能,又有交流电机结构简单、无换向火花、运行可靠和易于维护等优点。因而备受市场欢迎,广泛应用于汽车、家电、工业设备等领域中。01无刷直流电机发展历史直流无刷电机并不是最早的产品,而是在有刷电机的基础上发展而来的,

随机推荐