简体   繁体   English

在 WPF DataGrid 中使用多个 XML 文档

[英]Using Multiple XML Documents in a WPF DataGrid

So for a project I am working on I have a slight problem I can't figure out how to best solve.因此,对于我正在从事的项目,我有一个小问题,我不知道如何最好地解决。

In principle the application will start by loading an XML file that I will always know the location and contents of and displaying this in a DataGrid for the user to view.原则上,应用程序将从加载 XML 文件开始,我将始终知道该文件的位置和内容,并将其显示在 DataGrid 中以供用户查看。

The user can then go onto other sections of the application to input data that they wish to be exported into an XML in the same format as the original, however the kicker is that these "edits" must never overwrite the original, I will need the new inputs or edits to be saved on a seperate XML file.然后,用户可以 go 到应用程序的其他部分,以输入他们希望以与原始格式相同的格式导出到 XML 的数据,但更重要的是这些“编辑”绝不能覆盖原始数据,我需要要保存在单独的 XML 文件中的新输入或编辑。

I can handle that section just fine, however I then want if possible to have the DataGrid show a combination of both of the XML Files (and potentially it needs to be able to check if the new file overlaps and decide which one to show).我可以很好地处理该部分,但是如果可能的话,我希望 DataGrid 显示 XML 文件的组合(并且可能需要能够检查新文件是否重叠并决定显示哪个文件)。

I've been making the program in WPF, any thoughts would be great.我一直在 WPF 中制作程序,任何想法都会很棒。

Thanks.谢谢。

Data Grid - an element derived from ItemsControl.数据网格 - 从 ItemsControl 派生的元素。 All such elements work with only one data source.所有这些元素仅适用于一个数据源。 The data source must be IEnumerable.数据源必须是 IEnumerable。

Your two XML files are two different data sources.您的两个 XML 文件是两个不同的数据源。

I see two solutions.我看到两个解决方案。

Create a UserConrol containing two DataGrid and synchronize the scroll of lines in them.创建一个包含两个 DataGrid 的 UserConrol 并同步其中的行滚动。

In ViewModel, from two source files, create one complex collection containing data from both files.在 ViewModel 中,从两个源文件中创建一个包含来自这两个文件的数据的复杂集合。

Serialisation and deserialisation is the simple csharp friendly way to work with xml.序列化和反序列化是使用 xml 的简单 csharp 友好方式。

You want xml on disk but your code will be far easier to work with if you bind ObservableCollection rather than some object source directly from xml.您希望 xml 在磁盘上,但如果您绑定 ObservableCollection 而不是直接来自 xml 的某些 object 源,您的代码将更容易使用。

If this is a new concept to you start reading here:如果这对您来说是一个新概念,请从这里开始阅读:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/ https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/

This would involve serialising a class which has a public property that's a List where t is the class corresponding to each node of your xml file.这将涉及序列化一个 class ,它具有一个公共属性,它是一个 List ,其中 t 是 class 对应于 xml 文件的每个节点。

Here is some generic serialisation and deserialisation code:这是一些通用的序列化和反序列化代码:

    public static void saveType<T>(T obj, string fileURL)
    {
        if (!fileURL.EndsWith(".xml"))
        {
            fileURL += ".xml";
        }
        using (FileStream writer = new FileStream(fileURL, FileMode.Create))  // FileMode.Create will over write an existing file
        {
            DataContractSerializer ser = new DataContractSerializer(typeof(T));
            ser.WriteObject(writer, obj);
        }
    }
    public static T readType<T>(string fileURL)
    {
        if (!fileURL.EndsWith(".xml"))
        {
            fileURL += ".xml";
        }
        var deserializedObj = Activator.CreateInstance(typeof(T));

        if (!File.Exists(fileURL))
        {
            MessageBox.Show($"No file found at {fileURL}");
            return (T)deserializedObj;
        }

        FileStream fs = new FileStream(fileURL, FileMode.Open);
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
        DataContractSerializer ser = new DataContractSerializer(typeof(T));
        deserializedObj = (T)ser.ReadObject(reader, true);
        reader.Close();
        fs.Close();
        return (T)deserializedObj;
    }

    public static void SaveArmy(string fileURL, Army army)
    {
        saveType<Army>(army, fileURL);
    }

    public static Army ReadArmy(string fileURL)
    {
        Army army = readType<Army>(fileURL);
        return army;
    }

All you need to do is have public properties, no attributes are necessary for that to work.您需要做的就是拥有公共属性,不需要任何属性即可。

The properties can be themselves complex objects so you can have things like a list as a property of each.属性本身可以是复杂对象,因此您可以将列表之类的东西作为每个对象的属性。

You may also want a property in your class which you can use to tell you the origin of a record.您可能还需要 class 中的属性,您可以使用它来告诉您记录的来源。 Is this from original file or merged in from edited file, for example.例如,这是来自原始文件还是从编辑文件中合并。

Use Linq to merge your lists of data.使用 Linq 合并您的数据列表。

for example:例如:

var combinedList = listOriginal.Union(listNew).ToList();

I'm not clear what you do with the combined lists but that's how you'd get them into one.我不清楚你对组合列表做了什么,但这就是你如何将它们整合到一个列表中的方式。

If there is logic involved you could potentially manipulate that list further and translate into another list of viewmodels.如果涉及逻辑,您可能会进一步操作该列表并转换为另一个视图模型列表。

You can then bind that list to the itemssource of a listview or datagrid.然后,您可以将该列表绑定到列表视图或数据网格的项目源。

As I write this, it's clear to me that there is much you've not explained about your question.在我写这篇文章时,我很清楚你没有解释你的问题。 I strongly recommend you edit your post and clarify your requirements.我强烈建议您编辑您的帖子并阐明您的要求。 Because your question is likely to be closed otherwise.因为您的问题可能会以其他方式关闭。

I decided to just give up and use 2 data grids instead.我决定放弃并改用 2 个数据网格。

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

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