Рішення асинхронної повторної асинхронізації C # 5


16

Отже, щось переживає мене про нову підтримку async в C # 5:

Користувач натискає кнопку, яка запускає операцію асинхронізації. Виклик негайно повертається, і насос повідомлень знову починає працювати - ось у чому вся суть.

Тож користувач може знову натиснути кнопку - викликаючи повторне вступництво. Що робити, якщо це проблема?

У демонстраційних демонстраціях, які я бачив, вони вимикають кнопку перед awaitвикликом і знову включають її. Мені це здається дуже крихким рішенням у реальному додатку.

Чи повинні ми кодувати якусь машину стану, яка визначає, які елементи управління повинні бути відключені для заданого набору запущених операцій? Або є кращий спосіб?

Мені спокушається просто показати модальний діалог протягом тривалості операції, але це трохи схоже на використання кувалди.

У когось є якісь яскраві ідеї, будь ласка?


Редагувати:

Я думаю, що відключення елементів керування, які не слід використовувати під час виконання операції, є крихким, тому що я думаю, що це швидко стане складним, коли у вас буде вікно з багатьма елементами управління. Мені подобається робити прості речі, оскільки це зменшує ймовірність помилок, як під час первинного кодування, так і в подальшому технічному обслуговуванні.

Що робити, якщо існує колекція елементів керування, яку слід відключити для певної операції? А що робити, якщо кілька операцій виконуються одночасно?


Що в цьому крихке? Це дає користувачеві вказівку, що щось обробляється. Додайте деяку динамічну роботу індикації, яка обробляється, і це здається мені абсолютно гарним інтерфейсом користувача.
Стівен Євріс

PS: Чи називається C # 5 з .NET 4.5?
Стівен Євріс

1
Просто цікаво, чому це питання тут, а не ТАК? Це безумовно щодо коду, щоб він належав там, я думаю ...
С. Росс

@ C.Ross, Це більше питання дизайну / інтерфейсу користувача. Тут насправді немає технічного моменту, який потрібно пояснити.
Морган Херлокер

У нас є аналогічна проблема у формах HTML ajax, коли користувач натискає кнопку "Надіслати", надсилається запит ajax, і ми хочемо потім заблокувати користувач від повторного натискання надіслати, відключення кнопки - дуже поширене рішення в цій ситуації
Raynos

Відповіді:


14

Отже, щось запитує мене про нову підтримку асинхронізації в C # 5: Користувач натискає кнопку, яка запускає операцію асинхронізації. Виклик негайно повертається, і насос повідомлень знову починає працювати - ось у чому вся суть. Тож користувач може знову натиснути кнопку - викликаючи повторне вступництво. Що робити, якщо це проблема?

Для початку зауважимо, що це вже проблема, навіть без підтримки асинхронної мови. Багато речей може призвести до відмови повідомлень під час обробки події. Ви вже повинні кодувати захисно цю ситуацію; нова мовна функція просто робить це більш очевидним , а саме добро.

Найпоширенішим джерелом циклу повідомлень, що працює під час події, що викликає небажане повторне вступництво, є DoEvents. Хороша річ, на awaitвідміну від того DoEvents, що awaitробить більш імовірним, що нові завдання не збираються "голодувати" поточними завданнями. DoEventsперекачує цикл повідомлень, а потім синхронно викликає обробник події повторного вступу , тоді як awaitзазвичай виконує нове завдання, щоб воно запустилося в якийсь момент у майбутньому.

У демонстраційних демонстраціях, які я бачив, вони вимикають кнопку перед дзвінком, що очікує, і знову включають її. Я думаю, що відключення елементів керування, які не слід використовувати під час виконання операції, є крихким, тому що я думаю, що це швидко стане складним, коли у вас буде вікно з багатьма елементами управління. Що робити, якщо існує колекція елементів керування, яку слід відключити для певної операції? А що робити, якщо кілька операцій виконуються одночасно?

Ви можете керувати цією складністю так само, як ви керуєте будь-якою іншою складністю на мові ОО: ви абстрагуєте механізми від класу, а клас кладе відповідальність за правильну реалізацію політики . (Постарайтеся, щоб механізми логічно відрізнялися від політики; слід змінити політику, не переймаючись механізмами.)

Якщо у вас є форма з великою кількістю контролю, яка взаємодіє цікавими способами, ви живете в світі складності власного виготовлення . Ви повинні написати код для управління цією складністю; якщо вам це не подобається, тоді спростіть форму, щоб вона була не такою складною.

Мені спокушається просто показати модальний діалог протягом тривалості операції, але це трохи схоже на використання кувалди.

Користувачі ненавиджу це.


Дякую Еріку, я думаю, це остаточна відповідь - це залежить від розробника програми.
Ніколас Батлер

6

Чому ви вважаєте, що відключення кнопки перед, awaitа потім повторне ввімкнення її після завершення дзвінка неміцне? Це тому, що ви переживаєте, що кнопка ніколи не буде знову ввімкнена?

Що ж, якщо виклик не повертається, то ви не можете здійснити дзвінок знову, тому, схоже, саме така поведінка ви хочете. Це вказує на стан помилки, яке слід виправити. Якщо час виклику асинхронізовано, то це все ще може залишити вашу програму у невизначеному стані - знову ж таки такий, у якому включена кнопка може бути небезпечною.

Єдиний раз, коли це може заплутатися - це кілька операцій, які впливають на стан кнопки, але я думаю, що такі ситуації мають бути дуже рідкісними.


Звичайно, ви повинні впоратися з помилками - я оновив своє запитання
Ніколас Батлер

5

Я не впевнений, чи це стосується вас, оскільки я зазвичай використовую WPF, але я бачу, що ви посилаєтесь ViewModelтак, що це може бути.

Замість того, щоб вимкнути кнопку, встановіть IsLoadingпрапор true. Тоді будь-який елемент інтерфейсу, який ви хочете відключити, може бути прив’язаний до прапора. Кінцевим результатом є те, що завдання інтерфейсу стає вирішувати власне ввімкнений стан, а не бізнес-логіку.

На додаток до цього, більшість кнопок у WPF прив’язані до an ICommand, і я зазвичай встановлюю ICommand.CanExecuteрівний !IsLoading, тому він автоматично запобігає виконанню команди, коли IsLoading дорівнює true (також для мене вимикає кнопку)


3

У демонстраційних демонстраціях, які я бачив, вони вимикають кнопку перед дзвінком, що очікує, і вмикають її знову після цього. Мені це здається дуже крихким рішенням у реальному додатку.

У цьому немає нічого крихкого, і це те, що очікував би користувач. Якщо користувачеві потрібно зачекати, перш ніж натиснути кнопку, тоді змушуйте їх чекати.

Я бачу, як певні сценарії управління можуть зробити рішення, які елементи управління відключити / ввімкнути в будь-який час досить складними, але чи дивується це те, що управління складним інтерфейсом буде складним? Якщо у вас є занадто багато страшних побічних ефектів від конкретного контролю, ви завжди можете просто відключити всю форму і накинути «навантажувальний» вихровий концерт над усією справою. Якщо це стосується кожного контрольного елемента, то, напевно, ваш інтерфейс користувача, мабуть, не дуже добре розроблений (щільна з’єднаність, неправильне групування керування тощо).


Спасибі - але як керувати складністю?
Ніколас Батлер

Одним із варіантів було б помістити відповідні елементи управління в контейнер. Вимкнути / увімкнути керуючий контейнер, а не керування. тобто: EditorControls.Foreach (c => c.Enabled = false);
Морган Херлокер

2

Вимкнення віджета - найменш складний і схильний до помилок варіант. Ви вимикаєте його в оброблювачі перед запуском операції асинхронізації і повторно включаєте її в кінці операції. Тож відключення + включення для кожного елемента керування зберігається локально для обробки цього елемента управління.

Ви навіть можете створити обгортку, яка буде приймати делегата та керування (або більше їх), відключати елементи керування та асинхронно запускати щось, що зробить делегат і потім повторно включить елементи керування. Він повинен подбати про винятки (зробіть включення нарешті), тому він все ще надійно працює, якщо операція завершиться невдало. І ви можете комбінувати його з додаванням повідомлення в рядок стану, щоб користувач знав, що його чекає.

Ви можете додати деяку логіку для підрахунку відключень, тому система продовжує працювати, якщо у вас є дві операції, які мають відключити і третю, але інакше не є взаємовиключними. Ви вимикаєте елемент керування двічі, тож він знову стане увімкнутим, лише якщо ви знову ввімкнете його двічі. Це повинно охоплювати більшість випадків, зберігаючи справи окремо стільки, скільки ви можете отримати.

З іншого боку, все, як державна машина, стане складним. З мого досвіду, всі державні машини, які я коли-небудь бачив, важко було підтримувати, і ваша державна машина повинна була б охопити весь діалог, прив’язуючи все до всього.


Спасибі - мені подобається ця ідея. Отже, чи буде у вас вікно менеджера для вашого вікна, яке підраховує кількість запитів на відключення та включення для кожного елемента управління?
Ніколас Батлер

@ NickButler: Ну, у вас уже є об’єкт менеджера для кожного вікна - форма. Тож у мене був би клас, що реалізує запити та підрахунок і просто додавати екземпляри до відповідних форм.
Ян Худек

1

Хоча Ян Худек і Рейчел висловили споріднені ідеї, я б запропонував використовувати щось на зразок архітектури Model-View - виразити стан форми в об’єкті і прив’язати елементи форми до цього стану. Це призведе до відключення кнопки таким чином, що може масштабувати складніші сценарії.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.