Приложение wpf аварийно завершает работу при использовании BackgroundWorker - PullRequest
3 голосов
/ 05 октября 2010

моя модель представления создает BackgroundWorker в своем конструкторе. BackgroundWorker обновляет свойства модели из ее обработчика событий DoWork. Приведенный ниже код является надуманным примером (ViewModelBase почти дословно взят из статьи MVVM).


public class MyViewModel : ViewModelBase
{
    public int MyProperty
    {
        get
        {
            return this.my_property;
        }
        private set
        {
            if (this.my_property != value)
            {
                this.my_property = value;
                this.OnPropertyChanged("MyProperty");
            }
        }
    }

    public MyViewModel()
    {
        this.worker = new BackgroundWorker();
        this.worker.DoWork += (s, e) => { this.MyProperty = 1; };
        this.worker.RunWorkerAsync();
    }
}

моя точка зрения привязана к этой модели:


public partial class MyPage : Page
{
    public MyPage()
    {
        InitializeComponent();
        this.DataContext = new MyViewModel();
        }
}

проблема в том, что мое приложение прерывается, когда отображается моя страница. это определенно имеет отношение к рабочему потоку и привязке данных в XAML. кажется, что если я запускаю рабочий изнутри обработчика событий Loaded для страницы, проблема исчезнет, ​​но, поскольку трудно воспроизвести последовательно, я не уверен, является ли это правильным решением.

есть ли у кого-нибудь какие-либо предложения или идеи, что может быть точной причиной?

РЕДАКТИРОВАТЬ: я могу воспроизвести его, только если я запускаю его без отладчика. и ошибка в системном журнале - InvalidOperationException, брошенный из ShowDialog, который не очень помогает. под отладчиком работает нормально.

спасибо за любую помощь константин

Ответы [ 5 ]

3 голосов
/ 06 октября 2010

Поскольку MyProperty не является потокобезопасным, могут возникнуть странные вещи, когда два потока пытаются получить к нему доступ одновременно.Вы должны либо

  1. сделать его потокобезопасным (например, с помощью ключевого слова lock), либо

  2. убедиться, что его значение равноизменился только в потоке пользовательского интерфейса.

Я бы предложил второй подход, так как блокировка всегда сложная вещь.В частности, BackgroundWorker уже поддерживает передачу значений обратно в поток пользовательского интерфейса после завершения работы:

public void MyViewModel()
{
    this.worker = new BackgroundWorker();
    this.worker.DoWork += (s, e) => { /* do something */ e.Result = 1; };
    this.worker.RunWorkerCompleted += (s, e) =>
    {
        // all of this happens back in the UI thread
        if (e.Error != null)
        {
            // do some error handling... some exception occurred during DoWork
        }
        else
        {
            this.MyProperty = (int)e.Result;
        }
    };
    this.worker.RunWorkerAsync();
}
3 голосов
/ 06 октября 2010

Похоже, ваш фоновый работник пытается обновить разметку / привязки XAML из фонового потока. Вы должны вызвать Dispatcher, чтобы передать значение в основной поток следующим образом:

Внутри вашего рабочего мероприятия:

Dispatcher.BeginInvoke(delegate()
{
//UI element (test.Text) being updated with value i.ToString() from background thread
test.Text += i.ToString();
});
}
2 голосов
/ 06 октября 2010

Возможно, это связано с обновлением пользовательского интерфейса из фонового потока, но WPF должен справиться с этим за вас: Убедиться, что OnPropertyChanged () вызывается в потоке пользовательского интерфейса в приложении MVFM WPF

Читайте это тоже: http://www.wintellect.com/CS/blogs/jlikness/archive/2009/12/16/dispatching-in-silverlight.aspx

1 голос
/ 06 октября 2010

Запуск INotifyPropertyChanged.PropertyChanged или INotifyCollectionChanged.CollectionChanged (обычно из ObservableCollection) событий в объекте с привязкой к данным из фонового потока недопустим в WPF.

Обойти это можно с помощью Dispatcher.Invoke дляустановите свое свойство или задайте свойство в обработчике RunWorkerCompleted после возврата значения из любых длительных операций (сети или вычислений), выполненных в обработчике DoWork.

0 голосов
/ 06 октября 2010

Я думаю, что проблема была в том, что я обновлял свои свойства из обработчика событий DoWork. после того, как я переместил обновления в обработчик ProgressChanged, проблема, похоже, исчезла. Теперь я даже могу обновить свою коллекцию ObservableCollection из ProgressChanged. поэтому похоже, что обработчик событий ProgressChanged автоматически вызывается в потоке пользовательского интерфейса средой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...