Форум программистов, компьютерный форум, киберфорум
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. Показов 3890. Ответов 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
1596 / 601 / 185
Регистрация: 05.12.2015
Сообщений: 970
09.05.2024, 17:18
Студворк — интернет-сервис помощи студентам
wizard41,
А использовать для решения проблемы SynchronizationContext и CommandManager в вашем случае это криминально?
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 17:22  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
С какого перепуга?
Много раз встречалось это утверждение, в том числе у "маститых" пользователей WPF. Команды же, по большей части (а я других частей пока не встречал) используются для взаимодействия с логикой посредством UI.... Если именно про WPF говорить. Я знаю что они существуют и для всего прочего.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 17:23
Цитата Сообщение от wizard41 Посмотреть сообщение
Видел что некоторые пихают команды в Модели, что мне кажется вообще не верным.
Не скажу, что часто, но в модели они вполне могут быть использованны и используются.

Команда - это абстракции метода который не всегда можно вызывать.

Например, у вас COM порт и есть метод передачи в него серии байт void Send(byte[]). Но пока передача массива байт не завершилась, передавать следующий массив нельзя. Поэтому надо проверить перед вызовом метода, разрешена ли сейчас передача. Для этого создаётся метод bool CanSend(byte[]). Но не будеши же в вечном цикле вызывать этот метод и ждать когда он разрешить передачу. Поэтому добавляется событие EvenHandler CanSendChanged.
Так как такая связка из трёх членов может понадобиться где угодна и часто, то и добавили абстракцию ICommand в ОСНОВНЫЕ типа .Net.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 17:26  [ТС]
proa33, про SynchronizationContext подумывал еще неделю назад. Но, к сожалению, времени на эксперименты особо уже не было, поэтому решил проблему "в обход", а само решение оставил на потом. И то, случайно попался похожий вопрос на форуме и в порядке обсуждения его поделился своим случаем.
Заказчик уже хочет бету, а у меня ни одного теста не написано еще... Ну и там уже пора переходить к другой фазе..
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 17:28
Цитата Сообщение от wizard41 Посмотреть сообщение
а я других частей пока не встречал
В настоящее время из-за очень сильного повышение возможностей компов, действительно использование команд на низких уровнях значительно уменьшилось.
Вместо них используются различные блокировки, очереди, буферы, асинхронные методы и т.д. Например, для COM порта метод просто примет следующий массив байт, будет держать его в буфере, и потом автоматически передаст как порт освободится. Но "в глубине" всего этого по прежнему будут все те же три члена, но возможно, уже по отдельности, а не объединённые в команду.
0
1596 / 601 / 185
Регистрация: 05.12.2015
Сообщений: 970
09.05.2024, 17:31
Цитата Сообщение от wizard41 Посмотреть сообщение
времени на эксперименты особо уже не было,
написать всего 2 строчки кода проблема?
C#
1
2
3
4
5
   SynchronizationContext context;
   public MainVM()
   {
       context = SynchronizationContext.Current;
      ........................................................
C#
1
2
3
4
5
       context.Send( delegate 
       {
           Device1.Enabled = !Device1.Enabled;
           CommandManager.InvalidateRequerySuggested();
       }, null );
1
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 17:46  [ТС]
Элд Хасп, хорошо. Тогда как бы вы советовали использовать ваш последний вариант RC - вместе или вместо того, что использовалось ранее?
Про COM-порт - в тестовом проекте лишь небольшая "выжимка" из настоящего для быстрой демонстрации. На самом деле CanSend(byte[]) не нужен, т.к. в ядре уже сделана проверка на "занятость" и целый буфер для такого случая. Хотя такой случай в нормальных условиях возникнуть не должен, ну разве что какой-то сумасшедший будет давить на кнопки с частотой 50Гц ).

Добавлено через 5 минут
Цитата Сообщение от proa33 Посмотреть сообщение
написать всего 2 строчки кода проблема?
Проблема да. Я, так сказать, заложник хорошо известного "старого", чем пробования чего-то "неизвестного". Ну и "оттачивание" кода до блеска не всегда бывает оправдано. Если бы это было глобальной не разрешимой проблемой или не укладывалось в рамки требований - я бы более скрупулезно копал в этом направлении.

Добавлено через 3 минуты
Цитата Сообщение от proa33 Посмотреть сообщение
context.Send( delegate
думаю, в моем случае будет немного не так. В первом приближении, я не смог малой кровью его "прикрутить", поэтому даже не стал пробовать. Но, все возможно...
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 18:00
Цитата Сообщение от wizard41 Посмотреть сообщение
Тогда как бы вы советовали использовать ваш последний вариант RC - вместе или вместо того, что использовалось ранее?
Вариант который в моём архиве, конечно, простой, но он полностью заменяет по функционалу ваши предыдущие варианты. Поэтому использовать их нет смысла.
Что касается реальной реализации, то если в Модели нет нужного события от которого можно дёргать RaiseCanExecuteChanged, то можно добавить таймер, который будет его вызывать 2-5 раз в секунду. Какой-то большой нагрузки это не создаст.
1
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 18:13  [ТС]
Элд Хасп, касательно CanSend, наверное, надо учитывать еще то, что он повлечет за собой реализацию дополнительной логики для выполнения действия, если это действие было отменено из-за чего-то (занятости).
С другой стороны, ничто не мешает ставить команды в очередь, которые все же отправятся куда надо, когда буфер освободится. Это дешевле, с точки зрения реализации. Мне кажется.
Примерно так это сделано у меня: отдельный поток постоянно занимается опросом основных параметров, т.е. отправляет одну и ту же команду. Но иногда возникает необходимость отправить что-то другое. Как "вклинится" в этот поток? Правильно - сделать некий список команд, и если он пуст, то выполняется основная работа. Если же что-то в нем есть - выполняем от туда с последующим удалением. Так мне показалось проще, чем с предварительной проверкой.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 18:38
wizard41, но вы сами говорите, что у вас есть некий сигнал из устройства, по которому надо изменять состояние команды.
Зачем?
Наверное, для того что по этому сигналу меняется состояние модели, и какие-то её методы становится нельзя вызывать?
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 18:45  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Зачем?
Чтобы гарантировать обмен только с "правильным" устройством. Какой смысл отправлять команды в никуда или тому, кто их не поймет?
И пока не произойдет получения верного ответа на "дружеский" запрос - нет надобности в кнопках.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 19:00
Цитата Сообщение от wizard41 Посмотреть сообщение
Чтобы гарантировать обмен только с "правильным" устройством.
То есть всё таки есть метод, который нужно не всегда вызывать?

Добавлено через 43 секунды
Вы тем самым реализуете по сути туже команду, но своим уникальным, а не общепринятым способом.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
09.05.2024, 19:11  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вы тем самым реализуете по сути туже команду, но своим уникальным, а не общепринятым способом.
Нет, Элд Хасп, наверное вы запутались)
Слово "команда" в последних двух постах означала последовательность символов, отправляемая по каналу связи. Это не связано с решаемой задачей о команде ICommand в теле приложения, которая не обновляла UI-элемент.

Добавлено через 1 минуту
На текущий момент проблема вами решена. Придется встраивать это все, но уже в продакшен, на скорую руку...
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
09.05.2024, 22:29
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Смысл этой реализации, вообще, ускользает от меня.
"А чтобы было!" - наверное?
Вы правы, смысл лишнего кода чтобы был Из за не возможности получить ошибку, я оставил как есть всё.
wizard41,
Дописал класс AsyncRelayCommand. Теперь Enable меняется как нужно.
Использование
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
        private AsyncRelayCommand comAsyncCommand;
        public AsyncRelayCommand ComASyncCommand =>
            comAsyncCommand ?? (comAsyncCommand = new AsyncRelayCommand(EnabledCommandAsync));
 
 
        private async Task EnabledCommandAsync()
        {
            await Task.Run(async () =>
            {
                await Task.Delay(500);
                Device1.Enabled = !Device1.Enabled;
            });
        }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 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) => _canExecute == null || _canExecute();
 
     public async void Execute(object parameter)
     {
         await _execute();
         CommandManager.InvalidateRequerySuggested(); // Добавляем вызов InvalidateRequerySuggested
     }
     private void _CanExecuteChanged()  => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
 }
WpfApp_TestCommandIncp.rar
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
09.05.2024, 23:02
Цитата Сообщение от xellan24rus Посмотреть сообщение
Дописал класс AsyncRelayCommand. Теперь Enable меняется как нужно.
Что это реализация упрощает в применении?
C#
1
2
3
4
5
6
7
8
9
10
11
12
        public RelayCommand ComASyncCommand =>
            comAsyncCommand ?? (comAsyncCommand = new RelayCommand(EnabledCommandAsync));
 
 
        private async void EnabledCommandAsync()
        {
            await Task.Run(async () =>
            {
                await Task.Delay(500);
                Device1.Enabled = !Device1.Enabled;
            });
        }
Добавлено через 5 минут
Смысл асинхронной команды в том, что у неё есть какие-то дополнительные вспомогательные и нужные челны.
Например, состояние занятости пока выполняется команда.

Добавлено через 1 минуту
Цитата Сообщение от xellan24rus Посмотреть сообщение
CommandManager.InvalidateRequerySuggeste d(); // Добавляем вызов InvalidateRequerySuggested
Вместо проверки ОДНОЙ команды, вызываете проверку ВСЕХ команд.
Зачем?

Добавлено через 1 минуту
А если во время await _execute(); состояние команды несколько раз меняется?
0
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
09.05.2024, 23:10
Элд Хасп, вызывает CommandManager.InvalidateRequery после выполнения команды.
Далее копипаст текста.
CommandManager.InvalidateRequerySuggeste d() является статическим методом в классе CommandManager в пространстве имен System.Windows.Input. Этот метод используется в приложениях WPF (Windows Presentation Foundation) для уведомления системы о том, что нужно повторно проверить все команды, реализованные с помощью интерфейса ICommand, чтобы обновить их состояние.

В WPF команды обычно используются для связывания действий пользователя с логикой в приложении. Когда что-то изменяется в окружении приложения (например, свойства, влияющие на возможность выполнения команды), вызов CommandManager.InvalidateRequerySuggeste d() уведомляет систему о необходимости повторной проверки всех команд на возможность выполнения.
Как я понял этот вызов обновляет состояние команд на возможность их выполнения. И подходит для задачи когда canExcute зависит от свойства.

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вместо проверки ОДНОЙ команды, вызываете проверку ВСЕХ команд.
Зачем?
В примере все команды зависят от свойства.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
А если во время await _execute(); состояние команды несколько раз меняется?
Как я понимаю есть ExeCute и CanExeCute. Только два состояние для команды.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
10.05.2024, 00:01
А если во время await _execute(); состояние команды несколько раз меняется?
Цитата Сообщение от xellan24rus Посмотреть сообщение
Как я понял этот вызов обновляет состояние команд на возможность их выполнения.
ВСЕХ команд, во всех окнах одновременно.
Что, мягко говоря, не оптимально.

Цитата Сообщение от xellan24rus Посмотреть сообщение
Как я понимаю есть ExeCute и CanExeCute. Только два состояние для команды.
Да.
Но при длительном исполнении ExeCute состояние CanExeCute может меняться многократно, а может и ни разу.
В вашей же логике предусматривается только однократное изменение после завершения ExeCute. Что, скажем так, несколько ограничено. Единственный вариант из множества возможных.

Добавлено через 3 минуты
В общем случае, команда может зависеть от множества факторов и нужно прописывать зависимость от них при создании её экземпляра, а не в классе где единый код для всех экземпляров.

Добавлено через 6 минут
xellan24rus, просто поверьте на слово, такая реализация асинхронной команды абсолютно бесполезна. Просто выкиньте её.
1
 Аватар для xellan24rus
364 / 296 / 55
Регистрация: 08.04.2020
Сообщений: 1,175
10.05.2024, 01:03
Элд Хасп, вы правы. Это не оптимальное решение. И использовать нет смысла.
0
Эксперт JavaЭксперт по электроникеЭксперт .NET
 Аватар для wizard41
3460 / 2781 / 575
Регистрация: 04.09.2018
Сообщений: 8,743
Записей в блоге: 3
10.05.2024, 18:56  [ТС]
Элд Хасп, отчет рефакторинга:
поменял RC и INPC на ваши во всех проектах.
Все собственные команды окна (приложения) работают как и прежде, т.е. им не нужен RaiseCanExecuteChanged().
Зависимость создана только для команды, в которой CanExecuted устанавливается позднее, из потока. Все обновляется как положено.
Единственно что, поправил метод inpcbase Set<T> с void на bool, т.к. иногда удобно делать что-то еще, если данное свойство поменялось.
Благодарю за содействие!
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16164 / 11284 / 2891
Регистрация: 21.04.2018
Сообщений: 33,169
Записей в блоге: 2
10.05.2024, 20:13
Цитата Сообщение от wizard41 Посмотреть сообщение
поправил метод inpcbase Set<T> с void на bool,
У меня было так раньше, но убрал.
Объясню причины.
Зависимости можно реализовывать:
1) "От источника" - это когда источник зависимости "знает" всех кто от него зависим и при изменении влияет на каждого зависимого;
2) "В зависимости" - это когда зависимость сама следит за своими источниками.

Когда зависимости реализуются "1 к 1", то разница между этими двумя способами неочевидно. Но если вы чуток имеете знания по типичной для .Net архитектуре зависимостей, то сразу обратите внимание, что первый способ практические никогда не используется. Второй же очень распространён. Самый типичный пример - это события, через который зависимости следят за источниками.

Вот именно для того чтобы не было соблазна использовать первый способ, который кажется иногда проще, но в действительности ломает архитектуру зависимостей, я и убрал возврат bool в методе. И теперь реализацию зависимостей нужно делать только в методе OnPropertyChanged (или в прослушке события), как оно и принято в .Net.

Цитата Сообщение от wizard41 Посмотреть сообщение
Все собственные команды окна (приложения) работают как и прежде, т.е. им не нужен RaiseCanExecuteChanged().
Зависимость создана только для команды, в которой CanExecuted устанавливается позднее, из потока.
Команды чьи источники обновляются синхронно с действиями пользователя в GUI обновляет CommandManager.RequerySuggested. Для WPF этого достаточно. Но если будете делать мультиплатформенное приложение, то советую явно реализовать все зависимости - "Лучше перебдеть, чем недобдеть"
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
10.05.2024, 20:13

Обновление состояний 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 (по всем временным...


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Кредитный калькулятор
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