3

어제부터 다음번에 새로운 복잡성 계층을 추가했습니다. 이론적 인 Model 클래스 인 ViewModel과 View가 있습니다. 내 모델이 threading.Timer의를 가지고 이번에는 (이하 "잘못된"스레드에서 타이머 콜백을 얻기 위해 특별히 선정.INotifyPropertyChanged, ObservableCollection, Threads 및 MVVM

모델은 ObservableCollection에 있습니다. 타이머 콜백 컬렉션에 항목을 추가합니다.

뷰 모델은 단순히 통과 컬렉션에 바인딩 된 목록 상자가 들어있는보기에 컬렉션.

이 작동하지 않습니다.

이 모델은 같은 타이머 콜백에 업데이트되는 문자열을 제공합니다.

이것 역시 뷰 모델을 통해 노출되고 TextBox에 바인딩됩니다.

이것은 작동합니다.

Google 검색에서 힌트를 보았을 때 컬렉션을 업데이트해도 INotifyCollectionChanged가 예상대로 작동하지 않는다는 것을 알았습니다. 나는 총 내파를 얻었는데, 심지어 예외도 아니고, 응용 프로그램을 즉각적으로 종료합니다.

하나는 어제 우리의 토론에 관한 것이다

그래서 두 가지 질문이 있습니다. 내가보기에 일을하기 때문에 나는 내 모델에서 INotifyPropertyChanged와 ObservableCollections를 사용하고있다. 이러한 메커니즘을 사용하여 내 뷰 모델 또는 기본 모델이 변경된 사항을 알리는 것은 여전히 ​​의미가 있습니다. 그렇다면 다른 스레드에서 발생하는 업데이트를 어떻게 처리합니까?

둘째, INotifyPropertyChanged가 바인딩과 함께 작동하게되는 이유는 무엇입니까? Text라는 DependencyProperty에 문자열 속성을 바인딩하고 있으므로 DependencyProperty 시스템에서 UI 스레드에 대한 내 변경 사항을 마샬링합니다. 편집 : 그리고 나는 그것을 의지 할 수 있습니까? 예를 들어, 제가 크로스 스레드에 대해 이야기 할 것을 기대하기 때문입니까, 아니면 내가 의지해서는 안되는 것을 잡을 수 있습니까?

ListBox는 ItemsSource = "{Binding ObsCollection}"을 통해 바인딩됩니다. 이 때 응용 프로그램이 충돌합니다. 사실, 처음에는 윈도우의 DataContext를 설정되었을 때 무슨 일이 있었 모델이 생성 된 타이머를 시작, 그래서 사실은 ... 비주얼 스튜디오 폭탄

감사

답변

1

WPF 컨트롤이 스레드 친화력, 무엇이 것 UI 스레드에서만 해당 속성을 수정할 수 있다는 것을 의미합니다. 따라서 Timer (DispatcherTimer 이외의)에서 속성 값을 업데이트하는 경우이 업데이트를 UI 스레드에 마샬링해야합니다. 이 작업은 디스패처를 통해 perfomed됩니다 : 당신은이 문제의 원인이됩니다 다른 스레드에서 모델을 업데이트 할 경우

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Normal, 
    new Action(() => // update your control here)); 

데이터 바인딩 프레임 워크는 따라서 업데이트가 UI 스레드에 정렬 화되는 것을 보장하지 않습니다. 따라서 위와 동일한 패턴을 사용해야합니다. 즉, 관찰 가능한 콜렉션에 이의를 추가하는 경우이 추가는 Dispatcher를 통해 수행해야합니다.

+1

멋지다.하지만 MVVM 관점에서이를 처리하는 "올바른"프로세스는 무엇입니까? 따라서 내 모델의 스레드가 컬렉션을 업데이트하고 있습니다. 내 모델은 이제 Dispatcher에 대해 알고 있어야합니까? 그것은 틀린 것처럼 보인다. 이는 ViewModel을 모델과 뷰 사이의 정확한 분리에 대처할 수 있도록 무겁게 만들 것을 제안합니다. 말이 돼? – Ian

+1

'올바른'접근법이 없습니다. 그러나, 내 개인적인 취향은 ViewModel이 의존하는 간단한 인터페이스 인 IMarshalledInvoker를 만드는 것입니다. IMarshalledInvoker는 다른 스레드에서 일부 동작을 호출하는 단일 메서드를 가지고 있습니다. ViewModel을 뷰와 결합하면 Dispatcher를 커버 아래에 사용하는 IMarshalledInvoker를 생성합니다. 이 패턴을 사용하면 여전히 단위 테스트를 할 수 있으며 여전히 디자이너 지원을 할 수 있습니다. 즉, MVVM입니다 .-) – ColinE

+0

아, 이제 상황이 함께합니다. 교묘하게도 내가 고려하지 않은 방식으로 서로 관련이있는 서로 다른 지식의 비트가 있습니다. 우선 스레드 안전 컬렉션을 만드는 것이 까다로운 일임을 알고 있습니다. 나는 그것을 잊어 버렸고 내 머리 속에서 협회를 만들지 않았다 ... 본질적으로 나는 오직 하나의 실에만 추가하고있다. 재밌는 당신이 왜 당신이 일을하는지 잊어 버렸습니다. 그래서 대답의 핵심은 여러 스레드의 변경 사항을 단일 스레드로 퍼팅하는 것이라고 생각합니다. 뷰와 뷰 모델 사이에 단일 채널이 있습니까? – Ian

2

이 문제는 WPF에서 널리 발생합니다. 가장 좋은 방법은 자신의 ObservableCollection<> 하위 클래스가 UI 스레드에 이벤트 알림을 자동으로 전달하는 것입니다.

휠이 이미 발명되었으므로이 질문에 대한 대답으로 간단히 안내 할 것입니다 : ObservableCollection and threading.

관련 문제