C # 5 비동기 재진입 솔루션


16

그래서 C # 5의 새로운 비동기 지원에 대해 뭔가를 괴롭 혔습니다.

사용자는 비동기 작업을 시작하는 버튼을 누릅니다. 호출이 즉시 리턴되고 메시지 펌프가 다시 실행되기 시작합니다. 그게 요점입니다.

따라서 사용자가 버튼을 다시 누르면 재진입이 가능합니다. 이것이 문제라면?

내가 본 데모에서는 await통화 전에 버튼을 비활성화하고 나중에 다시 활성화합니다. 이것은 실제 응용 프로그램에서 매우 깨지기 쉬운 솔루션 인 것 같습니다.

주어진 실행중인 작업 집합에 대해 어떤 컨트롤을 비활성화해야하는지 지정하는 일종의 상태 시스템을 코딩해야합니까? 아니면 더 좋은 방법이 있습니까?

작업 기간 동안 모달 대화 상자를 표시하고 싶었지만 슬레지 해머를 사용하는 것과 약간 같습니다.

누구든지 밝은 아이디어가 있습니까?


편집하다:

작업이 실행되는 동안 사용해서는 안되는 컨트롤을 비활성화하는 것은 깨지기 쉽다고 생각합니다. 나는 초기 코딩 및 후속 유지 보수 중 버그 가능성을 줄이기 때문에 일을 단순하게 유지하고 싶습니다.

특정 작업에 대해 비활성화해야하는 컨트롤 모음이 있으면 어떻게됩니까? 여러 작업이 동시에 실행 중이면 어떻게해야합니까?


그것에 대해 연약한 것은 무엇입니까? 사용자에게 무언가가 처리되고 있음을 나타냅니다. 동적 표시 작업이 처리되고 있으며 완전히 UI처럼 보입니다.
Steven Jeuris

추신 : .NET 4.5의 C #은 C # 5입니까?
Steven Jeuris

1
왜이 질문이 여기에 있고 왜 그렇지 않은지 궁금하십니까? 이것은 분명히 코드에 관한 것이므로 내가 생각하기에 ...
C. Ross

@ C.Ross, 이것은 더 많은 디자인 / UI 질문입니다. 여기에 설명해야 할 기술적 요점이 없습니다.
Morgan Herlocker

사용자가 버튼을 제출 닿을 우리는 아약스 HTML 형태의 유사한 문제가, 아약스 요청을 전송하고 우리는 다음 버튼이 그 상황에서 매우 일반적인 솔루션입니다 해제, 다시 제출 타격에서 사용자를 차단하려는
Raynos

답변:


14

따라서 C # 5의 새로운 비동기 지원에 대해 무언가를 괴롭 히고 있습니다. 사용자가 비동기 작업을 시작하는 버튼을 누릅니다. 호출이 즉시 리턴되고 메시지 펌프가 다시 실행되기 시작합니다. 그게 요점입니다. 따라서 사용자가 버튼을 다시 누르면 재진입이 가능합니다. 이것이 문제라면?

언어에서 비동기 지원을하지 않더라도 이미 문제 가 있음을 지적하면서 시작하겠습니다 . 이벤트를 처리하는 동안 많은 것들로 인해 메시지가 대기열에서 제외 될 수 있습니다. 당신은 이미 수비에이 상황에 대한 코드에있다; 새로운 언어 기능은 그 점을 더욱 분명 하게 만듭니다 .

원하지 않는 재진입을 유발하는 이벤트 중에 실행되는 메시지 루프의 가장 일반적인 소스는 DoEvents입니다. 의 좋은 일 await에 반대는 DoEventsawait새 작업이 현재 실행중인 작업 "굶주 리기"를하지 않을 것으로 그 가능성이 있습니다. DoEvents메시지 루프를 펌핑 한 다음 재진입 이벤트 핸들러를 동기식으로 호출하는 반면, await일반적으로 새 작업을 대기열 에 추가하여 나중에 특정 시점에 실행되도록합니다.

내가 본 데모에서는 통화 대기 전에 버튼을 비활성화하고 나중에 다시 활성화합니다. 작업이 실행되는 동안 사용해서는 안되는 컨트롤을 비활성화하는 것은 깨지기 쉽다고 생각합니다. 특정 작업에 대해 비활성화해야하는 컨트롤 모음이 있으면 어떻게됩니까? 여러 작업이 동시에 실행 중이면 어떻게해야합니까?

OO 언어로 다른 복잡성을 관리하는 것과 같은 방식으로 복잡성을 관리 할 수 ​​있습니다. 메커니즘을 클래스로 추상화 하고 클래스가 정책 을 올바르게 구현하도록 합니다. (매커니즘을 정책과 논리적으로 구별되도록 노력하십시오. 매커니즘에 너무 많은 영향을주지 않고 정책을 변경할 수 있어야합니다.)

흥미로운 방식으로 상호 작용할 수있는 많은 제어 기능이있는 양식이 있다면 자신 만의 복잡한 세상에 살고 있습니다. 복잡성을 관리하기위한 코드를 작성해야합니다. 마음에 들지 않으면 복잡하지 않도록 양식단순화하십시오.

작업 기간 동안 모달 대화 상자를 표시하고 싶었지만 슬레지 해머를 사용하는 것과 약간 같습니다.

사용자는 그것을 싫어할 것입니다.


고마워 Eric, 나는 이것이 정답이라고 생각한다-그것은 응용 개발자에게 달려있다.
니콜라스 버틀러

6

await통화가 끝나기 전에 버튼을 비활성화했다가 다시 활성화하는 것이 왜 취약 하다고 생각 하십니까? 버튼이 다시 활성화되지 않을까 걱정되기 때문입니까?

전화가 안 오면 다시 전화를 걸 수 없으므로 이것이 원하는 동작 인 것 같습니다. 이것은 수정해야하는 오류 상태를 나타냅니다. 비동기 호출 시간이 초과되면 여전히 응용 프로그램이 불확실한 상태로 남아있을 수 있습니다. 버튼을 활성화하면 위험 할 수 있습니다.

버튼이 상태에 영향을 미치는 여러 작업이있는 경우에만 문제가 발생할 수 있지만 이러한 상황은 매우 드 물어야한다고 생각합니다.


물론 당신은 오류를 처리해야합니다-내 질문을 업데이트했습니다
Nicholas Butler

5

나는 보통 WPF를 사용하기 때문에 이것이 당신에게 적용되는지 확실하지 않지만, 당신이 ViewModel그렇게 참조 할 것입니다.

버튼을 비활성화하는 대신 IsLoading플래그를로 설정하십시오 true. 그런 다음 비활성화하려는 UI 요소를 플래그에 바인딩 할 수 있습니다. 최종 결과는 Business Logic이 아닌 자체 사용 가능 상태를 정렬하는 것이 UI의 작업이된다는 것입니다.

그 외에도, WPF에서 대부분의 버튼은 결합되어 ICommand, 일반적으로 내가 설정 ICommand.CanExecute동일한을 !IsLoading자동 IsLoading true로 동일 할 때 실행에서 명령을 방지 할 수 있도록 (또한 나를 위해 버튼을 비활성화)


3

내가 본 데모에서는 통화 대기 전에 버튼을 비활성화하고 나중에 다시 활성화합니다. 이것은 실제 응용 프로그램에서 매우 깨지기 쉬운 솔루션 인 것 같습니다.

이것에 대해 깨지기 쉬운 것은 없으며 사용자가 기대하는 것입니다. 사용자가 버튼을 다시 누르기 전에 기다려야 할 경우에는 기다리십시오.

특정 제어 시나리오로 인해 한 번에 비활성화 / 활성화 할 제어를 결정하는 방법을 알 수 있지만 복잡한 UI 관리가 복잡하다는 것은 놀라운 일입니까? 특정 컨트롤에서 무서운 부작용이 너무 많으면 항상 전체 양식을 비활성화하고 전체에 "로드"를 던질 수 있습니다. 이것이 모든 단일 컨트롤에 해당되는 경우 UI가 처음에는 제대로 설계되지 않았을 수 있습니다 (긴밀한 커플 링, 잘못된 컨트롤 그룹화 등).


고마워-그러나 복잡성을 관리하는 방법?
Nicholas Butler

한 가지 옵션은 관련 컨트롤을 컨테이너에 넣는 것입니다. 제어 컨테이너가 아닌 제어 컨테이너로 비활성화 / 활성화합니다. 즉 : EditorControls.Foreach (c => c.Enabled = false);
Morgan Herlocker

2

위젯을 비활성화하는 것은 가장 복잡하고 오류가 발생하기 쉬운 옵션입니다. 비동기 작업을 시작하기 전에 처리기에서이를 비활성화하고 작업이 끝날 때 다시 활성화하십시오. 따라서 각 컨트롤에 대해 disable + enable은 해당 컨트롤을 처리하는 데 로컬로 유지됩니다.

래퍼를 생성하여 델리게이트 및 컨트롤 (또는 그 이상)을 가져 와서 컨트롤을 비활성화하고 무언가를 비동기 적으로 실행하여 델리게이트를 수행하고 컨트롤을 다시 활성화 할 수 있습니다. 예외를 처리해야합니다 (마지막으로 활성화하십시오). 작업이 실패하더라도 여전히 안정적으로 작동합니다. 그리고 상태 표시 줄에 메시지를 추가하는 것과 결합하여 사용자가 기다리는 것을 알 수 있습니다.

비활성화를 계산하는 논리를 추가 할 수 있으므로 두 개의 작업이있는 경우 시스템이 계속 작동합니다. 두 번째 작업은 세 번째 작업을 비활성화하지만 상호 배타적이지는 않습니다. 컨트롤을 두 번 비활성화하면 다시 두 번 활성화 한 경우에만 다시 활성화됩니다. 최대한 많은 경우를 다루면서 가능한 한 많이 사례를 분리해야합니다.

반면에 상태 머신과 같은 것은 복잡해질 것입니다. 내 경험상 내가 본 모든 상태 머신은 유지 관리가 어려웠으며 상태 머신은 모든 것을 모든 것에 묶어 전체 대화 상자를 포함해야합니다.


고마워-나는이 아이디어를 좋아한다. 따라서 각 컨트롤에 대한 비활성화 및 활성화 요청 수를 계산하는 창에 대한 관리자 개체가 있습니까?
Nicholas Butler

@NickButler : 글쎄, 당신은 이미 각 창에 대한 관리자 객체를 가지고 있습니다. 그래서 요청과 계산을 구현하고 관련 양식에 인스턴스를 추가하는 클래스가 있습니다.
Jan Hudec

1

Jan Hudec과 Rachel은 관련 아이디어를 표현했지만 Model-View 아키텍처 와 같은 것을 사용하는 것이 좋습니다 . 객체에서 양식의 상태를 표현하고 양식 요소를 해당 상태에 연결합니다. 이렇게하면 더 복잡한 시나리오에 맞게 확장 할 수있는 방식으로 버튼이 비활성화됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.