Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: OnPropertyChanged не успевает за изменением данных

Уважаемые форумчане, столкнулся с такой проблемой.
ListBox привязан к ObservableCollection, состоящей из объектов класса pmDevice. В этом классе создал метод Test(), рандомно устанавливающий значения. Если в методе btnTest_Click() внутри цикла установить точку остановки и вручную, нажимая F5, проделать все операции, то всё нормально, все значения отображаются разные. Но если нажать на кнопку в нормальном режиме, без остановок, то все значения получаются одинаковые.

Как это побороть?

Кликните здесь для просмотра всего текста

XML
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
<ListBox x:Name="listDevices" Grid.Column="1" ItemsSource="{Binding}" SelectionChanged="listBox_SelectionChanged">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Height="35" Background="#4CD4B800">
                        <StackPanel.Style>
                            <Style>
                                <Style.Resources>
                                    <Style TargetType="Label">
                                        <Setter Property="BorderBrush" Value="Red" />
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Path=IsAviable}" Value="True">
                                                <Setter Property="BorderBrush" Value="LimeGreen" />
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                    <Style TargetType="Ellipse">
                                        <Setter Property="Width" Value="16" />
                                        <Setter Property="Height" Value="{Binding Path=ActualWidth, RelativeSource={RelativeSource Self}}" />
                                        <Setter Property="Stroke" Value="Black" />
                                        <Setter Property="Margin" Value="2,0" />
                                        <Setter Property="Fill" Value="Red" />
                                    </Style>
                                </Style.Resources>
                            </Style>
                        </StackPanel.Style>
                        
                        <Label Content="{Binding Path=Name}" Width="100" VerticalAlignment="Center" BorderThickness="7,0,0,0" />
                        <Ellipse />
                        <Ellipse>
                            <Ellipse.Style>
                                <Style TargetType="Ellipse">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Path=Detector1}" Value="True">
                                            <Setter Property="Fill" Value="LimeGreen" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Ellipse.Style>
                        </Ellipse>
                        <Ellipse>
                            <Ellipse.Style>
                                <Style TargetType="Ellipse">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Path=Detector2}" Value="True">
                                            <Setter Property="Fill" Value="LimeGreen" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Ellipse.Style>
                        </Ellipse>
                        <Ellipse>
                            <Ellipse.Style>
                                <Style TargetType="Ellipse">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding Path=Detector3}" Value="True">
                                            <Setter Property="Fill" Value="LimeGreen" />
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Ellipse.Style>
                        </Ellipse>
                        <Label Content="{Binding Path=ADCvalue}" Width="70"
                               VerticalAlignment="Center" HorizontalAlignment="Center"
                               FontSize="16" BorderThickness="2" BorderBrush="#FFFFDF17" Background="#FF3C3232" Foreground="#FF17F721"
                               Margin="35,0,0,0" Padding="5,0" FontFamily="/PowerMonitorWPF;component/#a_LCDNovaObl" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>


Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
ObservableCollection<pmDevice> devices = new ObservableCollection<pmDevice>();
listDevices.DataContext = devices;
 
private void btnTest_Click(object sender, RoutedEventArgs e)
        {
            Random r = null;
            foreach (pmDevice i in devices)
            {
                r = new Random();
                i.Test(r);
            }
        }


Кликните здесь для просмотра всего текста

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
class pmDevice : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string info)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
 
        string vName = "NULL";
        bool vIsAviable = false;
        byte vVoltage = 0;
 
        byte opcode;
 
        byte[] vMAC;
        IPAddress vIP, vMask, vGW, vIPServ;
        UInt16 vLocalPort, vPortServ;
        float vADCcalib = 0;
        byte vADChi, vADClo;
        UInt32 vFirmware;
 
        byte vADCvalue;
        bool vDetector1, vDetector2, vDetector3;
 
        public string Name { get { return vName; } set { vName = value; OnPropertyChanged("Name"); } }
        public bool IsAviable { get { return vIsAviable; } set { vIsAviable = value; OnPropertyChanged("IsAviable"); } }
        public byte Voltage { get { return vVoltage; } set { vVoltage = value; OnPropertyChanged("Voltage"); } }
 
        public byte ADCvalue    { get { return vADCvalue; } set { vADCvalue = value;    OnPropertyChanged("ADCvalue"); } }
        public bool Detector1 { get { return vDetector1; } set { vDetector1 = value; OnPropertyChanged("Detector1"); } }
        public bool Detector2 { get { return vDetector2; } set { vDetector2 = value; OnPropertyChanged("Detector2"); } }
        public bool Detector3 { get { return vDetector3; } set { vDetector3 = value; OnPropertyChanged("Detector3"); } }
 
        public byte[] MAC { get { return vMAC; } set { vMAC = value; OnPropertyChanged("MAC"); } }
        public IPAddress IP { get { return vIP; } set { vIP = value; OnPropertyChanged("IP"); } }
        public IPAddress Mask { get { return vMask; } set { vMask = value; OnPropertyChanged("Mask"); } }
        public IPAddress GW { get { return vGW; } set { vGW = value; OnPropertyChanged("GW"); } }
        public UInt16 LocalPort { get { return vLocalPort; } set { vLocalPort = value; OnPropertyChanged("LocalPort"); } }
        public IPAddress IPServ { get { return vIPServ; } set { vIPServ = value; OnPropertyChanged("IPServ"); } }
        public UInt16 PortServ { get { return vPortServ; } set { vPortServ = value; OnPropertyChanged("PortServ"); } }
        public float ADCcalib { get { return vADCcalib; } set { vADCcalib = value; OnPropertyChanged("ADCcalib"); } }
        public byte ADChi { get { return vADChi; } set { vADChi = value; OnPropertyChanged("ADChi"); } }
        public byte ADClo { get { return vADClo; } set { vADClo = value; OnPropertyChanged("ADClo"); } }
        public UInt32 Firmware { get { return vFirmware; } set { vFirmware = value; OnPropertyChanged("Firmware"); } }
 
        public pmDevice(byte[] Datagram)
        {
            UpdateSettings(Datagram);
            Name = "ip_" + IP.ToString();
        }
 
        public void Test(Random r)
        {
            ADCvalue = (byte)r.Next(0,255);
            Detector1 = Convert.ToBoolean(r.Next(0, 3));
            Detector2 = Convert.ToBoolean(r.Next(0, 3));
            Detector3 = Convert.ToBoolean(r.Next(0, 3));
 
            Name = "Test" + r.Next(0, 255);
            IsAviable = Convert.ToBoolean(r.Next(0, 3));
        }
    }


Кликните здесь для просмотра всего текста



Ответ: Ev_Hyper, спасибо за ответ.
Увы, незнание механизма работы Random сыграло такую шутку. Впредь буду знать.
Вопрос: Правильное построение биндинга

И снова здравствуйте.

Есть view.

Есть ViewModel :

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ImmortaL
{
    public class ViewModel
    {
        Model.Test test = new Model.Test();
 
        public ViewModel()
        {   
              test.Name = "qwerty";
        }
    }
}
Есть сама модель:

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
 
namespace ImmortaL
{
    public class Model
    {
        public class Test : INotifyPropertyChanged
        {
 
            private string name;
            public string Name
            {
                get{ return name; }
                set
                {
                    name = value;
                    OnPropertyChanged("Name");
                }
            }
            #region onpropertychanged
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
            #endregion
        }
    }
}
Именно класс в классе. Я реализовал OnPropertyChanged. Но как теперь мне забиндить test.Name поле в моей ViewModel? Ничего не выходит.

Добавлено через 1 минуту
Я думал создать прямо во viewmodel новую переменную, присвоить ей значение из test.Name и реализовать в этой переменной Property, но это как-то громоздко, постоянно переприсваивать значения, может есть другой способ? Спасибо
Ответ: Cuguyc, так нужно 100% В классе много классов, и там же есть Основной класс, колторый содержит в себе поля из этих классов) Просто это результат генерации классов от парсинга Json, по другому не могу сделать) Спасибо, вы очень помогли мне

Добавлено через 25 минут
В общем попробовал как вы написали, ничего не выходит Ссылка на объект не указывает на экземпляр объекта )
C#
1
2
3
4
5
6
7
8
9
10
11
CharacterData.RootObject character = new CharacterData.RootObject();
 public int UserGamelvl
        {
            get { return character.Pers.Level; }
            set { character.Pers.Level = value; OnPropertyChanged("UserGamelvl"); }
        }
 
        public MainViewModel()
        {
            character.Pers.Level = 1324;
        }
не хочет работать, а было бы так удобно

Добавлено через 1 минуту
Просто у меня постоянно в классе "character" изменяются значения, и создавать новые переменные, переписывать их, это бред, проще на WinForm остаться тогда там такое же дерево

Добавлено через 9 минут
Ага, открыл я классы, что насоздавал генератор классов Json и понял почему оно мне выдаёт такую ошибку :

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        public class RootObject
        {
            public string sec { get; set; }
            public List<Map> maps { get; set; }
            public List<Land> lands { get; set; }
            public List<Unit> units { get; set; }
            public List<Item> items { get; set; }
            public string mysql_error { get; set; }
            public DailyBonus dailyBonus { get; set; }
            public bool settings { get; set; }
            public Vip vip { get; set; }
            public Unitopenings unitopenings { get; set; }
            public Boss boss { get; set; }
            public List<string> tutorial { get; set; }
            public string urlCfg { get; set; }
            public Pers2 Pers { get; set; }
            public double PEFT_TEST_TOTAL { get; set; }
            public string cfgVersion { get; set; }
            public int srvTime { get; set; }
        }
Они не инициализированы по идее. Только вот не знаю, если сделать всё через new, JsonConverter не будет меня потом ругать, если я захочу десериализовать Json в этот класс?

Добавлено через 14 минут
Всё, разобрался, когда прописываю

C#
1
character = JsonConvert.DeserializeObject<CharacterData.RootObject>(str);
При десериализации, оно видимо само создаёт экземпляры этих объектов. Ошибка пропала, работает как надо)
Вопрос: Событие CheckBox.IsChecked и данные

Каким образом можно привязать событие IsChecked у CheckBox таким образом, чтобы при состоянии false затирались данные в модели?
К примеру:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, e);
        }
    }
 
public string PersonName
      {
          get { return name; }
          set
          {
              name = value;
              OnPropertyChanged("PersonName");
          }
      }
И теперь, жмакнув на CheckBox - данные из свойства затирались. Поступают они в свойство путём селекта на ListView. В целом, хочу обнулять свойства в модели, если у некоторых CheckBox устанавливается состояние IsChecked = false.
Ответ:
C#
1
2
3
4
5
6
7
8
9
10
public bool MyIsChecked
{
get { return _myIsChecked; }
          set
          {
               if(!value) PersonName = "";
              _myIsChecked= value;
              OnPropertyChanged("MyIsChecked");
          }
}
XML
1
<Checkbox IsChecked="{Binding MyIsChecked}" Content="Click me"/> 
Вопрос: Проверка записывающихся значений

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

Код XML
1
<TextBox Text="{Binding Dlina, Source={StaticResource Material}, UpdateSourceTrigger=PropertyChanged}"/>
Код C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        
public double Dlina
        {
            get { return _Dlina; }
            set
            {
                if (value == _Dlina) return;
                _Dlina= value;
                
                OnPropertyChanged("Dlina");
 
                FunktciiaDlini();
            }
        }
Добавлено через 1 час 51 минуту
Хотя наверно IValueConverter надо воспользоваться как советовали

Поторопился с вопросом думал IValueConverter работает по другому а щаз на видео работает так как мне надо. всем спс

Добавлено через 50 минут
Хотя вопрос не доконца решон каким же должно быть условие в Convert и ConvertBack

Добавлено через 19 минут
Заданное приведение является не допустимым
А как тогда его задать допустимо?

Код XML
1
<TextBox Text="{Binding Длинна, Source={StaticResource Material}, Converter={StaticResource dateConverter}, UpdateSourceTrigger=PropertyChanged}"
Ответ: Подскажите в чем минус этой грабли и как её поправить?

Код 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
        string _Количество;
        /// <summary>
        /// Количество
        /// </summary>
        public string Количество
        {
            get { return _Количество; }
            set
            {
                value = value.Replace('.', ',');
                if (value[0] == ',') { value = 0 + value; }
 
                if (value == _Количество) return;
 
                double num;
                bool isNum = double.TryParse(value, out num);
                if (isNum)
                {
                    _Количество = value;
                }
                else
                {
                    _Количество = "0";
                }
                OnPropertyChanged("Количество");
            }
        }
При первом написании любой буквы значение обнуляется, а последующие буквы символы записываются хотя при хотя значение Количество и _Количество все время равно 0
Вопрос: Передача данных в Imagebox (MVVM)

Добрый день,

только только начал вникать в суть WPF и наверное начал процесс с самого конца, то есть с модели программирования MVVM.
В качестве примера для обучения взял написанную мной " на коленках" winforms программу в которой есть один метод, который мне никак не получается переписать...

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
public void CameraConnect(PictureBox pictureBox)
      {
         ThermalCamera.Connect(CameraDeviceInfo = CameraIdentification()[SelectedIndex]);
         ThermalCamera.AutoReconnect = true;
         while (ThermalCamera.ConnectionStatus != ConnectionStatus.Connected)
         {
          Task.Delay(100);
         }
 
         while (ThermalCamera.ConnectionStatus == ConnectionStatus.Connected)
         {
            
            pictureBox.Invoke(new MethodInvoker(delegate ()
            {
              
               pictureBox.Image = ThermalCamera.GetImage().Image;
               pictureBox.Refresh();
               Task.Delay(4000);
               GC.Collect();
               
            }));
         }
 
      }
Суть метода в следующем : подключиться к выбранной IR камере и до тех пор пока статус подключения активен, передавать поток (в виде картинок) из камеры в PictureBox.

В WPF на смену PictureBox приходит ImageBox и несколько другой подход по передачи данных (MVVM).

Итак, есть у меня Viewmodel:

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
 private Image _im;
 
 public Image Im
        {
            get { return _im; }
            set
            {
                _im = value;
                OnPropertyChanged("Im");
            }
        }
 
public void Connection()
        {
            
            _thermalCam.ThermalCamera.AutoReconnect = true;
            _thermalCam.ThermalCamera.Connect(_thermalCam.CameraDeviceInfosList[_selectedItem]);
            // waiting of connection status "Connected"
            while (_thermalCam.ThermalCamera.ConnectionStatus != ConnectionStatus.Connected)
            {
                Task.Delay(100);
            }
            while (_thermalCam.ThermalCamera.ConnectionStatus == ConnectionStatus.Connected)
            {
                Im =_thermalCam.ThermalCamera.GetImage().Image;
                Task.Delay(4000);
 
            }
 
        }
И, есть у меня VIEW:

XML
1
2
3
 <Image Grid.Column="0" DataContext="{Binding Im, Mode= OneWay}"  
VerticalAlignment="Stretch"
 HorizontalAlignment="Stretch" Stretch="Fill">
И, вся эта связка конечно же не работает....

Подскажите, как передать данные в VIEW из ViewModel?
Ответ: Говоря о конвертере, я имел ввиду иной способ. В модели представления ты объявляешь свойство типа Bitmap
C#
1
2
3
4
5
6
7
8
9
10
11
private Bitmap _image;
 
public Bitmap Image
{
    get { return _image; }
    set
    {
        _image = value;
        OnPropertyChanged("Image");
    }
}
Как-то с ним работаешь и биндишь его к свойству Source через конвертер:
XML
1
2
3
<Image Source="{Binding Image, Converter={StaticResource ImageConverter}, Mode=OneWay}"
       HorizontalAlignment="Stretch"
       VerticalAlignment="Stretch" />
Сам конвертер указываешь в ресурсах (окна или приложения)
XML
1
2
3
<Window.Resources>
    <x:ImageConverter x:Key="ImageConverter" />
</Window.Resources>
Ну а класс ImageConverter реализует интерфейс IValueConverter с использованием твоей реализации:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
internal class ImageConverter : IValueConverter
{
    #region Implementation of IValueConverter
 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Imaging.CreateBitmapSourceFromBitmap((Bitmap)value);
    }
 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
 
    #endregion
}
Таким образом интерфейс сам берёт на себя работу по преобразованию свойства, когда ему нужно.
Вопрос: MVVM несколько моделей в одном списке

Привет знатокам.Нужен хелпНадо сделать библиотеку в которой есть книги и журналы(разные сущности).
Как бы мне их запихнуть в один листбокс(ну либо другой список,но они должны быть в одном) ?В один DataGrid их тоже не засунешь,т.к разные атрибуты.Еще есть проблема,как узнать что именно пользователь хочет добавить,журнал либо книгу.
Book model:
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
namespace Library
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;
 
    public partial class Book
    {
        public int id { get; set; }
 
        [StringLength(50)]
        public string Name { get; set; }
 
        [StringLength(50)]
        public string Autor { get; set; }
 
        [StringLength(50)]
        public string Cover { get; set; }
 
        [StringLength(50)]
        public string Genge { get; set; }
 
        [StringLength(50)]
        public string Publisher { get; set; }
 
        [StringLength(50)]
        public string Language { get; set; }
 
        public int? Price { get; set; }
 
        public int? Pages { get; set; }
 
        public int? Year { get; set; }
    }
}
Model Journal
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace Library
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;
 
    [Table("Journal")]
    public partial class Journal
    {
        public int id { get; set; }
 
        public int? Name { get; set; }
 
        public int? Year { get; set; }
    }
}
ViewModel:
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.SqlClient;
using System.Data;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.ObjectModel;
 
namespace Library
{
    class BookViewModel : INotifyPropertyChanged
    {
 
        private Book selectedBook { get; set; }
        public ObservableCollection<Book> Books { get; set; }
        public ObservableCollection<Journal> Journals { get; set; }
 
        #region Commands
        // команда добавления нового объекта
        private RelayCommand addCommand;
        public RelayCommand AddCommand
        {
            get
            {
                return addCommand ??
                  (addCommand = new RelayCommand(obj =>
                  {
                      Book book = new Book();
                      book.Name = "New Book";
                      Books.Insert(0, book);
 
                      selectedBook = book;
                      using (BooksContext context = new BooksContext())
                      {
                          context.Books.Add(SelectedBook);
                          context.SaveChanges();
                      }
                  }));
            }
        }
 
        // команда удаления
        private RelayCommand removeCommand;
        public RelayCommand RemoveCommand
        {
            get
            {
                return removeCommand ??
                  (removeCommand = new RelayCommand(obj =>
                  {
                      Book book = obj as Book;
                      if (book != null)
                      {
                          using (BooksContext context = new BooksContext())
                          {
                              List<Book> temp = context.Books.ToList();
                              var selecteditem = from t in context.Books
                                                 where book.id == t.id
                                                 select t;
                              context.Books.Remove(selecteditem.FirstOrDefault());
 
 
                              context.SaveChanges();
                          }
                          Books.Remove(book);
 
                      }
                  },
                 (obj) => Books.Count > 0));
            }
        }
        
        private ResreshCommand mUpdater;
        public ResreshCommand UpdateCommand
        {
            get
            {
                if (mUpdater == null)
                    mUpdater = new ResreshCommand();
                Update();
                return mUpdater;
            }
            set
            {
                mUpdater = value;
            }
        }
        
        #endregion
        #region Properties
        public int Id
        {
            get
            {
                return SelectedBook.id;
            }
            set
            {
                SelectedBook.id = value;
                OnPropertyChanged("Id");
            }
        }
        public string Name
        {
            get
            {
                return SelectedBook.Name;
            }
            set
            {
                SelectedBook.Name = value;
                OnPropertyChanged("Name");
            }
        }
        public string Autor
        {
            get
            {
                return SelectedBook.Autor;
            }
            set
            {
                SelectedBook.Autor = value;
                OnPropertyChanged("Autor");
            }
        }
        public string Cover
        {
            get
            {
                return SelectedBook.Cover;
            }
            set
            {
                SelectedBook.Cover = value;
                OnPropertyChanged("Cover");
            }
        }
        public string Genge
        {
            get
            {
                return SelectedBook.Genge;
            }
            set
            {
                SelectedBook.Genge = value;
                OnPropertyChanged("Genge");
            }
        }
        public string Publisher
        {
            get
            {
                return SelectedBook.Publisher;
            }
            set
            {
                SelectedBook.Publisher = value;
                OnPropertyChanged("Publisher");
            }
        }
        public string Language
        {
            get
            {
                return SelectedBook.Language;
            }
            set
            {
                SelectedBook.Language = value;
                OnPropertyChanged("Language");
            }
        }
        public int? Price
        {
            get
            {
                return SelectedBook.Price;
            }
            set
            {
                SelectedBook.Price = value;
                OnPropertyChanged("Price");
            }
        }
        public int? Pages
        {
            get
            {
                return SelectedBook.Pages;
            }
            set
            {
                SelectedBook.Pages = value;
                OnPropertyChanged("Pages");
            }
        }
        public int? Year
        {
            get
            {
                return SelectedBook.Year;
            }
            set
            {
                SelectedBook.Year = value;
                OnPropertyChanged("Year");
            }
        }
        #endregion
        public Book SelectedBook
        {
            get { return selectedBook; }
            set
            {
                selectedBook = value;
                OnPropertyChanged("SelectedBook");
            }
        }
 
        public BookViewModel()
        {
            Books = new ObservableCollection<Book>();
            using (BooksContext context = new BooksContext())
            {
                List<Book> temp = context.Books.ToList();
                foreach (var item in temp)
                {
                    Books.Add(item);
                }
            }
        }
 
        public void Update()
        {
            using (BooksContext context = new BooksContext())
            {
                context.Entry(SelectedBook).State = System.Data.Entity.EntityState.Modified;
                context.SaveChanges();
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string prop = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}
XAML:
XML
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
<Window x:Class="Library.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:local="clr-namespace:Library"
        mc:Ignorable="d"
        Title="Library" Height="489.216" Width="525">
    <Window.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="14" />
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="FontSize" Value="14" />
        </Style>
        <Style TargetType="Button">
            <Setter Property="Width" Value="40" />
            <Setter Property="Margin" Value="5" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0.8*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="0.2*" />
        </Grid.RowDefinitions>
        <ListBox Grid.Column="0" ItemsSource="{Binding Books}"
                 SelectedItem="{Binding SelectedBook}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBlock FontSize="18" Text="{Binding Path=Name}" />
                        <TextBlock Text="{Binding Path=Autor}" />
                        <TextBlock Text="{Binding Path=Price}" />
                        <TextBlock Text="{Binding Path=Pages}" />
                        <TextBlock Text="{Binding Path=Cover}" />
                        <TextBlock Text="{Binding Path=Genge}" />
                        <TextBlock Text="{Binding Path=Year}" />
                        <TextBlock Text="{Binding Path=Publisher}" />
                        <TextBlock Text="{Binding Path=Language}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Command="{Binding AddCommand}">+</Button>
            <Button Command="{Binding RemoveCommand}"
                    CommandParameter="{Binding SelectedBook}">-</Button>
            <Button Command="{Binding ResreshCommand}">Update</Button>
                 
            
        </StackPanel>
 
        <StackPanel Grid.Column="1" DataContext="{Binding SelectedBook}">
            <TextBlock Text="Selected book"  />
            <TextBlock Text="Name" />
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Autor" />
            <TextBox Text="{Binding Autor, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Price" />
            <TextBox Text="{Binding Price, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Pages" />
            <TextBox Text="{Binding Pages, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Cover" />
            <TextBox Text="{Binding Cover, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Genge" />
            <TextBox Text="{Binding Genge, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Year" />
            <TextBox Text="{Binding Year, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Publisher" />
            <TextBox Text="{Binding Publisher, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Language" />
            <TextBox Text="{Binding Language, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </Grid>
</Window>
Ответ: Gekr, по ссылке, то что View знает о самой модели, это же нарушает принципы MVVM.
Я конкретно про куски в разметке
XML
1
<DataTemplate DataType="{x:Type local:Album}">
local - как раз ссылка на модель.
Мне кажется правильнее сделать CustomTemplateSelector котоырй будет в зависимости от типа данных в коллекции возвращать нужный DataTemplate
которому в xaml уже расписывать оторажение.
что то типа такого:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public class CustomTemplateSelector : DataTemplateSelector
    {
        public DataTemplate BookTemplate { get; set; }
        public DataTemplate JournalTemplate { get; set; }
 
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (obj is Book) return BookTemplate;
 
            if (obj is Journal) return JournalTemplate ;
 
            return base.SelectTemplate(item, container);
        }
    }
XML
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
<Window x:Class="WpfApplication.Views.MainWindow" Title="lib" 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:behaviors="clr-namespace:WpfApplication.Behaviors"
                 Width="1366" Height="768" MinWidth="640" MinHeight="400">
    <ItemsControl ItemsSource="{Binding Collection, Mode=Default}" >
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Margin="0" x:Name="mainCanvas" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplateSelector>
            <behaviors:CustomTemplateSelector>
                <behaviors:CustomTemplateSelector.BookTemplate>
                    <DataTemplate>
                        <!-- прописываешь шаблон -->
                    </DataTemplate>
                </behaviors:CustomTemplateSelector.BookTemplate>
                <behaviors:CustomTemplateSelector.JournalTemplate >
                    <DataTemplate>
                        <!-- прописываешь шаблон -->
                    </DataTemplate>
                </behaviors:CustomTemplateSelector.JournalTemplate >
            </behaviors:CustomTemplateSelector>
        </ItemsControl.ItemTemplateSelector>
    </ItemsControl>
</Window>
ну и да согласен, надо переписывать модель данных.
П.С.: Думаю, что в коллекции которая биндится к View не должно быть непосредественно объектов модели, должны быть ее View с конкретными полями и т.д.

Добавлено через 5 минут
П.П.С: За CompositeCollection отдельное спасибо Не знал про такую удобную штуку.
Вопрос: DataBindings.Add

Добрый день, возник напрягающий вопрос, который беспокоит уже очень давно.
Задача состоит в выводе определенной строки из БД в richTextBox
Вот мои наброски, выводить не хочет, rtb пуст
C#
1
2
3
4
listBox2.DataSource = oSBindingSource;
                listBox2.DisplayMember = "name";      
                richTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("name",oSBindingSource,"opis",true, DataSourceUpdateMode.OnPropertyChanged));
                richTextBox2.DataBindings.Add(new System.Windows.Forms.Binding("name", oSBindingSource, "history", true, DataSourceUpdateMode.OnPropertyChanged));
Добавлено через 42 минуты
Проблема с отображением решилась, но появилась новая
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if ( listBox1.SelectedIndex == 0)
            {
                listBox2.DataSource = oSBindingSource;
                listBox2.DisplayMember = "name";
                richTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", oSBindingSource, "opis", true, DataSourceUpdateMode.OnPropertyChanged));
                richTextBox2.DataBindings.Add(new System.Windows.Forms.Binding("Text", oSBindingSource, "history", true, DataSourceUpdateMode.OnPropertyChanged));            
            }
            if (listBox1.SelectedIndex == 1)
            {
                listBox2.DataSource = gamesBindingSource;
                listBox2.DisplayMember = "name";
                richTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", gamesBindingSource, "opis", true, DataSourceUpdateMode.OnPropertyChanged));
                richTextBox2.DataBindings.Clear();
                richTextBox2.Visible = false;
            }
При переключении на след. БД вылетает. Подозреваю на то что пред. БД остается подключенной, но как отключить не знаю

Добавлено через 45 минут
Проблема решена, может кому пригодится)
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
if ( listBox1.SelectedIndex == 0)
            {
                richTextBox1.DataBindings.Clear();
                richTextBox2.DataBindings.Clear();
                listBox2.DataSource = oSBindingSource;
                listBox2.DisplayMember = "name";
                richTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", oSBindingSource, "opis", true, DataSourceUpdateMode.OnPropertyChanged));
                richTextBox2.DataBindings.Add(new System.Windows.Forms.Binding("Text", oSBindingSource, "history", true, DataSourceUpdateMode.OnPropertyChanged));
                
            }
            if (listBox1.SelectedIndex == 1)
            {
                richTextBox1.DataBindings.Clear();
                richTextBox2.DataBindings.Clear();
                listBox2.DataSource = gamesBindingSource;
                listBox2.DisplayMember = "name";
                richTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", gamesBindingSource, "opis", true, DataSourceUpdateMode.OnPropertyChanged));
                richTextBox2.Visible = false;
Ответ: Для добавления строк в richTextBox1

C#
1
2
3
4
5
6
7
8
9
10
Forms Code
{
       private void button1_Click(object sender, EventArgs e)
       {
         String s0,s;
          s0 = Environment.NewLine;  //Ввод добавления с новой строки
            s = "??????????"; //Добавляемая строка
             richTextBox1.Text += (s0 + s);
       }
}
Вопрос: Программа висит при попытке открыть ComboBox

Доброго времени суток, разрабатываю приложение , возникла следующая проблемма:

На форме есть несколько ComboBox, и в один из них забиваю порядка 65000 элементов. Когда пытаюсь его открыть, программа висит около 2-2,5 минут. Предполагаю что проблемма в количестве элементов, вернее в том что их подтягивает с черз биндинг, если пытаюсь двинутся вниз по списку опять зависание((((

Подскажите как можно проблемму решить, определенно должен быть какой либо паттерн о котором я не знаю, либо чтото с биндингом накосячил))

Спасибо)))

Добавлено через 53 секунды
MainWindow.xaml:
XML
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<Window x:Class="AKS16_AKS17_CalibrationGui_NewRev.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:local="clr-namespace:AKS16_AKS17_CalibrationGui_NewRev"
        xmlns:con="clr-namespace:AKS16_AKS17_CalibrationGui_NewRev.ServiceClasses.UniversallyServiceClasses"
        xmlns:src="clr-namespace:AKS16_AKS17_CalibrationGui_NewRev.ViewModel"
        mc:Ignorable="d"
        Title="{Binding Path=STitle}" Height="500" Width="1000" MaxHeight="1000" MaxWidth="2000" MinHeight="500" MinWidth="1000" x:Name="WindowView" Closed="WindowView_Closed">
    <!--Window resources-->
    <Window.Resources>
        <con:SizeConvertorForView x:Key="SizeConverter"/>
        <con:VisibilityConverterForView x:Key="VisibilityConverter"/>
        <!--Style difinition for user controls-->
        <Style x:Name="Headers" TargetType="TextBlock" BasedOn ="{StaticResource  BaseText}"/>
        <Style TargetType="ComboBox" >
            <Setter Property="Margin" Value="5"/>
        </Style>
        <!--Style triggers for user controls-->
        <Style TargetType="Menu">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Selector.IsSelected" Value="True"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="False">
                    <Setter Property="Selector.IsSelected" Value="False"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <!--Main markup container-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="40*"/>
            <RowDefinition Height="20*"/>
            <RowDefinition x:Name="ButtonRow" Height="20*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="ButtonColumn" Width="2*"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>
        <!--Logo-->
        <Image Source="/Resources/bo_logo_mit-slogan.png"
               Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="10"/>
        <!--Menus definitions-->
        <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
            <Menu Background="White">
                <MenuItem Header="File" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}">
                    <MenuItem Header="Save Encoder Config" Command="{Binding Path=CommandSaveEncoderConfig}"/>
                    <MenuItem Header="Load Encoder Config" Command="{Binding Path=CommandLoadEncoderConfig}"/>
                    <Separator/>
                    <MenuItem Header="Calibration Setup" Command="{Binding Path=CommandCalibrationSetup}"/>
                    <MenuItem Header="Preference" Command="{Binding Path=CommandPreference}"/>
                    <Separator/>
                    <MenuItem Header="Exit" Command="{Binding Path=CommandExit}"/>
                </MenuItem>
            </Menu>
            <Menu Background="White" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}">
                <MenuItem Header="Tools">
                    <MenuItem Header="Product Information" Command="{Binding Path=CommandProductInformation}"/>
                    <MenuItem Header="Show Protocol Data Packet" Command="{Binding Path=CommandShowProtocolDataPacket}"/>
                    <MenuItem Header="Offset Compensation" Command="{Binding Path=CommandOffsetCompensation}"/>
                    <MenuItem Header="Motor Controller" Command="{Binding Path=CommandMotorController}"/>
                    <MenuItem Header="Serial Port Trigger Signal" Command="{Binding Path=CommandSerialPortTriggerSignal}"/>
                    <MenuItem Header="Sensor Demo" Command="{Binding Path=CommandSensorDemo}"/>
                </MenuItem>
            </Menu>
            <Menu Background="White">
                <MenuItem Header="Help" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}">
                    <MenuItem Header="Send report" Command="{Binding Path=CommandSendReport}"/>
                    <MenuItem Header="About" Command="{Binding Path=CommandAbout}"/>
                </MenuItem>
            </Menu>
        </StackPanel>
        <!--Sensor setup region-->
        <Grid Grid.Column="0" Grid.Row="2">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <!--Headers-->
            <TextBlock Text="Sensor" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="0" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock Text="Size" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="1" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock Text="Interface Absolute" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="2" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock Text="Interface Incremental" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="3" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock x:Name="VariativeComboBox" Text="{Binding Path=SVariativeComboBoxtext}" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="4" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"
                       Visibility="{Binding Path=V_VariativeComboBoxVisibility}"/>
            <!--ComboBoxes-->
            <ComboBox x:Name="SensorType" Grid.Column="1" Grid.Row="0" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}" 
                      ItemsSource="{Binding ComboBoxSensor.Items}"
                      SelectedIndex="0"
                      Text="{Binding ElementName=SensorType, Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <ComboBox x:Name="Size" Grid.Column="1" Grid.Row="1" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}" ItemsSource="{Binding ComboBoxSize.Items}" SelectedIndex="1"/>
            <ComboBox x:Name="InterfaceAbsolute" Grid.Column="1" Grid.Row="2" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"  ItemsSource="{Binding ComboBoxAbsoluteInterface.Items}" SelectedIndex="0"/>
            <ComboBox x:Name="InterfaceIncremental" Grid.Column="1" Grid.Row="3" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"  ItemsSource="{Binding ComboBoxIncrementalInterface.Items}" SelectedIndex="1"/>
            <ComboBox x:Name="ABZResolution" Grid.Column="1" Grid.Row="4" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}" ItemsSource="{Binding ComboBoxVariables.Items}" AutomationProperties.ItemType="String"
                      />
        </Grid>
        <Grid Grid.Column="0" Grid.Row="3" Margin="10">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <CheckBox x:Name="InwertedRotation" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <CheckBox x:Name="SaveRawDatw" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock Text="Inverted Rotation" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
            <TextBlock Text="Save Raw Data" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
        </Grid>
        <Grid Grid.Row="4" Grid.Column="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            
            <Button Content="Details"
                    x:Name="ButtonDetails"
                    Grid.Column="0"
                    Grid.Row="0"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    HorizontalContentAlignment="Center"
                    VerticalContentAlignment="Center"
                    Margin="40,0,0,0"
                    Style="{DynamicResource BaseButton}"
                    Command="{Binding CommandDetails}"
                    Visibility="{Binding Path=VDetailsButton}"/>
            <Button Content="One step calibration" 
                    Grid.Column="1" 
                    Grid.Row="0" 
                    HorizontalContentAlignment="Center" 
                    VerticalContentAlignment="Center" 
                    HorizontalAlignment="Center" 
                    VerticalAlignment="Center" 
                    Style="{DynamicResource BaseButton}"
                    Command="{Binding Path=CommandOneStepCalibration}"/>
        </Grid>
                <Grid Grid.Column="1" Grid.Row="2" Grid.RowSpan="3" Margin="20">
            <UserControl Content="{Binding Path=OrientationOptionControl, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }" IsEnabled="{Binding Path=BDevelopmentMode, Mode=OneWay}"/>
        </Grid>
    </Grid>
 
</Window>
Добавлено через 3 минуты
Сдесь наполняю ComboBoxes:

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using AKS16_AKS17_CalibrationGui_NewRev.ServiceClasses.UniversallyServiceClasses;
 
namespace AKS16_AKS17_CalibrationGui_NewRev.ViewModel
{
    class GUIComboBoxElements: PropertyChangeSupervisor
    {
        private ComboBox cbSensorType;
        public ComboBox CbSensorType
        {
            get { return cbSensorType; }
            set
            {
                cbSensorType = value;
                onPropertyChanged("CbSensorType");
            }
        }
        private ComboBox cbSize;
        public ComboBox CbSize
        {
            get { return cbSize; }
            set
            {
                cbSize = value;
                onPropertyChanged("CbSize");
            }
        }
        private ComboBox cbInterfaceAbsolut;
        public ComboBox CbInterfaceAbsolut
        {
            get { return cbInterfaceAbsolut; }
            set
            {
                cbInterfaceAbsolut = value;
                onPropertyChanged("CbInterfaceAbsolut");
            }
        }
        private ComboBox cbInterfaceIncremental;
        public ComboBox CbInterfaceIncremental
        {
            get { return cbInterfaceIncremental; }
            set
            {
                cbInterfaceIncremental = value;
                onPropertyChanged("CbInterfaceIncremental");
            }
        }
        private ComboBox cbABZResolution;
        public ComboBox CbABZResolution
        {
            get { return cbABZResolution; }
            set
            {
                cbABZResolution = value;
                onPropertyChanged("CbABZResolution");
            }
        }
        private ComboBox cbNumberOfPolePairs;
        public ComboBox CbNumberOfPolePairs
        {
            get { return cbNumberOfPolePairs; }
            set
            {
                cbNumberOfPolePairs = value;
                onPropertyChanged("CbNumberOfPolePairs");
            }
        }
        private List<string> lABZResolution;
        private List<string> lNumberOfPolePairs;
        /// <summary>
        /// Constructor, fills all MainWindow ComboBoxes with default values.
        /// </summary>
        public GUIComboBoxElements()
        {
            Services.FillComboBoxWithItems(out cbSensorType, "AKS16", "AKS17");
            Services.FillComboBoxWithItems(out cbSize, "Large 20-Bit(64/63 Nonius)", "Medium 19-Bit(32/31 Nonius)", "Small 18-Bit(16/15 Nonius)");
            Services.FillComboBoxWithItems(out cbInterfaceAbsolut, "BiSS", "SSI");
            Services.FillComboBoxWithItems(out cbInterfaceIncremental, "None", "ABZ", "UVW", "Step", "CW/CCW");
            lABZResolution = new List<string>();
            for (int i = 4; i<262148; i += 4)
            {
                string s = i.ToString();
                lABZResolution.Add(s);
            }
            Services.FillComboBoxWithItems(out cbABZResolution, lABZResolution);
            lNumberOfPolePairs = new List<string>();
            for (int i = 1; i<17; i++)
            {
                lNumberOfPolePairs.Add(i.ToString());
            }
            Services.FillComboBoxWithItems(out cbNumberOfPolePairs, lNumberOfPolePairs);
        }
        /// <summary>
        /// Adapts ComboBoxItems for actualy selection
        /// </summary>
        /// <param name="selectedItem"></param>
        public void ComboBoxSensorTypeSelectionChanged(ComboBoxItem selectedItem)
        {
            if(((string)(selectedItem.Content)) == "AKS16")
            {
                Services.FillComboBoxWithItems(out cbSize, "Large 20-Bit(64/63 Nonius)", "Medium 19-Bit(32/31 Nonius)", "Small 18-Bit(16/15 Nonius)");
                onPropertyChanged("CbSize");
            }
            else
            {
                Services.FillComboBoxWithItems(out cbSize, "XLarge 24-Bit(1023/1024/992)", "Large 23-Bit(511/512/496)", "Medium 22-Bit(255/256/240)", "Small 21-Bit(127/128/120)");
                onPropertyChanged("CbSize");
            }
        }
    }
}
С помощью этой функции:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
/// <summary>
        /// Fills WPF ComboBox with items
        /// </summary>
        /// <param name="comboBoxToFill">ComboBox to fill</param>
        /// <param name="Items">List of string with items</param>
        public static void FillComboBoxWithItems(out ComboBox comboBoxToFill, List<string> Items)
        {
            comboBoxToFill = new ComboBox();
            for (int i = 0; i<Items.Count; i++)
            {
                comboBoxToFill.Items.Add(Items[i]);
            }
        }
Ответ:
Сообщение от Bars911
Интересно услышать критику, поскольку новичек в WPF)))
Я тоже новичок - стаж меньше 4 месяцев. Но один из "столпов" MVVM все UI элементы должны быть в пределах View.
Сообщение от Bars911
Не совсем так, эта функция из сервисного класса, который вызывается из ViewModel, поскольку в зависимости от выбора пользователя в одном из ComboBox должны меняться Visisbility и Items других .
Для этого вполне достаточно биндинга из View на свойства VM. Не зачем в VM создавать сами элементы.

Добавлено через 5 минут
Вот посмотрите. У Вас в XAML идёт привязка Combox к источнику ItemsSource="{Binding ComboBoxSize.Items}". Можно же в VM создавать не Combox от которого нужно только Items, а создать в VM свойство-перечислитель или список (допустим с именем SizeItems) которое будет возвращать источник данных. И тогда привязку сделать на него ItemsSource="{Binding SizeItems}" Получится тот же самый результат, но без паразитного создания UI элемента.

Добавлено через 1 минуту
Если есть желание - можно пройтись по Вашему приложению и исправить откровенные "коряги".
Вопрос: Как правильно произвести валидацию данных в WPF, не нарушая принципы MVVW?

Как правильно произвести валидацию данных в WPF, не нарушая принципы MVVW?
Если возможно приведите пример.
Мой код в котором должна происходить валидация:

XML
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<Window x:Class="Trade_WPF.View.AddEmployee"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:local="clr-namespace:Trade_WPF.Model"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        mc:Ignorable="d"
        Title="AddEmployee" WindowStartupLocation="CenterScreen"  Background="Beige" MinHeight="300" MinWidth="300" Height="300" Width="300" MaxHeight="300" MaxWidth="300">
    <Window.DataContext>
        <local:AddEmployeesModel/>
    </Window.DataContext>
    <Window.Resources>
     <ControlTemplate x:Key="validationFail">
            <StackPanel Orientation="Horizontal">
                <Border BorderBrush="Violet" BorderThickness="2">
                    <AdornedElementPlaceholder/>
                </Border>
                <TextBlock Foreground="Red" FontSize="26" FontWeight="Black">!</TextBlock>
            </StackPanel>
        </ControlTemplate>
        <Style x:Key="LableStyle" TargetType="Label">
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="Width" Value="60" />
            <Setter Property="Height" Value="26" />
        </Style>
        <Style x:Key="TextBoxStyle" TargetType="TextBox">
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="Width" Value="200" />
            <Setter Property="Height" Value="22" />
            <Setter Property="Background" Value="AliceBlue" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="90"/>
            <ColumnDefinition Width="210"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Label Grid.Column="0" Grid.Row="0" Style="{StaticResource LableStyle}">Name</Label>
        <Label Grid.Column="0" Grid.Row="1" Style="{StaticResource LableStyle}">SurName</Label>
        <Label Grid.Column="0" Grid.Row="2" Style="{StaticResource LableStyle}">BirthDay</Label>
        <Label Grid.Column="0" Grid.Row="3" Style="{StaticResource LableStyle}">Phone</Label>
        <Label Grid.Column="0" Grid.Row="4" Style="{StaticResource LableStyle}">Email</Label>
        <Label Grid.Column="0" Grid.Row="5" Style="{StaticResource LableStyle}">Login</Label>
        <Label Grid.Column="0" Grid.Row="6" Style="{StaticResource LableStyle}">Password</Label>
        <TextBox Name="Name" Grid.Column="1" Grid.Row="0" Style="{StaticResource TextBoxStyle}"  Text="{Binding Path=Name, Mode=TwoWay,UpdateSourceTrigger=Default,  ValidatesOnDataErrors=True}"/>
            <!--  <TextBox.Text>
                <Binding Path="Name" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                    <Binding.ValidationRules>
                        <DataErrorValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox-->
        <TextBox Name="SurName" Grid.Column="1" Grid.Row="1" Style="{StaticResource TextBoxStyle}"> <!-- Text="{Binding Path=SurName, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/-->
            <TextBox.Text>
                <Binding Path="SurName" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                    <Binding.ValidationRules>
                        <DataErrorValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBox Name="Birthday" Grid.Column="1" Grid.Row="2" Style="{StaticResource TextBoxStyle}"> <!-- Text="{Binding Path=Birthday, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/-->
            <TextBox.Text>
                <Binding Path="Birthday" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                    <Binding.ValidationRules>
                        <DataErrorValidationRule />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
 
 
        <TextBox Name="Phone" Grid.Column="1" Grid.Row="3" Style="{StaticResource TextBoxStyle}"> <!-- Text="{Binding Path=Phone, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/-->
        <TextBox.Text>
                <Binding Path="Phone" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                <Binding.ValidationRules>
                    <DataErrorValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
        </TextBox>
        <TextBox Name="Email" Grid.Column="1" Grid.Row="4" Style="{StaticResource TextBoxStyle}"><!-- Text="{Binding Path=Email, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/-->
        <TextBox.Text>
                <Binding Path="Email" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                <Binding.ValidationRules>
                    <DataErrorValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
        </TextBox>
        <TextBox Name="Login" Grid.Column="1" Grid.Row="5" Style="{StaticResource TextBoxStyle}"> <!-- Text="{Binding Path=Login, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/-->
        <TextBox.Text>
                <Binding Path="Login" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True">
                <Binding.ValidationRules>
                    <DataErrorValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
        </TextBox>
        <TextBox Name="Password" Grid.Column="1" Grid.Row="6" Style="{StaticResource TextBoxStyle}">
            <!-- Text="{Binding Path=Password, Mode=TwoWay,UpdateSourceTrigger=Default,  ValidatesOnDataErrors= True}" Validation.ErrorTemplate="{StaticResource validationFail}"/>< Validation.ErrorTemplate="{StaticResource validationFail}"/-->
              <TextBox.Text >
                    <Binding   Path="Password" Mode="TwoWay" UpdateSourceTrigger="Default" ValidatesOnDataErrors="True" >
                <Binding.ValidationRules>
                    <DataErrorValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
        </TextBox>
        <Canvas Grid.Row="7" Grid.ColumnSpan="2">
            <Button MinHeight="23" MinWidth="60" Canvas.Left="222" Canvas.Top="5" Content="Censel"  Command="{Binding CenselAdd}"/>
            <Button MinHeight="23" MinWidth="60" Canvas.Left="139" Canvas.Top="5" Content="OK"  Command="{Binding OkAdd}" />
        </Canvas>
    </Grid>
</Window>
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
class AddEmployeesModel :BindableBase, IDataErrorInfo
    {
        private string _login;
        private string _password;
        private string _name;
        private string _surName;
        private string _phone;
        private string _email;
        private string _birthday;
        public string Login
        {
            get 
            {
                return _login;
            }
            set 
            {
                _login = value;
                base.OnPropertyChanged("Login");
            }
        }
        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                _password = value;
                base.OnPropertyChanged("Password");
            }
        }
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                base.OnPropertyChanged("Name");
            }
        }
        public string SurName
        {
            get
            {
                return _surName;
            }
            set
            {
                _surName = value;
                base.OnPropertyChanged("SurName");
            }
        }
        public string Phone
        {
            get
            {
                return _phone;
            }
            set
            {
                _phone = value;
                base.OnPropertyChanged("Phone");
            }
        }
        public string Email
        {
            get
            {
                return _email;
            }
            set
            {
                _email = value;
                base.OnPropertyChanged("Email");
            }
        }
        public string  DateBirth
        {
            get
            {
                return _birthday;
            }
            set
            {
                _birthday = value;
                base.OnPropertyChanged("DateBirth");
            }
        }
       // private bool isNotCharSymbolLogin;
          private const string patternLogin = @"\d";
          private const string patternPassword = @"\s|\d";
          private const string patternName = "";
          private const string patternSurname = "";
          private const string patternPhone = @"\([0-9]{3}\)[0-9]{7}";
          private const string patternEmail = @"\w+@[a-zA-Z]+?\.[a-zA-Z]{2,6}";
          private const string patternDateBirth = @"(\d{1,2}\/\d{1,2}\/\d{4})";
          private const string pattern2 = @"(\d{1,2}\.\d{1,2}\.\d{4})";
          private const string pattern3 = @"(\d{1,2}\,\d{1,2}\,\d{4})";
 
          private string error;
          public string this[string columnName]
          {
              get
              {
                  Regex regex = null;
                  switch (columnName)
                  {
 
                      case "Login":
                          {
                              Error = "Not valid";
                              break;
                          }
                      case "DateBirth":
                          {
 
                              Regex regex2 = new Regex(pattern2);
                              Regex regex3 = new Regex(pattern3);
                              regex = new Regex(patternLogin);
 
                              if (Login == null || regex.IsMatch(_birthday) || regex2.IsMatch(_birthday) || regex3.IsMatch(_birthday))
                              {
                                  Error = "Not valid";
                              }
                              break;
                          }
                      case "Password":
                          {
                              regex = new Regex(patternPassword);
 
                              if (!regex.IsMatch(_password))
                              {
                                  Error = "Not valid";
                              }
                           
                              break;
                          }
                      case "Name":
                          {
                             // error = "Not valid";
                              if ((_name==null)||(_name ==""))
                              {
                                  Error = "Not valid";
                              }
 
                              break;
                          }
                      case "SurName":
                          {
                              if (_surName == null)
                              {
                                  Error = "Not valid";
                              }
                              break;
                          }
                      case "Phone":
                          {
                              regex = new Regex(patternPhone);
 
                              if (!regex.IsMatch(_phone))
                              {
                                  Error = "Not valid";
                              }
                             
                              break;
                          }
                      case "Email":
                          {
                              regex = new Regex(patternEmail);
 
                              if (!regex.IsMatch(_email))
                              {
                                  Error = "Not valid";
                              }
                              break;
                          }
                        default:
                          break;
                  }
                  return error;
              }
          }
        public string Error
        {
            get 
            {
                throw new NotImplementedException();
            }
            set
            {
                if (error != null)
                {
                     error =value;
                }
            }
        }
        Employees emp;
        public DelegateCommand OkAdd { get; set; }
        public DelegateCommand CenselAdd { get; set; }
 
        static  AddEmployee _addEmp;
        public AddEmployeesModel()
        {
            OkAdd = new DelegateCommand(Add);
            CenselAdd = new DelegateCommand(Censel);
            emp = new Employees();
        }
        public static void GetAddEmployee(AddEmployee _addEmp1)
        {
            _addEmp = _addEmp1;
 
        }
    }
}
Ответ:
Сообщение от Tema12345
Спасибо огромное! очень познавательная статья !
Tema12345, а теперь покажите, как вы исправили ошибки из стартового поста, после прочтения статьи
Вопрос: Использование EntityFramework в шаблоне MVVM

Недавно начал изучать шаблон MVVM и хотел бы узнать правильно ли я делаю, или нужно как-то иначе (пока команды не использую, это сейчас не принципиально).
Вот простейший код для отображения и заполнения данных о справке (таких форм может быть много в интерфейсе):
Пользователь может очистить всю информацию и при сохранении запись должна удаляться из базы. Или, если создаётся новая запись и пользователь ничего не заполняет, то она не должна попасть в базу при сохранении других форм интерфейса. Для отслеживания этих состояний служит свойство IsEmpty. Возможно это всё вообще неправильно и так не делают. Хочу разобраться как надо правильно делать. По возможности, объясните, если у меня две сущности Master и Detail, как поступить с ними?

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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    public class CertificateView : INotifyPropertyChanged, IDisposable
    {
        private MyDataContext _dbContext;
        private int _id;
 
        private Certificate _cert;
        private Certificate Certificate
        {
            get
            {
                if (_cert != null)
                    return _cert;
 
                if (_dbContext == null)
                    _dbContext = MyDataContext.GetNewContext();
 
                _cert = _dbContext.Certificate.Find(_id);
 
                if (_cert == null)
                {
                    _cert = new Certificate();
                    _dbContext.Certificate.Add(_cert);
                    IsEmpty = true;
                }
 
                return _cert;
            }
        }
 
        private bool IsEmpty { get; set; }
 
        public int? Num
        {
            get { return Certificate.Num; }
            set
            {
                IsEmpty = false;
                Certificate.Num = value;
                OnPropertyChanged(() => Num);
            }
        }
 
        public int? NumBlank
        {
            get { return Certificate.NumBlank; }
            set
            {
                IsEmpty = false;
                Certificate.NumBlank = value;
                OnPropertyChanged(() => NumBlank);
            }
        }
 
        public DateTime? Date
        {
            get { return Certificate.Date; }
            set
            {
                IsEmpty = false;
                Certificate.Date = value;
                OnPropertyChanged(() => Date);
            }
        }
 
        
        public CertificateView(int certID)
        {
            _id = certID;
        }
 
        public void Cancel()
        {
            _dbContext.CancelStateForEntity(Certificate);
            _cert = null;
 
            NotifyAllProperties();
        }
 
        public void Refresh()
        {
            Dispose();
 
            NotifyAllProperties();
        }
 
        public void Save()
        {
            if (IsEmpty)
            {
                _dbContext.Certificate.Remove(Certificate);
                _cert = null;
            }
 
            _dbContext.SaveChanges();
        }
        
        public void Clear()
        {
            _cert.Num = null;
            _cert.NumBlank = null;
            _cert.Date = DateTime.Now;
            IsEmpty = true;
            
            NotifyAllProperties();
        }
 
        private void NotifyAllProperties()
        {
            OnPropertyChanged(() => Num);
            OnPropertyChanged(() => NumBlank);
            OnPropertyChanged(() => Date);
        }
 
        public void Dispose()
        {
            if (_dbContext != null)
            {
                _dbContext.Dispose();
                _dbContext = null;
                _cert = null;
            }
        }
        
        public event PropertyChangedEventHandler PropertyChanged;
        
        protected virtual void OnPropertyChanged<T>(Expression<Func<T>> p)
        {
            var tmp = PropertyChanged;
            if (tmp != null)
                tmp(this, new PropertyChangedEventArgs((p.Body as MemberExpression).Member.Name));
        }
    }
Ответ: Насчет создания сущностей по примеру с покупкой - после создания вы можете сразу же загрузить их в базу, а при редактировании выгрузить и замэппить в VM.

Сообщение от SharpProg
Хотя сейчас мне такой подход уже не нравится и я его делать не буду.

Часто бывает, что пока вслух не расскажешь о проблеме - не найдешь сразу решение.

Сообщение от SharpProg
MVVMC - интересная идея, но пока не вижу в ней особого смысла.
Таки да. Я когда с mvvm сталкивался также не видел (хотя мой mvvm там совсем какушечный был) сейчас же работаю с mvc и размышляю насчет mvvm и проблемы "чего-то там не хватает.."