XML Datagrid根元素 - foreach循环

时间:2014-01-29 00:43:06

标签: c# xml wpf linq datagrid

我希望将所有信息从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;

}

2 个答案:

答案 0 :(得分:1)

你很亲密......

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

实际上确实有效,并且是正确的,具有给定的XML结构。不过,请参阅我的答案的底部以获得重要的区别。

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

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

要解决此问题,您需要将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;

}

希望这有帮助!


关于您在XDocument循环中更改foreach调用的尝试,正如我所提到的,您确实让它正常工作......但要解释为什么更改的版本不起作用,既然我已经写过,请看下面的内容:

您的主要问题是XDocument有一个Root元素,在本例中为<info>

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

要解决问题,

更改您的foreach以使用.Elements()的{​​{1}}方法,一切顺利:

XDocument

或者,就像你已经拥有它一样

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

这里的主要区别是foreach (var npc in getElement.Descendants("user")) 将获得名为“user”的任何节点,无论它嵌套的深度如何; .Descendants()只会从当前节点(直接子节点)下一级。

因此,虽然使用XML结构时它们的工作原理相同,但在XML结构发生更改(或者场景/项目不同等)的情况下理解这种区别非常重要。


作为旁注,getElement是.Elements()对象的奇怪名称;我通常只使用像xDoc ......

这样的东西

再次更新 - 为什么这不起作用?

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

我在带有DataGrid的空WPF应用程序中使用try / catch检查了这一点。

XDocument

这段代码,如果您单步执行,将抛出FileNotFound异常,如果未处理就会死掉,最后会出现一个空窗口!

在我的情况下,完整路径完成了技巧,并且网格很好地加载:

enter image description here

答案 1 :(得分:0)

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

哪种更易于测试和/或维护?