Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
1 / 1 / 0
Регистрация: 11.05.2022
Сообщений: 28

Данные из другого потока, mvvm

08.12.2022, 22:59. Показов 1491. Ответов 26
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте
Помогите, плизз, мне решить задачку. Я бы хотел, в рамках патnерна mvvm, реализовать следующее: ViewModel в конструкторе запускает поток, который ждет данные по TCP/IP. Затем эти данные обрабатываются и отображаются
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
public class ViewModel
{
        #region Свойства
        /// <summary>  /// Динамические данные для отображения  /// </summary>
        public ObservableCollection<DrawDown> DataDraw { get; }
        ///// <summary>  /// Выбранная категория   /// </summary>
        private DrawDown _SelectedCategory;
        public  DrawDown SelectedCategory { get => _SelectedCategory; set => Set(ref _SelectedCategory, value); }
        #endregion
 
       #region Поля
        ...
        Thread workerThread;
        ...
        #endregion
 
       public ViewModel()
        {
            #region Свойства
            DataDraw = new ObservableCollection<DrawDown>();
            #endregion
                        
            #region Закулисье
            workerThread = new Thread(ThreadWorker);
            workerThread.Start();   
            #endregion
            ...
 
        }
        ~ViewModel()
        {
            App.EndWork = true;
            workerThread.Join();    
        }
 
        private void ThreadWorker()
        {            
            IPEndPoint ipServer = null;
            Socket Server = null;
            byte[] buffer = null;
 
            App.eventWaitForStart.WaitOne(); // - жду пока сформируется currSource из логики окна
            
            ipServer = new IPEndPoint(IPAddress.Parse(App.currSource.Ipaddress), App.currSource.Ipport);
         
            Server = new Socket(ipServer.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
         
            Server.Bind(ipServer);
 
            Server.Listen(1);
 
            while (!App.EndWork)
            {
                Socket client = Server.Accept();
                
                try
                {
                    int sizeBuff = client.Available;
                    if (sizeBuff != 0)
                    {
                        buffer = new byte[sizeBuff];
                        client.Receive(buffer);
                    }
 
                    if (buffer != null)
                    {
                        //предполагается несколько пакетов вдальнейшем
                        dataPackages = new ObservableCollection<DataPackage>();
 
                        string xmlData = ConvertByteArrayToString(buffer);
                        DataPackage dataPackage = null;
                        dataPackage = DeserializeFromXML(xmlData);
 
                        dataPackages.Add(dataPackage);
 
                        cStatuses = (List<CStatus>)ReadStatus_Tbl._getStatus();
 
                        for (int i = 0; i < dataPackages.Count; ++i)
                        {
                            App.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                                (System.Threading.ThreadStart)delegate
                                {
                                    DrawDown drawDown = new DrawDown();
                                    drawDown.Tcentral = dataPackages[i].Tcentral;
 
                                    CStatus stat = cStatuses.Find(s => Equals(s.Tcentral, drawDown.Tcentral));
                                    drawDown.Status = (short)stat.Status;
 
                                    drawDown.Description = dataPackages[i].Description;
                                    drawDown.Time = dataPackages[i].Time;
                                    int k = App.DarawDownViewModel.DataDraw.IndexOf(drawDown);
                                    if (k < 0)
                                    {
                                        drawDown.dataPackages.Add(dataPackages[i]);
                                        DataDraw.Add(drawDown);
                                    }
                                    else
                                    {
                                        DataDraw[k].dataPackages.Add(dataPackages[i]);
                                    }
                                });
                        }
                    }
                }
                catch (SocketException ex)
                {
                    netLog.Error("Связь разорвана!!! {0} (код ошибки {1})", ex.Message, ex.ErrorCode);
 
                    client.Close();
 
                    continue;
                }
                catch (Exception ex)
                {
                    netLog.Error("Связь разорвана!!! {0} (код ошибки {1})", ex.Message);
 
                    client.Close();
 
                    continue;
 
                }
                             
            }
        }
}
Ну и разметка:
XML
1
2
3
4
5
6
7
8
9
10
       ...
        <Grid >
                    <Grid.DataContext>
                        <mv:ViewModel/>
                    </Grid.DataContext>
                    <DataGrid ItemsSource="{Binding DataDraw}" SelectedItem="{Binding SelectedCategory}"
                                  ...
                                  >
                    ...
        </Grid>
Программа работает не корректно... Данные не отображаются... Еще и поток не освобождается по завершению
Вместо Thread я попытался использовать BackgroundWorker, но получил стандартную ругань: доступ к контролу не из потока Dispatcher
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
08.12.2022, 22:59
Ответы с готовыми решениями:

[mvvm] Привязка данных которые изменяются из другого потока
здравствуйте, есть проблема следующего рода: есть поток(Task) который получает данные из сети и меняет viewmodel, но форма отказывается...

Не работает (видимо) байндинг при добавлении в коллекцию из другого потока (MVVM)
В общем, написал программу (WPF). Когда весь код был в MainWindow.xaml.cs, то такой код нормально работал: private...

Как изменить данные UI формы из другого потока
Есть MainWindow: using System.Threading; ... namespace WpfApplication1 { public partial class MainWindow : Window {...

26
1 / 1 / 0
Регистрация: 11.05.2022
Сообщений: 28
12.12.2022, 23:04  [ТС]
Студворк — интернет-сервис помощи студентам
Здравствуйте
Элд Хасп, благодарю, что уделяете внимание мне

Общая суть: есть модуль 'ReaderRS' - считывает пакеты из RS-каналов и формирует таблицы, есть модуль 'ReadDB' - который считывает и раздает в такте пакеты Opereator-ам , которые могут быть как удаленно, так и на одной машине (Astera). Сперва, как я предлагаю, регистрируются операторы - 'Operator_registration', заполняющая форму оператора. Эта таблица формируется на всех машинах операторов. Забегая вперед по пунктам, эта программа также редактирует и удаляет записи операторов:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И если будет этот ключ, то непонятно зачем нужен Id. Они будут дублировать друг друга. Где-то ещё Id используется?
- этот Id я назначил как "primary key identity"
Цитата Сообщение от Элд Хасп Посмотреть сообщение
1) Судя по методу EnterDialog в MainWindow вы работаете...
т.к. сейчас стадия разработки, то эти 2 оператора для отладки. Я б из Dlg возвратил количество операторов и в цикле создал бы программно GUID и использовал бы семафор - конструкция работает! Уже хоть какая-нибудь защита от повторного запуска.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
3) Как понял по логике...
сюда же
Цитата Сообщение от Элд Хасп Посмотреть сообщение
...Непонятно зачем вы проверяете открытые сеансы через семафоры...
сюда же

Цитата Сообщение от Элд Хасп Посмотреть сообщение
2) ...БД (метод ReadOperatorSett._updateOperator). Что за путаница? Объясните эту задумку.
В таблице регистрации Оператора есть поле 'Online'. Напоминаю:
C#
1
2
3
4
5
6
7
8
9
10
11
12
...
 private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //Сигнализирую - оператор подключился
            ReadOperatorSett._updateOperator(App.currOperator.OperatorSurname, 0b1);
        }
 
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {           
            ReadOperatorSett._updateOperator(App.currOperator.OperatorSurname, 0);
        }
...
Оператор, а скорее какой-то манагер может захотеть посмотреть какие App операторов запущены.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16152 / 11273 / 2890
Регистрация: 21.04.2018
Сообщений: 33,147
Записей в блоге: 2
13.12.2022, 00:35
MacksTiger, приглашение получил и принял.
Со временем в рабочие дни - очень туго.
Как будет - посмотрю. Возможно накидаю пример.
Пока попробуйте сами внести изменения о которых я писал в прошлом сообщении.

Цитата Сообщение от MacksTiger Посмотреть сообщение
то эти 2 оператора для отладки. Я б из Dlg возвратил количество операторов
Придуманный вами способ отладки очень плохой.

Эти Операторы, их проверка - относятся к БЛ и очень сильно влияют на архитектуру данных.
А использование списка и двух константных операторов требуют совершенно разной архитектуры данных.
При смене архитектуры весь смысл отладки теряется.
Поэтому даже если вы хотите отладить без БД, то всё равно должны формироваться не константные операторы, а список операторов. Соответственно условие их проверки тоже должно быть по списку. И ключ-имя (который вы используете в семафоре) должно быть частью состояния Оператора, а не константой в коде.

Сами семафоры следует, как минимум, заменить на мютексы.
И то, только при условии что допускается работа одного и того же оператора (вернее под его именем) одновременно на разных компах.
Если не допускается, то всё это нужно просто выкинуть.
Если нужна проверка по всей сети, то делать это нужно только через сервер.
А эти семафоры (или мютексы) только запутывают код и сбивают с толку.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16152 / 11273 / 2890
Регистрация: 21.04.2018
Сообщений: 33,147
Записей в блоге: 2
13.12.2022, 20:30
MacksTiger, в классе CStatus свойства какие значения могут принимать?
Как стринги в нём очень криво смотрятся.

Добавлено через 1 минуту
Особенно byte Status.

Добавлено через 4 минуты
В классе RWStatusSett не должно быть ни каких MessageBox. Исключения надо оставить как есть. Пусть их отлавливает тот кто вызывает его методы.
0
1 / 1 / 0
Регистрация: 11.05.2022
Сообщений: 28
13.12.2022, 23:34  [ТС]
Здравствуйте

Цитата Сообщение от Элд Хасп Посмотреть сообщение
MacksTiger, в классе CStatus свойства какие значения могут принимать?
- я задумал так: пакеты рассылаются на все станции операторов, когда кто-то из операторов берет на обработку сигнал, нажимая на элемент списка сигналов, он меняет статус сигнала (к примеру 1 - не 'взят', 2 - в обработке, 3 - обработан ). Остальные операторы должны видеть статуса сигналов. Когда сигнал обработан, он удаляет из таблицы бд. У меня есть таблица, в которой 'Tcentral' - char, а Status - tinyint
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если нужна проверка по всей сети, то делать это нужно только через сервер.
- последую вашему совету. Условный модуль 'ReadDB' будет все это обеспечивать

Цитата Сообщение от Элд Хасп Посмотреть сообщение
В классе RWStatusSett не должно быть ни каких MessageBox.
-понял, спс. ща уберу
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16152 / 11273 / 2890
Регистрация: 21.04.2018
Сообщений: 33,147
Записей в блоге: 2
14.12.2022, 01:35
Цитата Сообщение от MacksTiger Посмотреть сообщение
он меняет статус сигнала (к примеру 1 - не 'взят', 2 - в обработке, 3 - обработан
Это нормальная задумка.
Я в принципе так и думал.
Но вам нужно 3-5 значений.
А вы задаёте целый байт.

В таких случаях применяется два решения:
1) Status - имеет тип перечисления. Перечисление удобно тем, что его можно интерпретировать как строку и как инт. Но изменить перечисление без новой сборки приложения не получится.;
2) Status - это отдельный тип с Id и строкой значения. Список всех возможных статусов получается из отдельной таблицы БД. Эта реализация чуть сложнее, но позволяет изменять набор допустимых статусов без пересборки приложения. Во "взрослых" решениях (например, сервер биржи) применяется именно такая реализация.

Цитата Сообщение от MacksTiger Посмотреть сообщение
- последую вашему совету. Условный модуль 'ReadDB' будет все это обеспечивать
Ок.
Часть логике работы с БД останется за вами. Здесь я знаю только общие принципы. Если вам понадобятся какие-то тонкости, то придётся обращаться в раздел ADO.

Цитата Сообщение от MacksTiger Посмотреть сообщение
ща уберу
Я уже убрал.
И сделал небольшой рефакторинг.

На данный момент в решении созданы два репозитория RWOperatorSett и RWStatusSett.
Возможно в них ещё добавятся другие методы, но для начала получено некое разделение. Нужны Операторы обращаемся к RWOperatorSett, нужны статусы - к RWStatusSett.
Токо названия избыточные. Понятнее будет OperatorsSet и StatusesSet.

Добавлено через 3 минуты
Эти два репозитория объединим под "одной крышей".
Для чего это приложения, чем управляют операторы?
Вот по предметной области и назовите.
В этом типе будет приватное поле со строкой соединения и, пока, два репозитория.

Добавлено через 9 минут
Следующий шаг - нужно получить рабочий сеанс.
Я не совсем представляю как это реализовать на уровне БД, но примерно по логике должно быть такое:
1) Получили всех операторов;
2) У каждого оператора есть свойство указывающего есть ли у него действующий сеанс;
3) Показываем всех операторов, но выбрать можно только тех у которого нет рабочего сеанса;
4) Для выбранного оператора происходит запрос на создание сеанса;
5) Происходит перепроверка сеанса в БД. Если его до сих пор нет, то создаётся для этого оператора. Это должно происходить в одной транзакции, чтобы не было конфликта при одновременном создании двух сеансов;
6) После успешного создания, он запоминается в Модели. Представление получив событие об этом закрывает Окно (или страницу) авторизации и переходит к рабочему Окну.
7) Если создание сеанса не успешно, то выводится сообщение о причине провала. И юзер может выбрать другого оператора.

Добавлено через 2 минуты
Здесь нужно учесть один нюанс.
При корректном выходе из приложения, сеанс в БД будет закрыт или удалён.
А вот при некорректном? Вырубился комп, обрыв соединения? То есть нужен какой-то механизм сброса сеанса для таких случаев.
1
1 / 1 / 0
Регистрация: 11.05.2022
Сообщений: 28
15.12.2022, 19:10  [ТС]
Здравствуйте
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Я не совсем представляю как это реализовать на уровне БД,
признаюсь, я тем более...
Я склоняюсь перейти та такую структуру: модуль 'ReaderRS', модуль ServerOperator&DB (бывший 'ReadDB') и Operator-ы. Где все взаимодействие будут такими:
'RS'->ReaderRS->DB
DB<->ServerOperator&DB<-TCP/IP->Operator-ы

Сделаю наброски 'ServerOperator&DB' и выложу в git

Добавлено через 3 минуты
P.S.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
5) Происходит перепроверка сеанса в БД. Если его до сих пор нет, то создаётся для этого оператора. Это должно происходить в одной транзакции, чтобы не было конфликта при одновременном создании двух сеансов;
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16152 / 11273 / 2890
Регистрация: 21.04.2018
Сообщений: 33,147
Записей в блоге: 2
15.12.2022, 19:22
Цитата Сообщение от MacksTiger Посмотреть сообщение
признаюсь, я тем более...
Тогда стоит обратиться в раздел ADO.
Моих знаний хватит только для общего, поверхностного понимания, что нужно сделать.

Создайте там тему. В ней дайте ссылку на эту тему. И опишите проблему (если я правильно понимаю) примерно так:
- есть такая-то БД на сервере в локалке;
- с ней могут работать одновременно разные операторы;
- любой оператор может работать с любого компа;
- на любом компе может быть открыто одновременно несколько сеансов для разных операторов;
- один оператор может открывать одновременно только один сеанс во всей локалке.

Необходимо:
- получение списка операторов и у каких из них нет открытых сеансов;
- создание сеанса для выбранного оператора, если это возможно;
- корректно завершение сеанса в случае сбоев на локальном компе или в локальной сети.

Естественно несколько подробнее, с деталями реализации имеющими существенное значение.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
15.12.2022, 19:22
Помогаю со студенческими работами здесь

MVVM - Как в UserControl передавать данные с другого UserControl
Получаем данные в UserControl1 и при переключении на другой UC2 нужно передать определённые данные ему. Как это сделать? Желательно пример,...

Как получить данные из другого потока?
Здравствуйте. Приложение выполняется в 2 потока. В процессе выполнения необходимо получать данные из другого потока для вывод их в...

Как вывести данные в textbox из другого потока?
Добрый день, как вывести данные, допустим, в textbox из другого потока? TextBox t =...

Как из одного потока узнать состояние другого потока
Подскажите пожалуйста, как из одного потока узнать, что другой поток еще не запущен. Например, второй поток формируется в классе...

Получить данные от ComboBox из другого потока
Как проверить данное условие из потока, не создавшего ComboBox? if ((comboBox1.SelectedItem is _Class1) &amp;&amp;...


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

Или воспользуйтесь поиском по форуму:
27
Ответ Создать тему
Новые блоги и статьи
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
Модель здравосохранения 16. Слишком хорошие и здоровые сотрудники уходят, недовольные зарплатой
anaschu 23.05.2026
Отладка увольнений и настройка производительности Сегодня во второй половине дня разобрались с механикой увольнений и настроили коэффициент сложности заданий. Вот что было сделано. . . .
Как я стал коммунистом))) Модель сохранения здоровья сотрудников, запись блога номер 15
anaschu 23.05.2026
Внезапно хорошее здоровье сотрудников не нужно капиталистам?))
Модель здравоСохранения 15. Как мы чинили AnyLogic модель рабочего коллектива: сочленение диаграммы состояний болезней и поломок в ресурспул
anaschu 23.05.2026
Как мы чинили AnyLogic модель рабочего коллектива Сегодня разобрались с пятью багами, из-за которых модель либо падала с ошибкой, либо давала совершенно бессмысленные результаты. Каждый баг был. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru