需要有关StreamReader,ArrayList和DataGrid协同工作的帮助

时间:2011-07-28 17:00:02

标签: c# .net wpf wpfdatagrid streamreader

我正在开发一个基本上是账单提醒的程序,主要用于在自学C#& 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; }
    }
}

2 个答案:

答案 0 :(得分:3)

你在这里发布的逻辑有一堆错误。例如,数组中的每一行都包含一个字符串,因为这是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中的绑定定义中存在错误(可能是字段名称),或者集合可能未正确添加到资源字典中。

答案 1 :(得分:2)

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

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

我个人会切换到课堂:

public class PersonInfo { }