Нужна помощь с совместной работой StreamReader, ArrayList и DataGrid

Я работаю над программой, которая в основном представляет собой напоминание о счете, в основном для первой программы после того, как я научился С# и WPF. Я могу попросить пользователя ввести данные, а затем сохранить их в текстовый файл. Сейчас я пытаюсь закодировать часть, которая позже загружает файл из текста. Я использовал StreamReader, чтобы прочитать текстовый файл в ArrayList, а затем выполнить итерацию по ArrayList и заполнить DataGrid. Однако что-то не работает, и я получаю пустой DataGrid, но с правильным количеством строк и столбцами с правильными заголовками. Я считаю, что проблема в том, что я использую переключатель для определения типа каждого местоположения ArrayList, а затем помещаю содержимое этого местоположения в правильный столбец, но StreamReader извлекает все в виде строки, таким образом делая переключатель бессмысленно.

Итак, в основном мой вопрос заключается в том, как заставить 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; }
    }
}

person Keven M    schedule 28.07.2011    source источник
comment
Пытаетесь использовать WPF DataGrid в качестве своего первого реального набега? Ты смелый. :)   -  person Greg D    schedule 28.07.2011
comment
Я начинаю понимать это, но это делает то, что я хочу. :)   -  person Keven M    schedule 29.07.2011


Ответы (2)


Есть куча ошибок в логике, которую вы здесь разместили. Во-первых, каждая строка в вашем массиве содержит строку, потому что это то, что возвращает 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. Я больше знаком с ListView, чем с DataGrid, поэтому я собираюсь использовать его в этом примере, но примеров того, как это сделать с 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 или, возможно, коллекция неправильно добавляется в словарь ресурсов.

person Robert Rossney    schedule 28.07.2011
comment
Спасибо за помощь, хотя я не придерживался строго того, что вы написали, я смог объединить свой оригинал с большой частью того, что вы добавили, и это заработало. Спасибо! - person Keven M; 29.07.2011

В любом случае, не используйте ArrayList в 2011 году! Вместо этого используйте общий List<T>. Или просто массив:

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

Любой лично я бы переключился на класс:

public class PersonInfo { }
person abatishchev    schedule 28.07.2011