2013-04-08 2 views
-5

Я пытаюсь добавить загрузочный datamodel и загружать элементы в список в другом потоке, потому что загрузка 50 элементов в listbox занимает много времени (около 5 секунд).BackgroundWOker Недопустимый доступ к перекрестным потокам

У меня проблема с BackgroundWorker это показать мне ошибку неправильного пароля кросс-нить

His является код 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

Полагаю, что это ваша 'LoadData', поскольку она обращается к элементу' ItemsSource' элемента управления пользовательского интерфейса. Вы должны вызвать вызов на 'Диспетчер', я думаю, хотя я точно не помню. –

+2

Вы можете найти один из многих тысяч вопросов об этом здесь и на других сайтах. Это вопрос, заданный несколько раз в день ... Просто взгляните на «Связанные» потоки на боковой стороне экрана. – Servy

ответ

1

Вы пытаетесь обновить пользовательский интерфейс из потока, отличного от UI, поэтому вы получите исключение.

Только пользовательский интерфейс может выполнять обновления пользовательского интерфейса, вам необходимо использовать Dispatcher, чтобы обновлять пользовательский интерфейс из потока, отличного от UI.

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. – Servy

+0

ОК это работает, но мне нужно показать загрузку, когда элементы добавляются в список, это то, что занимает много времени – Earlgray

+0

@ Servy он действительно может! Это было бы одним из способов сделать это, НО, если ему нужно обновить интерфейс между длинными операциями, тогда отправка вызовов - это путь, если он не создает нескольких фоновых работников и не объединяет их вместе - беспорядочно! Лучше «современный» подход состоял бы в том, чтобы просто передать новый асинхронный метод schmancy и позволить асинхронному ожиданию с длинными операциями, которые вынуждены на новые потоки обрабатывать всю цепочку и тяжелую работу. – Clint

2

обработчик BackgroundWorker.DoWork работает на фоне не-UI потока. В вашем примере метод LoadData() работает в фоновом потоке non-ui, и вы устанавливаете свойство ItemSource ListBox в этом методе.

Вы должны попытаться переместить этот код в обработчик 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

У меня такая же ошибка, когда я извлекал строку из кода removeeloadinboxdata(), и мне нужно показать загрузку, когда элементы добавляются в список, это то, что занимает много времени – Earlgray

+0

Если вы хотите наложить баннер «Загрузка», существует несколько способов: может достигать 1) Имейте еще один элемент управления, такой как рамка границы/текстового блока/индикатора выполнения, а затем z-order, чтобы он отображался поверх ListBox и переключал видимость этого элемента управления по мере необходимости. 2) Контроль пользователя adorner. См. Это http://www.codeproject.com/Articles/57984/WPF-Loading-Wait-Adorner – sthotakura