탐색기 이벤트를 후킹해 우리가 만든 WPF로 대체하는 작업을 하던 중 다음과 같은 에러가 발생했습니다.
NotSupportedException
"이 형식의 CollectionView에서는 발송자 스레드와 다른 스레드에서의 해당 SourceCollection에 대한 변경 내용을 지원하지 않습니다."
웬만한 예외처리를 했음에도 불구하고 Exception의 발생으로 에러없이 종료되는 걸 보고 어떤 에러인지 확인했습니다.먼저 발생 상황은 다음과 같습니다.
1. 문서에 Close 이벤트 발생시에 해당 문서를 서버로 업로드
2. 업로드 하는 도중에 새로고침으로 서버에 있는 문서를 로컬로 로드
현재 관리하고 있는 문서에 또 다른 작업을 할 때 발생하는 에러였습니다.
MSDN에서 제공하는 WPF의 아키텍처를 참고하면 쓰레드와 관련된 설명이 다음과 같이 되어 있습니다.
"WPF의 대부분의 개체는 동시성과 스레딩을 처리하기위한 기본 구조를 제공하는 DispatcherObject 에서 파생됩니다 . WPF는 발송자가 구현 한 메시징 시스템을 기반으로합니다. 이것은 익숙한 Win32 메시지 펌프와 매우 유사하게 작동합니다. 실제로 WPF 디스패처는 크로스 스레드 호출을 수행하기 위해 User32 메시지를 사용합니다."
영어를 번역한 거라 다소 어색하고 어려운 문장이지만 대충 해석하면 WPF에서 사용하는 대부분의 개체는 스레드 관리를 Dispatcher라는 걸 이용한다는 것입니다. 만약에 UI 스레드에 의해 점유 중인 자원에 대해서 또 작업을 하려고 하면 막겠지요.. 그래서 점유 중인 자원에 접근하고 싶다면 Dispather에게 작업을 위임해야하는 것입니다.
Dispatcher는 큐에 요청된 작업을 넣고 우선순위를 지정한 뒤 순차적으로 작업을 진행시킵니다.따라서 제가 위에서 쓴 것처럼 1번을 하면서 2번을 하고 싶으면 Dispatcher에게 2번 작업을 위임해야하는 것입니다.Dispatcher를 어떻게 사용할까 고민 중 다음 블로그를 발견하였고, 여기서 제공하는 소스를 통해서 해결할 수 있었습니다.
public static class DispatcherService
{
public static void Invoke(Action action)
{
Dispatcher dispatchObject = Application.Current != null ? Application.Current.Dispatcher : null;
if (dispatchObject == null || dispatchObject.CheckAccess())
action();
else
dispatchObject.Invoke(action);
}
}
소스를 분석하면, 앱도메인을 조회해서 있을 경우 해당 앱도메인의 Dispatcher에 현재 작업을 Invoke시키고 아니면 일반적인 동작을 하라는 것입니다.
만약 1이 진행 중이 아니면 그냥 일반적인 작업(서버에서 문서 가져오기)을 하고, 1이 진행 중이라서 자원이 점유 중이면 해당 앱도메인의 Dispatcher에 위 작업을 Invoke하게 됩니다.
DispatcherService.Invoke((System.Action)(( ) =>
{
// your logic
}));
사용방법은 위와 같습니다.
'2020년기록' 카테고리의 다른 글
.NET 5.0 달라진 점 (0) | 2020.09.28 |
---|---|
digicert EV 인증서 서명방법 (1) | 2020.09.28 |