Запись данных в объект класса с формы DataGridView

152
07 декабря 2019, 09:30

Подскажите пожалуйста как записать данные в объект класса в формы DataGridView. Мне нужно считать все строки с формы для дальнейшей сериализации. Для этого, я так понимаю, надо создать массив объектов класса и через цикл записывать туда данные с формы... Но как?) Класс:

[Serializable]
    public class Person
    {
        public string name { get; set; }
        public string surename { get; set; }
        public string birthday { get; set; }
        public string sex { get; set; }
        public string country { get; set; }
        public string city { get; set; }
        public int growth { get; set; }
        public int weight { get; set; }
        public string hair_color { get; set; }
        public string eye_color { get; set; }
        public string zodiac_sign { get; set; }
        public Person()
        {
            name = null;
            surename = null;
            birthday = null;
            sex = null;
            country = null;
            city = null;
            growth = 0;
            weight = 0;
            hair_color = null;
            eye_color = null;
            zodiac_sign = null;
        }
    }

и вот часть кода, где должно быть по нажатию на кнопку считывание данных с формы

 private void btSave_Click(object sender, EventArgs e)
        {
            Person[] persons = new Person[dataGridView1.RowCount];
            for(int i = 0; i < dataGridView1.RowCount; i++)
            {
                persons[i] = new Person();
                //Дальше загвоздка...
            }
        }
Answer 1

Заметил еще с вашего прошлого вопроса, что пока вам никто не помог. Приведу пример по следам вашего кода из прошлого вопроса.

Создаем такую модель, с поддержкой проверки значений свойств.

[Serializable]
public class Person : IDataErrorInfo
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surename { get; set; }
    public DateTime Birthday { get; set; }
    public string Sex { get; set; }
    public int Weight { get; set; }
    //эти свойства я убрал, чтоб слегка облегчить пример
    //public string Country { get; set; }
    //public string City { get; set; }
    //public int Height { get; set; }
    //public string HairColor { get; set; }
    //public string EyeColor { get; set; }
    //public string ZodiacSign { get; set; }
    #region Реализация IDataErrorInfo
    public string Error => String.Empty;
    public string this[string columnName]
    {
        get
        {
            if (columnName.Equals(nameof(Name)) && String.IsNullOrEmpty(Name))
            {
                return "Введите имя";
            }
            if (columnName.Equals(nameof(Name)) && Name.Any(c => Char.IsDigit(c)))
            {
                return "Имя не должно содержать цифры";
            }
            if (columnName.Equals(nameof(Surename)) && String.IsNullOrEmpty(Surename))
            {
                return "Введите фамилию";
            }
            if (columnName.Equals(nameof(Surename)) && Surename.Any(c => Char.IsDigit(c)))
            {
                return "Фамилия не должна содержать цифры";
            }
            if (columnName.Equals(nameof(Sex)) && String.IsNullOrEmpty(Sex))
            {
                return "Выберите пол";
            }
            if (columnName.Equals(nameof(Weight)) && Weight <= 5)
            {
                return "Введите вес в килограммах";
            }
            if (columnName.Equals(nameof(Birthday)) &&
                (Birthday <= DateTime.Now.AddYears(-100) || Birthday > DateTime.Now.AddYears(-1)))
            {
                return "Введите дату рождения правильно";
            }
            return String.Empty;
        }
    }
    #endregion
}

Теперь надо задуматься о так называемом слое хранения данных (файл XML или работа с БД). Для этого создадим абстракцию Хранилища (Repository) в виде интерфейса

public interface IPersonRepository
{
    Task<List<Person>> GetPeople();
    Task<bool> AddPerson(Person person);
}

здесь пока объявлены 2 метода, потом вы можете добавить еще какие понадобятся вам по ходу разработки программы. Теперь тестовый класс хранилища, который будет работать с данными в опер.памяти. Такой репозиторий полезен, когда вы разрабатываете прототип программы и отвлечение на работу с конкретной базой данных или записью в файлы, только отвлекает от сути и влечет за собой возможность возникновения доп. ошибок. Вот такой простой тестовый репозиторий

public class PersonTestRepository : IPersonRepository
{
    private readonly List<Person> _people;
    //ctor
    public PersonTestRepository()
    {
        _people = new List<Person>
        {
            new Person { Id = 1, Name = "Андрей", Surename = "Миронов", Sex = "мужской", Birthday = DateTime.Parse("23.05.1989"), Weight = 86 },
            new Person { Id = 2, Name = "Владислав", Surename = "Смирнов", Sex = "мужской", Birthday = DateTime.Parse("03.12.1983"), Weight = 75 },
            new Person { Id = 3, Name = "Вера", Surename = "Брежнева", Sex = "женский", Birthday = DateTime.Parse("29.08.1998"), Weight = 55 },
        };
    }
    public Task<bool> AddPerson(Person person)
    {
        if (person == null)
            throw new ArgumentNullException(nameof(person));
        if (person.Id != 0)
            throw new ArgumentException(nameof(person));
        if (_people.Count == 0)
        {
            person.Id = 1;
        }
        else
        {
            person.Id = _people.Max(p => p.Id) + 1;
        }
        _people.Add(person);
        return Task.FromResult(true);
    }
    public Task<List<Person>> GetPeople()
    {
        return Task.FromResult(_people);
    }
}

Теперь реализация форм, вот главная

public partial class MainView : Form
{
    //источник данных для DGV
    private BindingSource _bsPeople = new BindingSource();
    public MainView()
    {
        InitializeComponent();
        //привязки
        SetBindings();
        this.StartPosition = FormStartPosition.CenterScreen;
        this.Text = "Пример";
        this.Load += MainView_Load;
        _buttonAddPerson.Click += ButtonAddPerson_Click;
    }
    /// <summary>
    /// Установка привязок
    /// </summary>
    private void SetBindings()
    {
        _dataGridViewPeople.AutoGenerateColumns = false;
        _dataGridViewPeople.DataSource = _bsPeople;
        _columnPersonName.DataPropertyName = nameof(Person.Name);
        _columnPersonSurename.DataPropertyName = nameof(Person.Surename);
        _columnPersonSex.DataPropertyName = nameof(Person.Sex);
        _columnPersonBirthday.DataPropertyName = nameof(Person.Birthday);
        _columnPersonWeight.DataPropertyName = nameof(Person.Weight);
    }
    /// <summary>
    /// Загружаем данные для DGV
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void MainView_Load(object sender, EventArgs e)
    {
        //получем коллекцию людей
        List<Person> people = await Program.PersonRepository.GetPeople();
        //заполняем источник данных
        people.ForEach(p => _bsPeople.Add(p));
    }
    /// <summary>
    /// Добавление новой записи о человеке
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void ButtonAddPerson_Click(object sender, EventArgs e)
    {
        using (var editView = new EditView())
        {
            //готовим форму
            editView.Owner = this;
            editView.StartPosition = FormStartPosition.CenterParent;
            editView.Text = "Создание новой записи";
            //назначаем экземпляр нового чела
            editView.CurrentPerson = new Person() { Birthday = DateTime.Now };
            //отображаем форму, ждем ответа
            if (editView.ShowDialog() == DialogResult.OK)
            {
                //запоминаем
                await Program.PersonRepository.AddPerson(editView.CurrentPerson);
                //перезагружаем коллекцию людей
                _bsPeople.Clear();
                var people = await Program.PersonRepository.GetPeople();
                people.ForEach(p => _bsPeople.Add(p));
            }
        }
    }
}

обратите внимание, что я работаю через привязки. И в качестве источника данных для DGV у меня служит экземпляр BindingSource (это к слову ответ на ваш вопрос).

Теперь форма редактирования человека

public partial class EditView : Form
{
    private BindingSource _bsPerson = new BindingSource();
    public EditView()
    {
        InitializeComponent();
        //привязки
        SetBindings();
        //роли кнопок
        this.AcceptButton = _buttonOK;
        this.CancelButton = _buttonCancel;
        //кнопка ОК отдает результат
        _buttonOK.Click += (s, e) => this.DialogResult = DialogResult.OK;
        //радиокнопки
        _radioButtonMale.CheckedChanged += RadioButton_CheckedChanged;
        _radioButtonFemale.CheckedChanged += RadioButton_CheckedChanged;
    }
    /// <summary>
    /// Текущий редактируемый чел
    /// </summary>
    public Person CurrentPerson
    {
        get => _bsPerson.Current as Person;
        set => _bsPerson.Add(value);
    }
    /// <summary>
    /// Установка привязок
    /// </summary>
    private void SetBindings()
    {
        _textBoxName.DataBindings.Add("Text", _bsPerson, nameof(Person.Name),
                                       true, DataSourceUpdateMode.OnPropertyChanged);
        _textBoxSurename.DataBindings.Add("Text", _bsPerson, nameof(Person.Surename),
                                         true, DataSourceUpdateMode.OnPropertyChanged);
        _textBoxWeight.DataBindings.Add("Text", _bsPerson, nameof(Person.Weight),
                                         true, DataSourceUpdateMode.OnPropertyChanged);
        _textBoxSex.DataBindings.Add("Text", _bsPerson, nameof(Person.Sex),
                                         true, DataSourceUpdateMode.OnPropertyChanged);
        _dateTimePickerBirthday.DataBindings.Add("Text", _bsPerson, nameof(Person.Birthday),
                                                 true, DataSourceUpdateMode.OnPropertyChanged);
        //отображение ошибок
        _errorProvider.DataSource = _bsPerson;
        //доступность кнопки OK через событие изменения свойств чела
        _bsPerson.CurrentItemChanged += _bsPerson_CurrentItemChanged;
    }
    /// <summary>
    /// Проверка значения свойств чела и вкл./выкл. кнопки ОК
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void _bsPerson_CurrentItemChanged(object sender, EventArgs e)
    {
        string error = String.Empty;
        //пробегаем по всем свойствам чела и собираем значения ошибок
        foreach (var prop in CurrentPerson.GetType().GetProperties())
        {
            error += CurrentPerson[prop.Name];
        }
        //вкл./выкл. кнопки ОК
        _buttonOK.Enabled = String.IsNullOrEmpty(error);
        //Debug.WriteLine($"error: {error}");
    }
    /// <summary>
    /// Радиокнопки, присвоение пола челу
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void RadioButton_CheckedChanged(object sender, EventArgs e)
    {
        var rb = sender as RadioButton;
        if (rb.Checked)
        {
            if (rb.Text.Equals("М"))
            {
                _textBoxSex.Text = "мужской";
            }
            else
            {
                _textBoxSex.Text = "женский";
            }
        }
    }
}

Что бы это как то запустить изменим Program.cs

static class Program
{
    public static IPersonRepository PersonRepository { get; private set; }
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        PersonRepository = new PersonTestRepository(); //данные в памяти программы
        //репозиторий реальный пишем/читаем XML файл
        //var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "people.xml");
        //PersonRepository = new PersonXmlRepository(path);
        Application.Run(new MainView());
    }
}

Вы конечно заметили, что закомментированы строки загрузки с репозиторием, который читает и сохраняет в XML файл, ну если все работает с хранилищем в памяти, осталось написать класс репозитория работающего с XML файлом и переключить использование на него в Program.cs. Вот он

public class PersonXmlRepository : IPersonRepository
{
    private readonly string _path;
    private List<Person> _people;
    //ctor
    public PersonXmlRepository(string path)
    {
        if (string.IsNullOrEmpty(path))
            throw new ArgumentException(nameof(path));
        _path = path;
        _people = new List<Person>();
    }
    /// <summary>
    /// Запись в XML файл
    /// </summary>
    private void WriteFile()
    {
        var serializer = new XmlSerializer(typeof(List<Person>));
        using (var writer = new StreamWriter(_path, false))
        {
            serializer.Serialize(writer, _people);
        }
    }
    /// <summary>
    /// Чтение из XML файла
    /// </summary>
    private void ReadFile()
    {
        var contents = String.Empty;
        if (File.Exists(_path))
        {
            contents = File.ReadAllText(_path);
        }
        if (String.IsNullOrEmpty(contents))
        {
            return;
        }
        var serializer = new XmlSerializer(typeof(List<Person>));
        using (var reader = new StringReader(contents))
        {
            var records = (List<Person>)serializer.Deserialize(reader);
            _people.Clear();
            _people.AddRange(records);
        }
    }

    /// <summary>
    /// Добавление нового человека
    /// </summary>
    /// <param name="person"></param>
    /// <returns></returns>
    public async Task<bool> AddPerson(Person person)
    {
        if (person == null)
            throw new ArgumentNullException(nameof(person));
        if (person.Id != 0)
            throw new ArgumentException(nameof(person));
        //назначаем Id
        if (_people.Count == 0)
        {
            person.Id = 1;
        }
        else
        {
            person.Id = _people.Max(p => p.Id) + 1;
        }
        //добавляем в коллекцию
        _people.Add(person);
        //пишем в файл
        try
        {
            await Task.Run(() => WriteFile());
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"Ошибка {ex.Message} записи файла {_path}");
            return false;
        }
        return true;
    }
    /// <summary>
    /// Получение всей коллекции людей
    /// </summary>
    /// <returns></returns>
    public async Task<List<Person>> GetPeople()
    {
        try
        {
            await Task.Run(() => ReadFile());
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"Ошибка {ex.Message} чтения файла {_path}");
        }
        return _people;
    }
}

Весь пример целиком здесь.

READ ALSO
Конструктор форм не видит базовый класс

Конструктор форм не видит базовый класс

Имеется базовый класс для формы и собственно форма, которая его наследует:

168
Посчитать количество итераций цикла do while

Посчитать количество итераций цикла do while

Подскажите, пожалуйста, как посчитать количество итераций цикла do while с помощью Roslyn? Нужен семантический анализатор, который бы определял...

145
Доступ к статическим файлам в ASP.NET Core MVC

Доступ к статическим файлам в ASP.NET Core MVC

Для статических файлов в проекте ASPNET Core MVC есть папка wwwroot

127
Как реализовать выстрел из гарпуна(хука)?

Как реализовать выстрел из гарпуна(хука)?

Я хочу реализовать выстрел из гарпуна(хука), как в игре Dota 2Чтобы когда Pudge бросал крюк: 1

159