【问题标题】:Need help with StreamReader, ArrayList, and DataGrid working together在 StreamReader、ArrayList 和 DataGrid 协同工作方面需要帮助
【发布时间】:2011-07-29 03:00:05
【问题描述】:

我正在开发一个基本上是账单提醒的程序,主要是在自学 C# 和 WPF 之后的第一个程序。我可以让用户输入详细信息,然后将其保存到文本文件中。我现在正在尝试编写稍后从文本加载文件的部分。我使用 StreamReader 将文本文件读入 ArrayList,然后让程序遍历 ArrayList 并填充 DataGrid。虽然有些东西不起作用,我最终得到一个空白的 DataGrid,但行数和列标题正确。我认为问题在于我使用 switch-case 来确定每个 ArrayList 位置的类型,然后将该位置的内容放在正确的列中,但是 StreamReader 将所有内容作为字符串拉入,从而使 switch-case毫无意义。

所以基本上我的问题是,我如何让 StreamReader 将项目放置在正确的值类型中,或者这甚至是问题所在?

这是我正在使用的代码。尽管它实际上不是预算程序,但我只是将其用作测试平台,因此我不会“污染”我的好代码。 :) 这些值是完全相同的值类型,所以一旦它工作并转移它,它将完成我需要它做的一切。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ArrayList array = new ArrayList();

        DataGridTextColumn nameOfPerson = new DataGridTextColumn();
        nameOfPerson.Binding = new Binding("name");
        DataGridTextColumn ageOfPerson = new DataGridTextColumn();
        ageOfPerson.Binding = new Binding("age");
        DataGridTextColumn birthdayOfPerson = new DataGridTextColumn();
        birthdayOfPerson.Binding = new Binding("birthday");
        DataGridTextColumn netWorth = new DataGridTextColumn();
        netWorth.Binding = new Binding("netWorth");

        using (StreamReader reader = new StreamReader("ArrayListSource.txt"))
        {
            while (!reader.EndOfStream)
            {
                array.Add(reader.ReadLine());
            }
        }

        //Array is now populated with contents of text file.

        string name;
        int age;
        DateTime birthday;
        decimal value;

        //Checks the type of each entry in the array.
        for (int i = 0; i < array.Count; i++)
        {
            System.Type idType = array[i].GetType();
            string currentItem = idType.Name;

            switch (currentItem)
            {
                case "String":
                    name = (string)array[i];
                    dataGrid1.Items.Add(new PersonInfo() { nameOfPerson = name });
                    break;
                case "Int32":
                    age = (int)array[i];
                    dataGrid1.Items.Add(new PersonInfo() { ageOfPerson = age });
                    break;
                case "DateTime":
                    birthday = (DateTime)array[i];
                    dataGrid1.Items.Add(new PersonInfo() { birthdayOfPerson = birthday });
                    break;
                case "Decimal":
                    value = (decimal)array[i];
                    dataGrid1.Items.Add(new PersonInfo() { netWorth = value });
                    break;
            }

            dataGrid1.Columns.Add(nameOfPerson);
            dataGrid1.Columns.Add(ageOfPerson);
            dataGrid1.Columns.Add(birthdayOfPerson);
            dataGrid1.Columns.Add(netWorth);

            nameOfPerson.Header = "Name";
            ageOfPerson.Header = "Age";
            birthdayOfPerson.Header = "Birthdate";
            netWorth.Header = "Net Worth";
    }

    public struct PersonInfo
    {
        public string nameOfPerson { get; set; }
        public int ageOfPerson { get; set; }
        public DateTime birthdayOfPerson { get; set; }
        public decimal netWorth { get; set; }
    }
}

【问题讨论】:

  • 尝试使用 WPF DataGrid 作为您的第一次真正尝试?你很勇敢。 :)
  • 我开始意识到这一点,但它做了我想要的。 :)

标签: c# .net wpf wpfdatagrid streamreader


【解决方案1】:

您在此处发布的逻辑有很多问题。首先,数组中的每一行都包含一个字符串,因为这是StreamReader.ReadLine() 返回的内容。它们可能是可以被解析为另一种数据类型的字符串,但它们不是整数或小数,它们是字符串。

另一方面,您的 switch/case 块正在为数组中的每个元素创建一个新的 PersonInfo 结构(因此是网格中的一行)。 (我对您断言网格具有正确的行数感到惊讶;在我看来,它的行数应该是您期望的 4 倍。)另外,您将相同的四列添加到网格中每次处理元素时(幸运的是,这不会导致错误,但没有必要;数据网格只有四列,而不是每行四列)。并且这些列每个都有一个绑定,但它们的绑定没有来源。

您实际上需要做的很少。在代码中创建绑定是绝望和痛苦的道路。

首先,让我们解决文本文件的解析问题。您还没有明确文件的格式。设计文件格式的典型方法是,每行代表一个项目(无论是对象、结构、DataRow 还是您拥有的),并且行通过分隔符分隔为字段。因此,使用竖线作为分隔符的典型行可能如下所示:

Abner Stoltzfus|36|1975-02-01|12000.00

如果这样做,您可以将每一行拆分为一个数组,然后将结构中的每个字段分配给一个数组元素,例如:

List<PersonInfo> persons = new List<personInfo>();
using (StreamReader sr = new StreamReader(filename))
{
   while (!sr.EndOfStream)
   {
      string line = sr.ReadLine();
      string[] fields = line.Split(new char[] { '|' });
      PersonInfo p = new PersonInfo
      {
         Name = fields[0],
         Age = int.Parse(fields[1]),
         DateOfBirth = DateTime.Parse(fields[2]),
         NetWorth = decimal.Parse(fields[3])
      });
      Debug.WriteLine(string.Format("Name={0}, Age={1}, DateOfBirth={2}, NetWorth={3}",
         p.Name, p.Age, p.DateOfBirth, p.NetWorth);
      persons.Add(p);
   }
}
AddResource("Persons", persons);

该代码中可能有错误 - 我正在将它写在我的头上 - 所以你需要修复它,直到你运行它,它可靠地将人员信息写入调试窗口。您应该在开始解决问题的 WPF 部分之前执行此操作。

注意这段代码正在做而您的代码没有做的事情,例如创建一个集合来保存所有PersonInfo 结构,并将字符串解析为它们的本机类型。它所做的最后一件事是获取persons 列表并将其添加到资源字典中(我在这里假设此代码在您的Window 的代码隐藏中运行;如果没有,还有很多其他方法这样做)。

现在让我们转到您的 XAML。我对ListViewDataGrid 更熟悉,所以这就是我将在本示例中使用的内容,但有关如何使用DataGrid 执行此操作的示例比比皆是。

  <ListView ItemsSource="{Binding {DynamicResource Persons}}">
    <ListView.View>
      <GridView>
        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
        <GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}"/>
        <GridViewColumn Header="Date of birth" DisplayMemberBinding="{Binding DateOfBirth}"/>
        <GridViewColumn Header="Net worth" DisplayMemberBinding="{Binding NetWorth}"/>
      </GridView>
    </ListView.View>
  </ListView>
</ListView>

这会执行您在代码中尝试执行的所有操作以及更多操作:它创建控件,告诉它从哪里获取项目,告诉它要显示哪些列,并定义每个列的绑定。

上面的各种原因可能都行不通,但既然问题已经细分,至少你知道去哪里找了。如果调试窗口不包含正确的数据,则从文件中读取数据的逻辑存在错误。如果“输出”窗口包含绑定错误,则 XAML 中的绑定定义中存在错误(可能是字段名称),或者可能未将集合正确添加到资源字典中。

【讨论】:

  • 感谢您的帮助,虽然我没有严格遵守您所写的内容,但我能够将我的原始内容与您添加的大部分内容合并并使其正常工作。谢谢!
【解决方案2】:

无论如何,不​​要,不要在 2011 年使用 ArrayList!请改用通用List&lt;T&gt;。或者只是一个数组:

string[] lines = System.IO.File.ReadAllLines("ArrayListSource.txt");

任何我个人都会转课的人:

public class PersonInfo { }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-21
    • 2020-06-10
    • 1970-01-01
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多