2016-12-29 1 views
1

내 뷰에 바인딩 된 속성이있는 클래스가 있습니다. 내보기를 최신 상태로 유지하기 위해 INotifyPropertyChanged를 구현하고 속성 변경 시마다 이벤트를 발생시킵니다.비동기 구현 방법 INotifyPropertyChanged

이제 응용 프로그램이 정지되는 무거운 기능이 생겼습니다. 나는 그들을 배경 작업에 넣고 싶다.

첫째, 여기 내 현재의 접근 방식

은 위의 코드는 예외를 제공

public async Task<int> Fetch() 
{ 
    //network stuff 

    RaisePropertyChanged("MyProperty"); 
} 

public async void RaisePropertyChanged(string pChangedProperty) 
{ 
    await Application.Current.Dispatcher.BeginInvoke(
     System.Windows.Threading.DispatcherPriority.Normal, 
     new ThreadStart(() => 
     { 
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty); 
     } 
    ); 
} 

private async void HeavyFunc() 
{ 
    foreach (var stuff) 
    { 
     count += await Task.Run(() => stuff.Fetch()); 
    } 

    if (count == 0) 
     //... 
} 

물건 클래스 (버튼 클릭에 예) ("DependencySource"를 만들어야합니다

"DependencyObject"와 같은 스레드).

AFAIK, 일반적으로 새 스레드를 만들고 실행해야합니다 (기다리는 동안). 'await Task.Run (...); '이 작업을 수행해야합니다.

PropertyChanged 이벤트가 UI에 직접적인 영향을주기 때문에 UI 스레드에서 호출하는 것이 좋은 결정 인 것 같습니다. 이것이 Dispatcher.BeginInvoke를 호출하는 이유입니다.

이해가 안되는 점 : 위의 예외는 다른 스레드가 데이터를 담당 할 때 발생합니다. 하지만 분명히 내 UI 스레드 및 개체에 이벤트를 호출 할 UI 스레드에 의해 만들어야합니다. 그렇다면 예외가 발생하는 이유는 무엇입니까?

내 질문은 : InotifyPropertyChanged 인터페이스의 이벤트를 구현하여 일반적으로 위와 같은 대부분의 비동기 프로그래밍 문제를 피하거나 처리하는 방법은 무엇입니까? 기능을 구성하는 동안 고려해야 할 사항은 무엇입니까?

+0

스레드에서 propertychanged 이벤트를 발생 시키므로 UI ​​요소를 생성하지 않은 경우 UI 요소에 액세스 할 수 없습니다. – CodingYoshi

+0

ui 스레드와 다른 스레드가 어떤 코드를 실행하는지 실제로 이해하려면 [this] (http://stackoverflow.com/questions/41271185/interface-freeze-when-trying-to-update-datagridview/41272238#41272238)를 읽으십시오. – CodingYoshi

+0

속성 자체가 비트 맵과 같은 DepedencyObject입니까? –

답변

4

이제 응용 프로그램을 정지시키는 무거운 기능이 생겼습니다.

비동기식 "네트워크 항목"을 실제로 수행하는 경우 앱을 고정해서는 안됩니다.

내 주요 질문은 : 어떻게하면 일반적으로 위의 비동기 프로그래밍 문제를 피하거나 처리하기 위해 INotifyPropertyChanged 인터페이스의 이벤트를 구현합니까?

내가 선호하는 접근 방식은 이 아니고이 코드를 발생시키는 이벤트에서 처리합니다. 대신 코드의 나머지을 구성하여 UI 레이어를 준수하도록하십시오. 즉

, 당신의 "UI"코드에서 "서비스"(또는 "비즈니스 논리") 코드를 분할하면은 다음과 같이 작동하도록 :

// In StuffService class: 
public async Task<Result> FetchAsync() 
{ 
    //network stuff 
    return result; 
} 

// In StuffViewModel class: 
public async void ButtonClicked() 
{ 
    foreach (var stuff) 
    { 
    var result = await Task.Run(() => _stuffService.FetchAsync()); 
    MyProperty = result.MyProperty; 
    count += result.Count; 
    } 

    if (count == 0) 
    //... 
} 

public Property MyProperty 
{ 
    get { return _myProperty; } 
    set 
    { 
    _myProperty = value; 
    RaisePropertyChanged(); 
    } 
} 
private void RaisePropertyChanged([CallerMemberName] string pChangedProperty = null) 
{ 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(pChangedProperty)); 
} 

이 방법은, 어떤 수동 스레드 점프 없다, 네트워크 호출이 진정으로 비동기 경우이 불필요한해야하지만 모든 특성 등

내가 Task.Run 호출에 남겨 않았다, 표준 뷰 모델 구현, 코드가 간단하고 유지 보수입니다 있습니다.

관련 문제