简体   繁体   English

使用XML节点作为页面列表。 添加编号的XML节点,然后重新排序。 Visual C#

[英]Using XML nodes as page list. Add numbered XML nodes then reordering them. Visual C#

I was hoping that someone could help me with roadblock I've hit with my project. 我希望有人可以帮我解决我遇到的问题。 I am beginner to programming in general and I'm learning C# (WinForms). 我是编程的初学者,我正在学习C#(WinForms)。 I'm making a simple text editor. 我正在制作一个简单的文本编辑器。 I have a rich text file and a XML file to store other information. 我有一个富文本文件和一个XML文件来存储其他信息。 Inside the XML file I have a pages node that I want to use to store line numbers. 在XML文件中,我有一个页面节点,我想用它来存储行号。 I have a button that will scroll a rich text box to the next page's line number stored in the XML file. 我有一个按钮,可以将富文本框滚动到存储在XML文件中的下一页的行号。 For example: 例如:

<pages>
  <page1>0</page1>
  <page2>32</page2>
</pages>

I have another button that will add a page to the pages node. 我有另一个按钮,将页面添加到页面节点。 When adding the new page, I need my app to add the new node with the correct name and in the correct place in the pages node. 添加新页面时,我需要我的应用程序添加具有正确名称的新节点,并在页面节点中的正确位置。 For example, Adding a new page for line 16, the file will then look like this; 例如,为第16行添加新页面,该文件将如下所示;

<pages>
  <page1>0</page1>
  <page2>16</page2>
  <page3>32</page3>
</pages>

I have got as far a adding a new node into the XML file and getting the selected line number, but I can't figure out the next step. 到目前为止,我已经在XML文件中添加了一个新节点并获取了所选的行号,但我无法弄清楚下一步。 Firstly, How do I get the new node's (in the case above, page2) to have the correct number in its name? 首先,如何让新节点(在上面的情况下,第2页)在其名称中包含正确的数字? If you clicked on the add page button again on line 8, it would become page2, line 16 would become page3, line 32 would become page4 and so on. 如果你在第8行再次点击添加页面按钮,它将成为page2,第16行将成为page3,第32行将成为page4,依此类推。 See comment 1 in following code which is from the main form.cs file. 请参阅以下代码中的注释1,该代码来自主form.cs文件。

string xmlFile = @"C:/test.xml";

private void bottomBarAddPageButton_Click(object sender, EventArgs e)
    {
        int cursorPosition = mainTextbox.SelectionStart;
        int lineIndex = mainTextbox.GetLineFromCharIndex(cursorPosition);
        XmlNode pagesNodes = XmlReader.SelectSingleNode("root/pages");
        XmlNode pageNodeCreate = XmlReader.CreateElement("page"); // Comment 1: Needs to add correct page number here 
        pageNodeCreate.InnerText = Convert.ToString(lineIndex);
        pagesNodes.AppendChild(pageNodeCreate);
        XmlReader.Save(xmlFile);
    }

The following is what the XML file currently looks like. 以下是XML文件目前的样子。 Clicking bottomBarAddPageButton adds a new node called page with the inner text as the selected line number (lineIndex). 单击bottomBarAddPageButton会添加一个名为page的新节点,其内部文本将作为选定的行号(lineIndex)。

<root>
  <otherNodes>
  <pages>
    <page>0</page>
    <page>28</page>
    <page>32</page>
    <page>8</page>
    <page>76</page>
    <page>10</page>
  </pages>
</root>

Secondly, After a new node is added, how do I then reorder all the child nodes within pages so the XML file looks like this? 其次,添加新节点后,如何重新排序页面中的所有子节点,以便XML文件如下所示?

<root>
  <otherNodes>
  <pages>
    <page1>0</page1>
    <page2>8</page2>
    <page3>10</page3>
    <page4>28</page4>
    <page5>32</page5> 
    <page6>76</page6>       
  </pages>
</root>

I also need to be able to do the reverse when a page is removed. 我还需要能够在删除页面时执行相反操作。 For example, if one clicks on the remove page button on line 19 of the rich text box, page3 (node containing line 10) would be removed so that page2 would be from line 8 through to line 27. page3 would be from line28 through to line 32 and so on. 例如,如果单击富文本框第19行上的删除页面按钮,则将删除page3(包含第10行的节点),以便page2将从第8行到第27行.page3将从第28行到第23行。第32行等等。

As I said at the start, I beginner with C# and I have no idea how to do this, what the best method is or if I'm going down that right road. 正如我在开始时所说的那样,我初学C#并且我不知道如何做到这一点,最好的方法是什么,或者我是否正走这条正确的道路。 So I was hoping that someone out there would be able to help me. 所以我希望那里的人能够帮助我。 I hope I have explained what I'm trying to do clearly enough and that my question makes sense. 我希望我已经解释了我要做的事情,并且我的问题是有道理的。

Thank you so much for your time and with any help. 非常感谢你的时间和任何帮助。

Morgan 摩根

PS Please forgive me for posting such a huge question but I wanted to give as much info as I could. PS请原谅我发布这么大的问题,但我想尽可能多地提供信息。

I think best approach would be to have class named Page and list of those pages. 我认为最好的方法是将类命名为Page和这些页面的列表。 Then, you can serialize class to xml (and deserialize xml to class again). 然后,您可以将类序列化为xml(并再次将xml反序列化为类)。 That way you can manipulate Page collection without fiddling with xml. 这样你就可以在不摆弄xml的情况下操纵Page集合。

I would make it like this: 我会这样做:

Classes

[Serializable]
[XmlRoot("root")]
public class Data
{

    [XmlArray("Pages")]
    [XmlArrayItem(ElementName = "Page", Type = typeof(Page))]
    public List<Page> Pages { get; set; }

    //add as many properties as needed
    public int SomeIntNode { get ; set; }

    //using [XmlElement] attribute, you can change how the element will be named in xml 
    [XmlElement("otherName")]
    public string Name { get; set; }

}

[Serializable]
public class Page
{
    [XmlAttribute]
    public int Value { get; set; }

    //you can add additional attributes if needed.
    //just make a property and add [XmlAttribute] attrib, like this:
    //[XmlAttribute]
    //public sting SomeText { get; set; }
    //so it will be written as <Page Value="123" SomeText="abc" />
}

Class Data is just container which contains Pages collection. Data只是包含Pages集合的容器。 You can add addition properties to Data class if you also want them serialized. 如果还希望序列化,可以向Data类添加其他属性。

Page is class that contains value (row in your RichTextBox ). Page是包含值的类( RichTextBox行)。

Attributes like [XmlArray("Pages")] and [XmlArrayItem(ElementName = "Page", Type = typeof(Page))] are used as additional description for serializer (class that converts and writes data to xml format). [XmlArray("Pages")][XmlArrayItem(ElementName = "Page", Type = typeof(Page))]等属性用作序列化程序(将数据转换为xml格式的类)的附加说明。 First tells serializer how to name collection and second how to name an element and it's type. 首先告诉序列化器如何命名集合,然后告诉如何命名元素及其类型。 Attribute [Serializable] tells that class can be serialized. 属性[Serializable]告诉该类可以序列化。

Usage 用法

Make an instance of Data class and add pages to it's Pages collection. 创建一个Data类的实例,并将页面添加到Pages集合中。 Write data, and load it again when necessary. 写入数据,并在必要时再次加载。 Once loaded, you can iterate thru Pages by index or using foreach or using for loop. 加载后,您可以通过索引或使用foreach或使用for循环遍历Pages Then, you can add one or more pages to collection and sort it again. 然后,您可以将一个或多个页面添加到集合中并再次对其进行排序。

public void Test()
{ 

    //create data and write it to xml
    CreateData();
    //load data from xml
    Data data = LoadData();
    //iterate thru collection if needed
    foreach (Page page in data.Pages)
    {
        System.Diagnostics.Debug.WriteLine(string.Format("page number {0}, value: {1}",(data.Pages.IndexOf(page) + 1), page.Value));
        //or, you can write to debug window like this:
        //System.Diagnostics.Debug.WriteLine("page number " + (data.Pages.IndexOf(page) + 1).ToString() + ", value: " + page.Value.ToString());
        //or fill some listbox
        //listBox1.Items.Add("page number " + (data.Pages.IndexOf(page) + 1).ToString() + ", value: " + page.Value.ToString());
        //...
    }
    //access second page (by index... index 1 is page 2)
    var specificPage = data.Pages[1];
    //add additional page and sort it by value
    data.Pages.Add(new Page() { Value = 15 });
    data.Pages.OrderBy(x => x.Value);
    //write again if needed
    WriteToXml(data);

}

private void CreateData()
{
    Data data = new Data();
    data.Pages = new List<Page>();             
    data.Pages.Add(new Page() { Value = 10 });
    data.Pages.Add(new Page() { Value = 20 });
    data.Pages.Add(new Page() { Value = 30 });

    //other properties
    data.SomeIntNode = 100;
    data.Name = "here is name";

    WriteToXml(data);

}

private void WriteToXml(Data data)
{
    XmlSerializer xSer = new XmlSerializer(typeof(Data));
    using (TextWriter writer = new StreamWriter(@"c:\temp\pages.xml"))
    {
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add("", "");
        xSer.Serialize(writer, data, ns);
    }
}

private Data LoadData()
{
    XmlSerializer xSer = new XmlSerializer(typeof(Data));
    using (TextReader reader = new StreamReader(@"c:\temp\pages.xml"))
    {
        return xSer.Deserialize(reader) as Data;
    }
}

xml data (EDIT: updated because of new properties and with new root name) xml数据 (编辑:由于新属性和新的根名称而更新)

<?xml version="1.0" encoding="utf-8"?>
<root>
  <Pages>
    <Page Value="10" />
    <Page Value="20" />
    <Page Value="30" />
    <Page Value="15" />
  </Pages>
  <SomeIntNode>1000</SomeIntNode>
  <otherName>here is name</otherName>
</root>

If you have some questions, feel free to ask. 如果您有一些问题,请随时提出。

EDIT: renamed data element to root (to be more like your sample) and added new properties in Data class to show how other data can be added (look in CreateData() ). 编辑:将data元素重命名为root (更像是您的示例)并在Data类中添加新属性以显示如何添加其他数据(查看CreateData() )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM