6 / 6 / 0
Регистрация: 21.05.2016
Сообщений: 18
1
WPF

Программное заполнение коллекции и отображение в DataGrid с использованием MVVM

22.07.2019, 19:11. Показов 3884. Ответов 29

Студворк — интернет-сервис помощи студентам
Здравствуйте. Только начинаю вникать в MVVM. Нашел такой пример:
Модель:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
namespace MVVMTest.Model
{
    public class Person : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Impl
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
 
        private string m_firstName;
        public string FirstName
        {
            get { return m_firstName; }
            set
            {
                if (value == m_firstName)
                    return;
 
                m_firstName = value;
                OnPropertyChanged();
            }
        }
 
        private string m_lastName;
        public string LastName
        {
            get { return m_lastName; }
            set
            {
                if (value == m_lastName)
                    return;
 
                m_lastName = value;
                OnPropertyChanged();
            }
        }
 
        private int m_age;
        public int Age
        {
            get { return m_age; }
            set
            {
                if (value == m_age)
                    return;
 
                m_age = value;
                OnPropertyChanged();
            }
        }
    }
 
 
}
ВьюМодель:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
namespace MVVMTest.ViewModel
{
        public class MyViewModel : INotifyPropertyChanged
        {
            #region INotifyPropertyChanged Impl
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion
 
            public ObservableCollection<Person> m_people = new ObservableCollection<Person>();
        public ObservableCollection<Person> test = new ObservableCollection<Person>();
            public ObservableCollection<Person> People
            {
                get { return m_people; }
                private set
                {
                    if (value == m_people)
                        return;
 
                    m_people = value;
                    OnPropertyChanged();
                }
            }
 
        public MyViewModel()
        {
            m_people.CollectionChanged += m_people_CollectionChanged;
            m_people.Add(new Person() { FirstName = "Bob", LastName = "Brown", Age = 45 });
            m_people.Add(new Person() { FirstName = "Sarah", LastName = "Smith", Age = 25 });
        }
 
            private void m_people_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                if (e.NewItems != null && e.NewItems.Count > 0)
                {
                    foreach (INotifyPropertyChanged item in e.NewItems.OfType<INotifyPropertyChanged>())
                    {
                        item.PropertyChanged += person_PropertyChanged;
                    }
                }
                if (e.OldItems != null && e.OldItems.Count > 0)
                {
                    foreach (INotifyPropertyChanged item in e.OldItems.OfType<INotifyPropertyChanged>())
                    {
                        item.PropertyChanged -= person_PropertyChanged;
                    }
                }
            }
            //Property Changed will be called whenever a property of one of the 'Person'
            //objects is changed.
            private void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                var row = sender as Person;
                SaveData(row);
            }
 
            private void SaveData(Person row)
            {
                //Save the row to the database here.
            }
 
        }
}
И Xaml:
HTML5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<Window x:Class="MVVMTest.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodel="clr-namespace:MVVMTest.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="284.025" Width="525">
    <Window.DataContext>
        <viewmodel:MyViewModel/>
    </Window.DataContext>
    <Grid Margin="0,0,0,41">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="168*"/>
            <ColumnDefinition Width="349*"/>
        </Grid.ColumnDefinitions>
        <DataGrid ItemsSource="{Binding People, Mode=OneWay}" AutoGenerateColumns="False" Height="88" VerticalAlignment="Top" Grid.ColumnSpan="2">
            <DataGrid.Columns>
                <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
                <DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
                <DataGridTextColumn Header="Age" Binding="{Binding Age}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>
Вопрос - как мне программно заполнять коллекцию m_people , чтобы изменения отображались в датагриде?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.07.2019, 19:11
Ответы с готовыми решениями:

Отображение номеров строк в DataGrid в MVVM
Здравствуйте! kenny69, Casper-SC, подскажите как реализовать отображение номера строк DataGrid при...

Отображение коллекции в DataGrid
Привет всем! Есть коллекция: private ObservableCollection&lt;Points&gt; _tablePointsList; public...

Программное создание item в TreeView MVVM
Доброго времени суток, очень нужна помощь: Нажатием кнопки пытаюсь добавить узел в древовидное...

WPF MVVM Бинарная сериализация коллекции классов
Всем привет. Вот есть задачка. Класс. class Employer : INotifyPropertyChanged { ...

29
Эксперт .NET
17223 / 12675 / 3323
Регистрация: 17.09.2011
Сообщений: 20,949
22.07.2019, 21:56 2
Цитата Сообщение от c0d3r Посмотреть сообщение
как мне программно заполнять коллекцию m_people , чтобы изменения отображались в датагриде?
Как в 33-й и 34-й строчках кода с ВьюМоделью.
0
6 / 6 / 0
Регистрация: 21.05.2016
Сообщений: 18
22.07.2019, 22:25  [ТС] 3
Цитата Сообщение от kolorotur Посмотреть сообщение
Как в 33-й и 34-й строчках кода с ВьюМоделью.
Не отображаются изменения в датагриде.
0
Эксперт .NET
17223 / 12675 / 3323
Регистрация: 17.09.2011
Сообщений: 20,949
22.07.2019, 22:38 4
c0d3r, покажите как добавляете
0
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
22.07.2019, 23:00 5
Цитата Сообщение от c0d3r Посмотреть сообщение
Только начинаю вникать в MVVM. Нашел такой пример:....
Пример так себе....
Здесь нет полноценной Модели.
Класс Person - это не Модель. Это тип элемента списка.
В MVVM коллекция People должна создавать и изменяться в Модели, так как она содержит ДАННЫЕ. А у ViewModel нет полномочий на ИЗМЕНЕНИЕ ДАННЫХ.

Если делать полноценное MVVM решение. То надо создать класс Модели. В нём объявить методы для сохранения/чтения коллекции, добавлении/удалении/изменении элементов коллекции, событие (или события) уведомляющее об измени данных.

Для View вы выбрали DataGrid - это сложный элемент и не совсем удачный для начального освоения MVVM.
Он сам залезает в коллекцию-источник и изменяет её. А для классического MVVM так делать нельзя. Необходимо "развязывать" коллекции Модели и View - это сложно для начинающих. Нужно отлавливать изменения элементов, самой коллекции, синхронизировать их с коллекцией Модели.
1
6 / 6 / 0
Регистрация: 21.05.2016
Сообщений: 18
23.07.2019, 15:11  [ТС] 6
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В нём объявить методы для сохранения/чтения коллекции, добавлении/удалении/изменении элементов коллекции, событие (или события) уведомляющее об измени данных.
Есть какой либо пример?

У меня пользователь не будет работать с таблицей через интерфейс. Есть метод который парсит данные через селениум и результат сохраняет в коллекцию. В проекте на винформ использовал List<T> для сохранения результата и этот список выводился в datagridview. Теперь переношу проект на wpf и моментально столкнулся с такой задачей.

Цитата Сообщение от kolorotur Посмотреть сообщение
c0d3r, покажите как добавляете
m_people.Add
People.Add

В коллекцию попадает, но датагрид не реагирует.
0
Эксперт .NET
17223 / 12675 / 3323
Регистрация: 17.09.2011
Сообщений: 20,949
23.07.2019, 16:48 7
Цитата Сообщение от c0d3r Посмотреть сообщение
m_people.Add
People.Add
Я имел в виду полный код хотя бы метода, где производится добавление.
Имею подозрение, что вы привязываете к гриду один экземпляр MyViewModel, а элементы добавляете совсем в другой.
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 17:04 8
Цитата Сообщение от c0d3r Посмотреть сообщение
В проекте на винформ использовал List<T> для сохранения результата и этот список выводился в datagridview. Теперь переношу проект на wpf и моментально столкнулся с такой задачей.
Походы к созданию View на WPF и WF очень сильно различаются.
На WF решения реализуются в MVC, на WPF - MVVM.
Поэтому основной инициатор действий в WF - это контролер, который часто (хоть это и неверно) реализуется в CB формы.
А в WPF инициирует действия View и использование CB окна для работы с данными не просто неверно, а чаще всего - ошибка.

Цитата Сообщение от c0d3r Посмотреть сообщение
Есть какой либо пример?
Посмотрите темы по разделу.
Часть примеров я собрал здесь Готовые решения, примеры и рекомендации начинающим на WPF [Элд Хасп].

Если будет время - сделаю на основе вашего кода простую реализацию.
1
0 / 0 / 0
Регистрация: 23.07.2019
Сообщений: 1
23.07.2019, 17:07 9
Consumers today have short attention spans so companies have very limited time to convince prospects that their products are worth the consideration. This is where a solid logo design comes in which grabs viewers’ attention and communicate the core values of the company in a unique and creative way.
0
6 / 6 / 0
Регистрация: 21.05.2016
Сообщений: 18
23.07.2019, 18:12  [ТС] 10
Цитата Сообщение от kolorotur Посмотреть сообщение
Имею подозрение, что вы привязываете к гриду один экземпляр MyViewModel, а элементы добавляете совсем в другой.
Да, действительно, глупо конечно), но как тогда добавить элемент в коллекцию не вызывая новый экземпляр вм? Я предполагаю, что только так:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если делать полноценное MVVM решение. То надо создать класс Модели. В нём объявить методы для сохранения/чтения коллекции, добавлении/удалении/изменении элементов коллекции, событие (или события) уведомляющее об измени данных.
Однако пока не понял, как реализовать.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если будет время - сделаю на основе вашего кода простую реализацию.
Спасибо.
0
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 18:18 11
c0d3r, посмотрите реализацию похожего решения WPF MVVM Template Number One
Я там пошагово в нескольких постах объясняю как и для чего что-то делается.
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 18:26 12
c0d3r, вот эта тема тоже показательна Пример реализации WPF+MVVM приложения

Добавлено через 2 минуты
Eщё похожая Программное создание item в TreeView MVVM

Добавлено через 1 минуту
Ещё Datagrid сохранение изменений
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 21:58 13
Цитата Сообщение от c0d3r Посмотреть сообщение
Однако пока не понял, как реализовать.
Создаём новое решение с проектом MVVMTest типа WPF FW.

В нём создаём проект CommLibrary типа библиотека классов FW. Эта библиотека типов которые могут быть использованы в любом решении. И в следующем решении можно сделать просто ссылку на эту сборку.
Для начала в нём создаём два класса и один интерфейс
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
 
namespace CommLibrary
{
    /// <summary>Базовый класс с реализацией INPC </summary>
    public abstract class OnPropertyChangedClass : INotifyPropertyChanged
    {
        #region Событие PropertyChanged
        /// <summary>Событие для извещения об изменения свойства</summary>
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
 
        #region Методы вызова события PropertyChanged
        /// <summary>Метод для вызова события извещения об изменении свойства</summary>
        /// <param name="propertyName">Изменившееся свойство</param>
        public void OnPropertyChanged([CallerMemberName]string propertyName = "")
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
        /// <summary>Метод для вызова события извещения об изменении списка свойств</summary>
        /// <param name="propList">Список имён свойств</param>
        public void OnPropertyChanged(IEnumerable<string> propList)
        {
            foreach (string propertyName in propList.Where(name => !string.IsNullOrWhiteSpace(name)))
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        /// <summary>Метод для вызова события извещения об изменении перечня свойств</summary>
        /// <param name="propList">Список имён свойств</param>
        public void OnPropertyChanged(params string[] propList)
        {
            foreach (string propertyName in propList.Where(name => !string.IsNullOrWhiteSpace(name)))
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
 
        /// <summary>Метод для вызова события извещения об изменении всех свойств</summary>
        /// <param name="propList">Список свойств</param>
        public void OnAllPropertyChanged()
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
 
        #endregion
 
        #region Виртуальные защищённые методы для изменения значений свойств
        /// <summary>Виртуальный метод определяющий изменения в значении поля значения свойства</summary>
        /// <param name="fieldProperty">Ссылка на поле значения свойства</param>
        /// <param name="newValue">Новое значение</param>
        /// <param name="propertyName">Название свойства</param>
        protected virtual void SetProperty<T>(ref T fieldProperty, T newValue, [CallerMemberName]string propertyName = "")
        {
            if ((fieldProperty != null && !fieldProperty.Equals(newValue)) || (fieldProperty == null && newValue != null))
                PropertyNewValue(ref fieldProperty, newValue, propertyName);
        }
 
        /// <summary>Виртуальный метод изменяющий значение поля значения свойства</summary>
        /// <param name="fieldProperty">Ссылка на поле значения свойства</param>
        /// <param name="newValue">Новое значение</param>
        /// <param name="propertyName">Название свойства</param>
        protected virtual void PropertyNewValue<T>(ref T fieldProperty, T newValue, string propertyName)
        {
            fieldProperty = newValue;
            OnPropertyChanged(propertyName);
        }
        #endregion
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Windows;
using System.Windows.Input;
 
namespace CommLibrary
{
    #region Делегаты для методов WPF команд
    public delegate void ExecuteHandler(object parameter);
    public delegate bool CanExecuteHandler(object parameter);
    #endregion
 
    #region Класс команд - RelayCommand
    /// <summary>Класс реализующий интерфейс ICommand для создания WPF команд</summary>
    public class RelayCommand : ICommand
    {
        private readonly CanExecuteHandler _canExecute;
        private readonly ExecuteHandler _onExecute;
        private readonly EventHandler _requerySuggested;
 
        /// <summary>Событие извещающее об изменении состояния команды</summary>
        public event EventHandler CanExecuteChanged;
 
        /// <summary>Конструктор команды</summary>
        /// <param name="execute">Выполняемый метод команды</param>
        /// <param name="canExecute">Метод разрешающий выполнение команды</param>
        public RelayCommand(ExecuteHandler execute, CanExecuteHandler canExecute = null)
        {
            _onExecute = execute;
            _canExecute = canExecute;
 
            _requerySuggested = (o, e) => Invalidate();
            CommandManager.RequerySuggested += _requerySuggested;
        }
 
        public void Invalidate()
            => Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            }), null);
 
        /// <summary>Вызов разрешающего метода команды</summary>
        /// <param name="parameter">Параметр команды</param>
        /// <returns>True - если выполнение команды разрешено</returns>
        public bool CanExecute(object parameter) => _canExecute == null ? true : _canExecute.Invoke(parameter);
 
        /// <summary>Вызов выполняющего метода команды</summary>
        /// <param name="parameter">Параметр команды</param>
        public void Execute(object parameter) => _onExecute?.Invoke(parameter);
    }
    #endregion
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using System;
 
namespace CommLibrary
{
    /// <summary>Интерфейс для создания копии экземпляра того же типа
    /// и копирования значений в другой или из другого экземпляра</summary>
    /// <typeparam name="T"></typeparam>
    public interface ICopy<T> : ICloneable
    {
        /// <summary>Создание копии экземпляра</summary>
        /// <returns>Новый экземпляр в том же типе</returns>
        T Copy();
        /// <summary>Копирование значений экземпляра в другой экземпляр</summary>
        /// <param name="other">Другой экземпляр в который надо скопировать значения</param>
        void CopyTo(T other);
        /// <summary>Копирование значений экземпляра из другого экземпляра</summary>
        /// <param name="other">Другой экземпляр из которого надо скопировать значения</param>
        void CopyFrom(T other);
    }
}
Создаём ещё один проект ModelLibrary типа Библиотека FW. В этой библиотеке будут типы для описания данных Модели. Пока это будет только один класс Person. Так как этот тип будет использоваться во всех проектах решения, в том числе в View, то делаем его производным от OnPropertyChangedClass. Так же с большой долей вероятности потребуется сравнение и копирование экземпляров этого класса. Поэтому добавляем интерфейсы ICopy<Person>, IComparable<Person>, IComparable
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using CommLibrary;
using System;
 
namespace ModelLibrary
{
    public class Person : OnPropertyChangedClass, ICopy<Person>, IComparable<Person>, IComparable
    {
        #region Поля для хранения значений свойств
        private string m_firstName;
        private string m_lastName;
        private int m_age;
        #endregion
 
        #region Свойства с INPC
        public string FirstName { get => m_firstName; set => SetProperty(ref m_firstName, value); }
        public string LastName { get => m_lastName; set => SetProperty(ref m_lastName, value); }
        public int Age { get => m_age; set => SetProperty(ref m_age, value); }
        #endregion
 
        #region Конструкторы
        public Person() { }
        public Person(string firstName, string lastName, int age)
        {
            FirstName = firstName;
            LastName = lastName;
            Age = age;
        }
        #endregion
 
        #region Реализация интерфейса ICopy<Person>
        /// <summary>Создание копии экземпляра Person</summary>
        /// <returns>Новый экземпляр в типе Person</returns>
        public Person Copy() => new Person(FirstName, LastName, Age);
 
        /// <summary>Копирование значений экземпляра Person в другой экземпляр Person</summary>
        /// <param name="other">Другой экземпляр Person в который надо скопировать значения</param>
        public void CopyTo(Person other)
        {
            other.FirstName = FirstName;
            other.LastName = LastName;
            other.Age = Age;
        }
 
        /// <summary>Копирование значений в экземпляр Person из другого экземпляра Person</summary>
        /// <param name="other">Другой экземпляр Person из которого надо скопировать значения</param>
        public void CopyFrom(Person other)
        {
            FirstName = other.FirstName;
            LastName = other.LastName;
            Age = other.Age;
        }
 
        /// <summary>Создание копии экземпляра Person</summary>
        /// <returns>Новый экземпляр в типе Object</returns>
        public object Clone() => Copy();
        #endregion
 
        #region Реализация интерфейсов IComparable<Person> и IComparable
        /// <summary>Компаратор с другим экземпляром Person</summary>
        /// <param name="other">Другой экземпляр Person</param>
        /// <returns>0 - экземпляры равны, 1 - экземпляр больше другого, -1 - экземпляр меньше</returns>
        public int CompareTo(Person other)
        {
            int ret;
            if ((ret = LastName.CompareTo(other.LastName)) != 0)
                return ret;
            if ((ret = FirstName.CompareTo(other.FirstName)) != 0)
                return ret;
            return Age.CompareTo(other.Age);
        }
 
        /// <summary>Компаратор с другим экземпляром любого типа</summary>
        /// <param name="other">Другой экземпляр Person</param>
        /// <returns>0 - экземпляры равны, 1 - экземпляр больше другого, -1 - экземпляр меньше</returns>
        public int CompareTo(object obj)
        {
            if (obj == null) return 1;
            if (obj is Person person)
                return CompareTo(person);
            throw new ArgumentException("Object is not a Person");
        }
        #endregion
    }
}
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 22:47 14
Цитата Сообщение от c0d3r Посмотреть сообщение
Однако пока не понял, как реализовать.
Теперь создаём проект для Модели Model так же типа Библиотека FW.
Добавляем ссылки на проекты CommLibrary и ModelLibrary.
В нём создаём класс для Модели ModelMVVMTest.

В первую очередь надо создать методы сохранения и загрузки данных. Самое простое решение использовать для этого сериализацию/десериализацию данных. Для этого нужны классы с атрибутом [Serializable]. Добавляем этот атрибут в класс Person
C#
6
7
    [Serializable]
    public class Person : OnPropertyChangedClass, ICopy<Person>, IComparable<Person>, IComparable
Так же, возможно, кроме списка Person будут другие данные. Поэтому создадим класс-контейнер, в котором список Person будет свойством. Если появятся другие данные, то добавим в это класс ещё свойства.
C#
1
2
3
4
5
6
7
8
9
10
11
12
using ModelLibrary;
using System;
using System.Collections.Generic;
 
namespace Model
{
    [Serializable]
    public class DataSerializable
    {
        public List<Person> People { get; set; }
    }
}
Теперь можно добавить методы сохранения и загрузки данных.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
 
namespace Model
{
    public class ModelMVVMTest
    {
        /// <summary>Сериализатор типа DataSerializable</summary>
        public static XmlSerializer DataSerializer { get; } = new XmlSerializer(typeof(DataSerializable));
 
        /// <summary>Десериализация DataSerializable из заданного файла</summary>
        /// <param name="fileName">Имя файла</param>
        /// <returns>Десериализованный DataSerializable</returns>
        /// <remarks>При ошибках выбрасывается исключение</remarks>
        public static DataSerializable LoadData(string fileName)
        {
            using (FileStream file = File.OpenRead(fileName))
            {
                return (DataSerializable)DataSerializer.Deserialize(file);
            }
        }
 
        /// <summary>Десериализация DataSerializable из заданного файла</summary>
        /// <param name="fileName">Имя файла</param>
        /// <param name="data">Десериализованный DataSerializable</param>
        /// <returns><see langword="true"/> если десериализация успешна, иначе - <see langword="false"/></returns>
        /// <remarks>При ошибках исключение не возникает</remarks>
        public static bool TryLoadData(string fileName, out DataSerializable data)
        {
            try
            {
                data = LoadData(fileName);
                return true;
            }
            catch (Exception)
            {
                data = null;
                return false;
            }
        }
 
        /// <summary>Поле для хранения данных</summary>
        private DataSerializable dataSerializable;
 
        /// <summary>Загрузка данных в экземпляр Модели</summary>
        /// <param name="fileName">Имя файла данных</param>
        public void Load(string fileName)
        {
            if (TryLoadData(fileName, out DataSerializable data))
                dataSerializable = data;
            else
                throw new Exception("Ошибка загрузки данных!");
        }
 
        /// <summary>Загрузка данных в экземпляр Модели из файла
        /// данных по умолчанию "dataMVVM.xml"</summary>
        public void Load() => Load("dataMVVM.xml");
 
 
        /// <summary>Сериализация DataSerializable в заданный файл</summary>
        /// <param name="fileName">Имя файла</param>
        /// <param name="data">Сериализуемый экземпляр</param>
        public static void SaveData(string fileName, DataSerializable data)
        {
            using (FileStream file = File.Create(fileName))
            {
                DataSerializer.Serialize(file, data);
            }
        }
 
        /// <summary>Сериализация данных Модели в заданном файле</summary>
        /// <param name="fileName">Имя файла</param>
        public void Save(string fileName) => SaveData(fileName, dataSerializable);
        /// <summary>Сериализация данных Модели в файле по умолчанию "dataMVVM.xml"</summary>
        public void Save() => SaveData("dataMVVM.xml", dataSerializable);
    }
}
На этом этапе можно добавить в решение консольный проект для проверки и отладки Модели.

На сегодня всё. Будет время продолжу.
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
23.07.2019, 22:49 15
Архив решения в текущем состоянии
Вложения
Тип файла: 7z MVVMTest (0723).7z (151.7 Кб, 6 просмотров)
1
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
24.07.2019, 09:50 16
Цитата Сообщение от c0d3r Посмотреть сообщение
Однако пока не понял, как реализовать.
Теперь в Модель надо добавить методы для работы с данными.

Чтобы не делать файл класса необъятным разобьём класс на несколько файлов. В одном будет сохранение/загрузка данных, в другом методы для работы с данными. Для этого в объявление класса добавляем слово partial.

Что нам нужно для работы с данными? Для начала хватит методов:
  1. Получения последовательности элементов "отвязанной" от исходной коллекции
  2. Добавления элемента в коллекцию
  3. Удаления элемента из коллекции

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    public partial class ModelMVVMTest
    {
        /// <summary>Получения последовательности Person</summary>
        /// <returns>Последовательность "отвязанную" от исходной коллекции</returns>
        public IEnumerable<Person> GetPeople() => dataSerializable?.People;
 
        /// <summary>Добавление Person в исходную коллекцию</summary>
        /// <param name="person">Добавляемый Person</param>
        public void AddPerson(Person person)
        {
            if (dataSerializable != null)
                dataSerializable.People.Add(person);
        }
 
        /// <summary>Удаление Person из исходной коллекции</summary>
        /// <param name="person">Удаляемый Person</param>
        public void RemovePerson(Person person)
        {
            if (dataSerializable != null)
                dataSerializable.People.Remove(person);
        }
    }
Теперь можно сделать консольку для проверки и отладки Модели. Создаём проект ConsoleDebug типа Консольное приложение FW. В нём добавляем ссылки на проекты CommLibrary, ModelLibrary и Model. Для вывода в строку добавляем в класс Person переопределение метода ToString()
C#
85
        public override string ToString() => $"Person: {FirstName} {LastName} - {Age};";
Код консольки. В нём ввод и удаление одного элемента. В дебагере можно переставлять точку выполнения, использовать интерпретатор.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    class Program
    {
        static ModelMVVMTest modelMVVM;
 
        static void Main(string[] args)
        {
            modelMVVM = new ModelMVVMTest();
            modelMVVM.Load();
 
            ConsolePeople();
 
            string input;
            do
            {
                Console.WriteLine("Введите имя, фамилию и возраст через пробел:");
                input = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(input))
                    continue;
 
                string[] values = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (values.Length == 3 && uint.TryParse(values[2], out uint age))
                {
                    modelMVVM.AddPerson(new Person() { FirstName = values[0], LastName = values[1], Age = (int)age });
                    modelMVVM.Save();
                }
                else
                    input = null;
            } while (string.IsNullOrWhiteSpace(input));
 
            ConsolePeople();
 
            do
            {
                Console.WriteLine("Введите имя:");
                input = Console.ReadLine().Trim();
                if (string.IsNullOrWhiteSpace(input))
                    continue;
 
                Person person = modelMVVM.GetPeople().FirstOrDefault(p => p.FirstName == input);
                if (person != null)
                {
                    modelMVVM.RemovePerson(person);
                    modelMVVM.Save();
                }
                else
                    input = null;
            } while (string.IsNullOrWhiteSpace(input));
 
            ConsolePeople();
 
        }
 
        static void ConsolePeople()
            => Console.WriteLine(string.Join("\r\n", modelMVVM.GetPeople()));
    }
При запуске консольки сразу ловим исключение - нет файла с данными. Надо добавить в код Модели создание пустой коллекции если нет файла данных, а в консольку обработку исключения.
C#
51
52
53
54
55
56
57
58
59
60
61
62
        /// <summary>Загрузка данных в экземпляр Модели</summary>
        /// <param name="fileName">Имя файла данных</param>
        public void Load(string fileName)
        {
            if (TryLoadData(fileName, out DataSerializable data))
                dataSerializable = data;
            else
            {
                dataSerializable = new DataSerializable() { People = new List<Person>() };
                throw new Exception("Ошибка загрузки данных!");
            }
        }
C#
15
16
17
18
19
20
21
22
23
24
25
26
27
        static void Main(string[] args)
        {
            modelMVVM = new ModelMVVMTest();
            try
            {
                modelMVVM.Load();
            }
            catch (Exception ex)
            {
 
                Console.WriteLine(ex.Message);
                Console.WriteLine("Создана новая пустая коллекция!");
            }
После этого всё работает и можно переходить к созданию View.
1
6 / 6 / 0
Регистрация: 21.05.2016
Сообщений: 18
24.07.2019, 10:27  [ТС] 17
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Person
    {
        public static List<Person> list = new List<Person>();
        public string FirstName { get; set; }
        public string LastName { get; set; }
 
        public static List<Person> GetPersons()
        {
            list.Add(new Person() { FirstName = "test", LastName = "test" });
            return list;
        }
 
        public static List<Person> SetPersons(Person item)
        {
            list.Add(item);
            return list;
        }
    }
Попробовал так. Данные добавляются и выводятся в датагриде.

C#
1
Person.SetPersons(new Person { FirstName = "123" , LastName = "321" });
Однако подозреваю, что это не тот подход)
0
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
24.07.2019, 11:49 18
Цитата Сообщение от c0d3r Посмотреть сообщение
Попробовал так. Данные добавляются и выводятся в датагриде.
Цитата Сообщение от c0d3r Посмотреть сообщение
Однако подозреваю, что это не тот подход)
Person - это тип для описания одного элемента. Закладывать в него "знания" о списке элементов и методах работы с ним - моветон.
Это касается не только WPF, а ООП в целом. Прочитайте за SOLID.
0
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
24.07.2019, 11:57 19
Вам, наверное, такие сложности кажутся излишними. Но это связанно с тем, что создаётся очень простое решение работающее локально на одном компе. И цель этого решения Получение навыков для правильного создания WPF приложения. Теоретически Модель должна работать независимо от View и, в том числе она может работать на удалённом сервере. В таком случае класс Person Модели будет относится к бизнес логике и у View и VM не будет доступа к нему. Обмен данными между Model и VM будет происходить через потоки сериализации/десериализации. В основном сейчас используется JSON, но XML тоже допустим и почти не отличается (по методам работы с сериализацией).
0
Модератор
Эксперт .NET
13821 / 10026 / 2670
Регистрация: 21.04.2018
Сообщений: 29,826
Записей в блоге: 2
24.07.2019, 12:00 20
Для начала (в виду вашего опыта) будем создавать простое решение, но создавать его будем правильно.
Потом, если будет желание и "потянете", разобьём его на отдельно работающие Model и View. Но для этого потребуются уже знания по созданию клиент-сервер приложений.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.07.2019, 12:00
Помогаю со студенческими работами здесь

Программное создание элемента XAML UWP MVVM
До недавнего времени я думал, что умею пользоваться поиском. Однако ничего даже близко похожего я...

Отображение данных в одном datagrid при клике в другом datagrid
Здравствуйте! Хотел уточнить, как можно реализовать возможность при клике на форме в dataGrid1,...

MVVM и datagrid
Здравствуйте! Пытаюсь освоить MVVM на wpf хочу сделать, чтобы с помощью entity грузилась таблица в...

Mvvm datagrid ef
Здравствуйте форумчане, у меня такая проблема есть приложение При выделении datagrid биндю...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru