Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3

Асинхронное обновление состояния команды

06.05.2024, 23:11. Показов 3893. Ответов 65
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
xellan24rus, скорее всего порядок "обновления" на это влияет. Потому что не раз сталкивался немного с другой вещью: есть свойство в VM, оно же используется в качестве CanExecuted в некой команде. Но! Если привязать элемент View IsEnabled к тому свойству напрямую - все замечательно. А вот, если этот элемент ведется от этого же свойства, но от команды - он "енаблируется" только по тычку мыши по окну! Хотя все возможные дебаги показывают что это свойство давно уже в TRUE. Не стал сильно разбираться, переделал, но пока такой вот "факт" остался непонятным явлением...

Добавлено через 3 минуты
Иными словами, происходит некая "серия команд", часть из которых не достигает получателей (типа застревает), но если тыкнуть окно - все приходит. Что интересно - точно с таким же проектом на таких же условиях все работает. Вообще не понял что происходит с этим, каждую запятую проверял - ну блин вообще отличий нет. Но не работает. Чудеса.
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
06.05.2024, 23:11
Ответы с готовыми решениями:

Потоки: асинхронное обновление объектов на карте
Здравствуйте, разрабатываю приложение с картой, на карте есть объекты, которые постоянно должны обновлять. Как это сделать? Хочу сделать...

Принудительное обновление UI для обновления кнопки по состоянию команды
Добрый день. Есть View и соответствующая ViewModel со стандартной реализацией INotifyPropertyChanged, а также типичная реализация...

Асинхронное обновление Partial view
Суть примера в следующем: 1. Есть один единственный совсем не хитрый контроллер. public ActionResult Index() { ...

65
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
08.05.2024, 17:15
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от wizard41 Посмотреть сообщение
Сейчас приделаю это.
с Task.Run я ранее код кидал там работало четко все от свойства

Добавлено через 2 минуты
wizard41, а если сделать локальный сервер для активации и деактивации Enable? Допустим даже фокуса у окна не будет и клика. Только в реальном времени должен обновить свойство локальный сервер. Такая симуляция подойдет под ваш вопрос? Можно HttpListern сделать чтобы не заморачиваться так сильно
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 17:53  [ТС]
Цитата Сообщение от xellan24rus Посмотреть сообщение
Такая симуляция подойдет под ваш вопрос?
Да, конечно это будет самое то. Сейчас попробую с Task.Run сперва
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
08.05.2024, 18:07
Цитата Сообщение от wizard41 Посмотреть сообщение
Сейчас попробую с Task.Run сперва
заберите код с примера что я ранее отправил в смс. Может с ним что то выйдет. Как раз там другой поток + задержка.
Цитата Сообщение от wizard41 Посмотреть сообщение
Да, конечно это будет самое то.
Тогда это идеальная симуляция)
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
08.05.2024, 19:14
Цитата Сообщение от xellan24rus Посмотреть сообщение
а если сделать локальный сервер для активации и деактивации Enable? Допустим даже фокуса у окна не будет и клика.
Это нисколько не будет отличаться от подачи сигнала из другого потока в самом приложении.
Для полной имитации (чтобы исключить фактор фокуса окна) можно создать 3-5 секундный таймер (System.Timers.Timer или System.Threading.Timer).

Я думаю, что ошибка в чём-то ином. И при попытке воспроизведения проблемы, wizard41, вполне возможно, сам найдёт её причину.
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
08.05.2024, 19:23
Элд Хасп, тоже верно. Загвоздка в воспроизведение примера только.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
можно создать 3-5 секундный таймер (System.Timers.Timer или System.Threading.Timer).
А если свернуть приложение и там пробовать с сервера работать с Enable? тогда фокуса не будет.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
08.05.2024, 22:45
Цитата Сообщение от xellan24rus Посмотреть сообщение
тогда фокуса не будет.
Достаточно выбрать другое окно. А кнопка должна продолжать мигать Enabled-Disabled
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 23:16  [ТС]
Залил клавиатуру, пришлось разбирать/стирать/сушить...
xellan24rus, попробовал ваш EnabledCommandAsync() - результат тот же:

Кнопка что активится от Команды - не активируется. Ну и это как бы предполагается, т.к. проблема не в источнике сигнала, а в самой команде... Что-то вокруг этого крутится.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 23:17  [ТС]
C#
1
2
3
4
5
6
7
8
9
10
11
12
        private ICommand comAsyncCommand;
        public ICommand ComASyncCommand =>
            comAsyncCommand ?? (comAsyncCommand = new RelayCommand(async execute => await EnabledCommandAsync()));
 
        private async Task EnabledCommandAsync()
        {
            await Task.Run(async () =>
            {
                await Task.Delay(500);
                Device1.Enabled = !Device1.Enabled;
            });
        }
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 23:21  [ТС]
Приложил проект, если будет время натурально посмотреть что происходит.
Вложения
Тип файла: 7z WpfApp_TestCommandIncp.7z (16.1 Кб, 10 просмотров)
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 23:36  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это нисколько не будет отличаться от подачи сигнала из другого потока в самом приложении
Да, потому что сигнал от реального устройства тоже фактически из другого потока прилетает. А окну какая разница что в самом потоке происходит и в каком.
Поэтому Async Task полностью эмулирует ситуацию.

Добавлено через 11 минут
Надо попробовать какую-то другую базовую реализацию ICommand. Считаю, что неправильно работает моя текущая реализация, хотя она вполне себе "стандартная" - как у всех.
Раньше этот момент "замаскировывался" тем, что все команды приходили от элементов самого окна и такая ситуация была не видна. Но как только источник команды стал "сторонним" - вылезли такие странные вещи.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
08.05.2024, 23:46
Цитата Сообщение от wizard41 Посмотреть сообщение
Надо попробовать какую-то другую базовую реализацию ICommand.
Попробуйте эту.
Простые реализации для тем на форуме

Добавлено через 4 минуты
Цитата Сообщение от wizard41 Посмотреть сообщение
Приложил проект
C#
38
39
40
41
        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }
Здесь должен быть переход в UI поток.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
08.05.2024, 23:49  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Попробуйте эту.
Ага, завтра буду пробовать, крутить-вертеть... Надо понять что тут не так.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
08.05.2024, 23:56
C#
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    internal class AsyncRelayCommand : ICommand
    {
        private readonly Func<Task> _execute;
        private readonly Func<bool> _canExecute;
 
        public event EventHandler CanExecuteChanged;
 
        public AsyncRelayCommand(Func<Task> execute, Func<bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
 
        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute();
        }
 
        public async void Execute(object parameter)
        {
            await _execute();
        }
Смысл этой реализации, вообще, ускользает от меня.
"А чтобы было!" - наверное?

Добавлено через 2 минуты
Вот здесь есть ссылка на более-менее нормальную реализацию асинхронных команд: Интерфейс и асинхронность

Добавлено через 1 минуту
А ваша реализации по сути ничего не упрощает при применении, только добавляет ещё один лишний тип.

Добавлено через 2 минуты
C#
6
7
8
9
10
11
12
13
14
15
16
    internal abstract class BaseCommand : ICommand
    {
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
 
        public abstract bool CanExecute(object parameter);
        public abstract void Execute(object parameter);
    }
Какая-то гибридно мутантная реализация.
Для UWP - не подойдёт так как есть CommandManager.
Для WPF не подойдёт так как нет публичного метода поднятия CanExecuteChanged.
1
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 00:15  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Смысл этой реализации, вообще, ускользает от меня.
Это только сегодня появилось - AsyncRelayCommand предложил xellan24rus...
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 14:42  [ТС]
Элд Хасп, в общем, потыкался с разными вариантами RelayCommand - пока ситуация остается прежней.

Почему это работало в первой версии:
Рассмотрел детально первый проект, где все команды и их CanExecute отрабатывали четко - оказалось, там я контролировал флаг ComConnection, который просто отвечает за факт соединения с COM-портом, а это происходит почти моментально.
Проблема появилась именно тогда, когда я стал проверять ответ от устройства - а он, само собой, приходит не сразу а с некоторой задержкой. Вот тут то все и поломалось.

Почему это работает для другого устройства по USB:
Тут почти точно так же, как описано выше - устройство USB либо есть, либо его нет. И если оно есть, то подключение к нему происходит мгновенно, что сразу же отражается на свойстве в команде и она работает правильно (активирует canexecute).

От сюда возникает вывод, что причина кроется в "запоздалых" изменениях свойств, которые, почему-то, уже не отслеживаются CanExecute'ами команд. Это подтвердилось и в последнем экспериментальном проекте с async Task: если в ней у Task.Delay(300) задержку выставить 0, то все будет работать как надо. В других случаях, получается, что эту команду нужно каким-то образом "пнуть", чтобы она обновила у себя canexecute. Это и происходит при любой другой активности окна.

Странно еще то, что такая проблема ни где не освещена прежде, как-будто с ней никто не сталкивался. Хотя, вряд-ли ситуация с изменением свойств через некоторое время после первичной активности вызывающей событие команды, и/или из других потоков является каким-то неординарным явлением...

Поэтому, в настоящий момент, единственным работающим вариантом остается прямая привязка IsEnabled контрола к нужному свойству. Это работает безотказно при любых задержках и из любых потоков.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
09.05.2024, 15:56
Лучший ответ Сообщение было отмечено wizard41 как решение

Решение

Цитата Сообщение от wizard41 Посмотреть сообщение
пока ситуация остается прежней.
"Потыкайте" здесь: WpfApp_TestCommandIncp-EldHasp.7z

Основная часть устранения причины:
C#
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
        protected override void OnPropertyChanged(string propertyName, object oldValue, object newValue)
        {
            base.OnPropertyChanged(propertyName, oldValue, newValue);
 
            if(propertyName == nameof(Device1))
            {
                if (oldValue is Device old)
                {
                    old.PropertyChanged -= OnDevicePropertyChanged;
                }
                if (newValue is Device @new)
                {
                    @new.PropertyChanged += OnDevicePropertyChanged;
                }
            }
        }
 
        private void OnDevicePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(Device.Enabled))
            {
                ComASyncCommand.RaiseCanExecuteChanged();
                ComConnectCommand.RaiseCanExecuteChanged();
                ButtonCommand1.RaiseCanExecuteChanged();
            }
        }
1
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 16:18  [ТС]
Элд Хасп, ну да, ну да. Интуитивно предполагал, что нужно как-то RaiseCanExecuteChanged() использовать, но видно к чему это привело: создание еще одного кастомного INCP вместе RelayCommand )

Добавлено через 2 минуты
Полагаю, что создавать зависимости нужно только для таких "трудных" команд разнесенных по времени. Для обычных оконных - использовать простой подход, как и прежде.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
09.05.2024, 17:03
Цитата Сообщение от wizard41 Посмотреть сообщение
Полагаю, что создавать зависимости нужно только для таких "трудных" команд разнесенных по времени. Для обычных оконных - использовать простой подход, как и прежде.
Так как в VM не должно быть зависимости от View, то и "оконных команд" тоже не должно быть.

VM зависит от Модели.
В данном случае, ваша Модель - это Device Device1.
А события Модели НУЖНО прослушивать иначе не удастся реализовать актуальное её отражение в свойствах VM.

Добавлено через 4 минуты
Для UWP этого не нужно.
Там используется какой-то иной способ ревалидации команд. Возможно, там просто по какому-то таймеру проверяются все команды в GUI - точно не знаю.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 17:12  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Так как в VM не должно быть зависимости от View, то и "оконных команд" тоже не должно быть.
Я имел в виду команды, которые отправляются непосредственно из интерфейса приложения (кнопки), которые и отрабатывают тут же. Зачем для них создавать дополнительные зависимости, если они сами по себе извещают всех.
Проблема возникала с теми командами, canexecute которых зависел от "внешнего мира".

Добавлено через 3 минуты
Команда - это же View-компонент? Поэтому размещать их в VM самое место. Видел что некоторые пихают команды в Модели, что мне кажется вообще не верным. Т.к. модели могут использоваться не только в UI-приложениях.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,170
Записей в блоге: 2
09.05.2024, 17:16
Цитата Сообщение от wizard41 Посмотреть сообщение
Зачем для них создавать дополнительные зависимости, если они сами по себе извещают всех.
Если бы было так просто....
Команда "сама по себе" никого не извещает.
Этим занимается CommandManager. Но многие разработчики считают его использование отрицательным фактором. Поэтому есть пакеты в которых реализация команд не имеет автоматической подписки на CommandManager.RequerySuggested и в таких пакетах всегда явно надо подымать CanExecuteChanged.
Не помню точно, но в каком-то "большом" есть такая реализация. Может быть в ReactiveUI.

Добавлено через 1 минуту
Цитата Сообщение от wizard41 Посмотреть сообщение
Команда - это же View-компонент?
С какого перепуга?
ICommand находится в сборке System.ObjectModel.dll. Эта сборка общего применения, входит даже в Standard 2.0.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
09.05.2024, 17:16

Обновление состояний checkBox при изменении состояния соответствующего comboBox
Доброго времени суток, возник вопрос: Как при смене значения comboBox изменять состояния checkBox? Например, у меня есть 2 значения в...

Асинхронное выполнение команды
В чем преимущества и недостатки асинхронного выполнения команд? TExecuteOption = (eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlocking,...

Асинхронное обновление таблицы
Здравия желаю, сразу к делу: Есть таблица, хочу записать в нее десять тысяч строк (допустим через цикл), если делать это в лоб, страница...

Асинхронное обновление QListWidget
Имеется код для демонстрации проблемы: #!/usr/bin/env python3 import sys import time from PyQt5.QtCore import QTimer from...

Обновление свойств компонентов на обновление состояния родителя
Компонент Clock отрисовывается 500 раз. Внутри тикает таймер и когда компонент один - все ОК. Но когда их 500 (по всем временным...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru