【问题标题】:XML Datagrid Root Element - foreach loopXML Datagrid 根元素 - foreach 循环
【发布时间】:2014-01-29 00:43:06
【问题描述】:

我想将我的所有信息从 XML 获取到 Datagrid。

目前我有这个:

class ColumnNames
{
    public string id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Computer { get; set; }

    public ColumnNames(
        string id, 
        string Name, 
        string Surname, 
        string Computer, 
    {
        this.id = id;
        this.Name = Name;
        this.Surname = Surname;
        this.Computer = Computer; 
    }
}

private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{

    XDocument getElement = XDocument.Load("details.xml");

    foreach (var npc in getElement.Descendants("user"))
    {
        string id = npc.Attribute("id").Value;
        string Name = npc.Attribute("Name").Value;
        string Surname = npc.Attribute("Surname").Value;
        string Computer = npc.Attribute("Computer").Value;

        var items = new List<ColumnNames>();
        items.Add(new ColumnNames(id, Name, Surname, Computer));
        var grid = sender as DataGrid;
        grid.ItemsSource = items;
    }
}

这是我的 XML

    <info>
        <user id="1" Name="Max0" Surname="0test" Computer="0" />
        <user id="2" Name="Max1" Surname="1test" Computer="1" />
        <user id="3" Name="Max2" Surname="2test" Computer="2" />
        <user id="4" Name="Max3" Surname="3test" Computer="3" />
        <user id="5" Name="Max4" Surname="4test" Computer="4" />
        <user id="6" Name="Max5" Surname="5test" Computer="5" />
    </info>

我想要做的是将根元素中的所有数据放入包含 id、name、surname 和 computer 列的数据网格中。我的问题是,目前它只获得第一个条目,并且当我尝试使用以下内容时:

foreach (var npc in getElement.Root("info"))

我收到一个错误提示

“不可调用的成员‘System.Xml.Linq.XDocument.Root’不能使用 像一种方法。”

我不知道如何才能完成这项工作,我一直在努力解决这个问题已经有一段时间了,一些帮助会很好。谢谢。


更新:

这是大卫慷慨帮助我后的新代码。虽然还是不行。

private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{

    // getElement is a weird name for this object :)
    XDocument getElement = XDocument.Load("details.xml");

    // Create your List of ColmNames outside the foreach to use later
    var items = new List<ColumnNames>();

    foreach (var npc in getElement.Root.Elements("user"))
    {
        string id = npc.Attribute("id").Value;
        string Name = npc.Attribute("Name").Value;
        string Surname = npc.Attribute("Surname").Value;
        string Computer = npc.Attribute("Computer").Value;

        items.Add(new ColumnNames(id, Name, Surname, Computer));
    }

    // Finally, get a reference to the grid and set the ItemsSource property to use
    // your full list containing all the items
    var grid = sender as DataGrid;
    grid.ItemsSource = items;

}

【问题讨论】:

  • 您确定正在调用 DataBind() 吗?您是否已通过调试器并正在执行此代码。代码对我来说看起来不错。
  • 它只经过一次,其余的都不会经过。
  • 执行一次,fo​​reach 循环? 1. 确保您的 XML 文件正确。 2. 确保正确重建解决方案并运行新代码。

标签: c# xml wpf linq datagrid


【解决方案1】:

你已经接近了……

foreach (var npc in getElement.Descendants("user"))

实际上确实有效,而且是正确的,使用给定的 XML 结构。不过,请参阅我答案的底部以了解重要区别。

问题是您在foreach 循环中设置grid.ItemsSource = items;,因此每次foreach 循环时只添加一个项目,并且您总是只得到数据网格中的最后一个项目。

此外,您还需要将项目列表保存在foreach 循环之外,否则它只存在于foreach 内(只有scope)。

要解决这个问题,您需要将grid.ItemsSource = items; 移动到foreach 循环之后,并将列表创建移动到foreach 循环之前:

// Your code
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{    
    // getElement is a weird name for this object :)
    XDocument getElement = XDocument.Load("details.xml");

    // Create your List of ColumnNames outside the foreach to use later
    var items = new List<ColumnNames>();

    foreach (var npc in getElement.Descendants("user"))
    {
        string id = npc.Attribute("id").Value;
        string Name = npc.Attribute("Name").Value;
        string Surname = npc.Attribute("Surname").Value;
        string Computer = npc.Attribute("Computer").Value;

        // You are adding an item to the existing List<ColumnNames> now, not a new one each time
        items.Add(new ColumnNames(id, Name, Surname, Computer));
    }

    // Finally, get a reference to the grid and set the ItemsSource property to use
    // your full list containing all the items
    var grid = sender as DataGrid;
    grid.ItemsSource = items;

}

希望这会有所帮助!


关于您在foreach 循环中更改XDocument 调用的尝试,正如我所提到的,您实际上让它正常工作......但是解释为什么更改后的版本不起作用,因为我写了它已经,见下文:

您的主要问题是XDocument 有一个Root 元素,在本例中为&lt;info&gt;

您使用的语法getElement.Root("info") 告诉编译器您要调用method,称为XDocument 的Root - 但该方法不存在。这是一个财产。这就是您的错误消息告诉您的内容。

要解决问题,

将您的foreach 更改为使用.Elements()XDocument 方法,一切都会好起来的:

foreach (var npc in getElement.Root.Elements("user"))

或者,就像你已经拥有的那样

foreach (var npc in getElement.Descendants("user"))

这里的主要区别是.Descendants() 将获取任何名为“user”的节点,无论它嵌套多深; .Elements() 只会从当前节点(直接子节点)开始向下一层。

因此,尽管使用您的 XML 结构,它们的工作方式似乎相同,但在您的 XML 结构发生变化(或场景/项目不同等)的情况下,了解这种区别很重要。


附带说明,getElement 是 XDocument 对象的奇怪名称;我通常只使用 xDoc 之类的东西...


另一个更新 - 为什么这不起作用?

当我意识到这是一个 WPF 数据网格,并且您正在加载一个本地 XML 文件时,我突然意识到您的网格没有显示任何内容,因为 XDocument.Load() 无法找到该文件。

我在一个带有 DataGrid 的空 WPF 应用程序中使用 try/catch 对此进行了检查。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void DataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        XDocument getElement = null;// = XDocument.Load(@"c:\dev\stackoverflow\DataGridWpf\DataGridWpf\details.xml");
        try
        {
            getElement = XDocument.Load(@"details.xml");
        } catch (Exception ex) {
            var test = ex.ToString();
        }

        // Create your List of ColumnNames outside the foreach to use later
        var items = new List<ColumnNames>();

        foreach (var npc in getElement.Descendants("user"))
        {
            string id = npc.Attribute("id").Value;
            string Name = npc.Attribute("Name").Value;
            string Surname = npc.Attribute("Surname").Value;
            string Computer = npc.Attribute("Computer").Value;

            // You are adding an item to the existing List<ColumnNames> now, not a new one each time
            items.Add(new ColumnNames(id, Name, Surname, Computer));
        }

        // Finally, get a reference to the grid and set the ItemsSource property to use
        // your full list containing all the items
        var grid = sender as DataGrid;
        grid.ItemsSource = items;
    }

如果您单步执行此代码,将抛出 FileNotFound 异常,如果不处理该异常就会死掉,您最终会得到一个空窗口!

在我的例子中,完整路径起到了作用,并且网格加载得很好:

【讨论】:

  • 感谢您的回复,非常感谢您的回复,对我帮助很大,虽然现在数据网格中没有结果。
  • 要么你复制了一些代码错误,要么有另一个问题;使用您现在拥有的新代码更新您的问题,我们会看看我们是否可以解决它。
  • 等一下,我发现了问题 - 它与 XML 加载本身有关。
  • 全路径和npc.xml我都试过了,有什么问题?
【解决方案2】:

Perl 的作者 Larry Wall 将懒惰描述为程序员的第一大美德。不要做超过你需要的工作(有人必须维护它......可能是你)。所以……

你为什么不用 XML 序列化属性来装饰你的数据结构,比如:

[XmlRoot("info")]
public class InfoList
{

  [XmlElement("user")]
  public User[] Users { get ; set ; }

  public class User
  {
    [XmlAttribute] public string id       { get; set; }
    [XmlAttribute] public string Name     { get; set; }
    [XmlAttribute] public string Surname  { get; set; }
    [XmlAttribute] public string Computer { get; set; }
  }

}

将反序列化包装在一个方法中:

static User[] LoadUserDetails()
{
    XmlSerializer serializer = new XmlSerializer(typeof(InfoList)) ;
    using ( Stream s = File.Open("details.xml",FileMode.Open,FileAccess.Read,FileShare.Read) )
    {
        InfoList instance = (InfoList) serializer.Deserialize(s) ;
        return instance.Users ;
    }
}

然后你的方法看起来像:

private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
  DataGrid grid = (DataGrid) sender ;
  grid.ItemsSource = LoadUserDetails() ;
  return ;
}

哪个更容易测试和/或维护?

【讨论】:

  • 我对要导入的名称空间感到困惑。我使用 System.Xml.Linq 导入;使用 System.Xml;使用 System.Xml.Serialization;使用 System.IO;
  • @FarbodD -- 基于属性的 XML 序列化只需要System.Xml.Serialization,可能还需要System.Xml,这取决于你在做什么。
猜你喜欢
  • 2021-05-14
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
  • 2012-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多