2013-04-08 1 views
-5

나는 목록 상자에 50 개 항목의 로딩 시간이 오래 (약 5 초)이 걸리기 때문에 다른 스레드에서 목록 상자에로드 데이터 모델 및로드 항목을 추가하려고합니다.BackgroundWorker에 잘못된 크로스 스레드 액세스

내가있는 BackgroundWorker에 문제가 그것은 나를 잘못된 크로스 스레드 액세스에게 내가 잘못 뭐하는 거지 Inbox.xaml

public Inbox() 
    { 
     InitializeComponent(); 

     DataContext = App.ViewModel; 
    } 

    protected override void OnNavigatedTo(NavigationEventArgs e) 
    { 
     ProgressIndicator progress = new ProgressIndicator 
     { 
      IsVisible = true, 
      IsIndeterminate = true, 
      Text = "Načítání" 
     }; 

     SystemTray.SetProgressIndicator(this, progress); 
     SystemTray.IsVisible = true; 

     BackgroundWorker backgroundWorker = new BackgroundWorker(); 
     backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork); 
     backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted); 

     backgroundWorker.RunWorkerAsync(); 
    } 

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     LoadData(); 
    } 

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Error != null) 
     { 
      MessageBox.Show(e.Error.Message); 
     } 
     else 
     { 
      SystemTray.IsVisible = false; 
     } 
    } 

    private void LoadData() 
    { 
     try 
     { 
      (this.DataContext as MainViewModel).LoadInboxData(); 
     } 
     finally 
     { 
      TasksListBox.ItemsSource = (this.DataContext as MainViewModel).Tasks; 
     } 
    } 

그분은 코드 에러 보여?

+0

을 받고 어떤 오류 :

당신의 코드는 오류가 발생하지 않도록 다음과 같이 다시 쓸 수

? 스택 추적을 게시 할 수 있습니까? – Shark

+0

UI 컨트롤의'ItemsSource'에 접근 할 때'LoadData'라고 추측합니다. 내가 정확하게 기억할 수는 없지만, 생각하는'Dispatcher '에 대한 호출을 호출해야합니다. –

+2

여기 및 기타 사이트에서 수천 가지 질문 중 하나를 검색 할 수 있습니다. 이것은 하루에 여러 번 질문하는 질문입니다 ... 화면의 '관련'스레드를 살펴보십시오. – Servy

답변

1

UI가 아닌 스레드에서 UI를 업데이트하려고하므로 예외가 발생합니다.

만 UI 스레드가 UI 업데이트를 수행 할 수 있습니다, 당신은 비 UI 스레드에서 UI를 업데이트하기 위해 Dispatcher를 사용해야합니다.

Dispatcher.BeginInvoke(() => 
{ 
    // Update UI in here as this part will run on the UI thread. 
}); 

참조 : http://msdn.microsoft.com/en-gb/library/system.windows.threading.dispatcher.begininvoke.aspx

+1

백그라운드 작업자를 사용하는 것이므로 수동으로 호출하지 않습니다. 그는 do 작업 이벤트 대신 worker 완료 이벤트의 결과로 UI를 간단히 업데이트해야합니다. – Servy

+0

그래도 작동하지만 항목이 목록 상자에 추가 될 때로드하는 것을 보여줄 필요가 있습니다. 이것은 오랜 시간이 걸립니다. – Earlgray

+0

@Servy 그는 실제로 그렇게 할 수있었습니다! 그것은 하나의 방법 일 것입니다.하지만 장시간 운영중인 사용자간에 UI를 업데이트해야 할 경우 여러 가지 배경 작업자와 체인을 함께 만들지 않는 한 전화를 파견하는 것이 좋습니다. 더 나은 "현대적인"접근법은 간단히 새로운 비동기식 방법으로 넘어가는 것이고, 긴 스레드는 새로운 스레드에 강제로 연결되어 모든 비헤이비어와 무거운 짐을 처리하는 비동기를 기다리게됩니다. – Clint

2

BackgroundWorker.DoWork 핸들러는 배경이 아닌 UI 스레드에서 실행됩니다. 귀하의 예제에서 LoadData() 메서드는 배경이 아닌 UI 스레드에서 실행되며 해당 메서드에서 ListBox의 ItemSource 속성을 설정합니다.

당신이 시도하고이 핸들러는 UI 스레드에서 실행 귀하의 BackgroundWorkder.RunWorkerCompleted 핸들러에 해당 코드를 이동해야합니다. 당신이

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Error != null) 
    { 
     MessageBox.Show(e.Error.Message); 
    } 
    else 
    { 
     SystemTray.IsVisible = false; 
    TasksListBox.ItemsSource = (this.DataContext as MainViewModel).Tasks; 
    } 
} 

private void LoadData() 
{ 
    (this.DataContext as MainViewModel).LoadInboxData(); 
} 
+0

내가 같은 오류가 있고 항목 목록 상자에 추가 할 때 내가 로딩을 보여줄 필요, 이것은 당신이 '로드'배너를 오버레이 찾고 있다면 여러 가지 방법이있다, 오랜 시간이 – Earlgray

+0

을 것입니다 수 있습니다. 1) 경계선/텍스트 블록/진행 표시 줄과 같은 다른 컨트롤을 만든 다음 ListBox 위에 표시하고 필요할 때 해당 컨트롤의 표시 여부를 전환하려면 z 순서로 정렬하십시오. 2) 사용자 adorner 컨트롤. http://www.codeproject.com/Articles/57984/WPF-Loading-Wait-Adorner를 참조하십시오. – sthotakura

관련 문제