Исключения BindingSource и Cross-ThreadC#

Место общения программистов C#
Ответить
Anonymous
 Исключения BindingSource и Cross-Thread

Сообщение Anonymous »

Чтобы объяснить эту проблему, я поместил все необходимое в небольшой пример приложения, который, надеюсь, объясняет проблему. Я действительно старался уместить все в как можно меньше строк, но в моем реальном приложении эти разные актеры не знают друг друга и не должны. Таким образом, простой ответ типа «возьмите переменную, расположенную несколькими строками выше, и вызовите для нее Invoke» не сработает.

Итак, давайте начнем с кода, а потом еще немного объяснение. Сначала есть простой класс, реализующий INotifyPropertyChanged:

Код: Выделить всё

public class MyData : INotifyPropertyChanged
{
private string _MyText;

public MyData()
{
_MyText = "Initial";
}

public string MyText
{
get { return _MyText; }

set
{
_MyText = value;
PropertyChanged(this, new PropertyChangedEventArgs("MyText"));
}
}

public event PropertyChangedEventHandler PropertyChanged;
}
Так что ничего особенного. А вот пример кода, который можно просто поместить в любой пустой проект консольного приложения:

Код: Выделить всё

static void Main(string[] args)
{
// Initialize the data and bindingSource
var myData = new MyData();
var bindingSource = new BindingSource();
bindingSource.DataSource = myData;

// Initialize the form and the controls of it ...
var form = new Form();

// ... the TextBox including data bind to it
var textBox = new TextBox();
textBox.DataBindings.Add("Text", bindingSource, "MyText");
textBox.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
textBox.Dock = DockStyle.Top;
form.Controls.Add(textBox);

// ... the button and what happens on a click
var button = new Button();
button.Text = "Click me";
button.Dock = DockStyle.Top;
form.Controls.Add(button);

button.Click += (_, __) =>
{
// Create another thread that does something with the data object
var worker = new BackgroundWorker();

worker.RunWorkerCompleted += (___, ____) => button.Enabled = true;
worker.DoWork += (___, _____) =>
{
for (int i = 0; i < 10; i++)
{
// This leads to a cross-thread exception
// but all i'm doing is simply act on a property in
// my data and i can't see here that any gui is involved.
myData.MyText = "Try " + i;
}
};

button.Enabled = false;
worker.RunWorkerAsync();
};

form.ShowDialog();
}
Если вы запустите этот код, вы получите межпоточное исключение при попытке изменить свойство MyText. Это происходит потому, что объект MyData вызывает PropertyChanged, который будет перехвачен BindindSource. Затем, в соответствии с привязкой, будет предпринята попытка обновить свойство Text TextBox. Что явно приводит к исключению.

Моя самая большая проблема здесь связана с тем, что объект MyData не должен ничего знать о графическом интерфейсе (потому что он простой объект данных). Кроме того, рабочий поток ничего не знает о графическом интерфейсе. Он просто воздействует на кучу объектов данных и манипулирует ими.

ИМХО, я думаю, что BindingSource должен проверить, в каком потоке находится принимающий объект, и выполнить присвойте Invoke(), чтобы получить их значение. К сожалению, это не встроено в него (или я ошибаюсь?), поэтому мой вопрос:

Как можно разрешить это межпотоковое исключение, если объект данных или рабочий поток знает что-либо об источнике привязки, который прослушивает их события, чтобы передать данные в графический интерфейс.

Подробнее здесь: https://stackoverflow.com/questions/707 ... exceptions
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»