Любое решение для исключения исключений из незаконной перекрестной резьбы?
Когда вы связываете данные в С#, поток, который изменяет данные, также приводит к изменению элемента управления. Но если этот поток не тот, на котором был создан элемент управления, вы получите исключение операции "Незаконный перекрестный поток".
Есть ли способ предотвратить это?
Ответы
Ответ 1
Если модификация данных не занимает слишком много времени (это означает, что если основная цель фонового потока не является фактической модификацией данных), попробуйте переместить раздел, который изменяет данные делегату, и Invoke'ing, что делегировать.
Если фактическая тяжелая работа связана с данными, вам, вероятно, придется создать глубокую копию этих данных, чтобы перейти к фоновому потоку, который отправит обработанные данные обратно в поток пользовательского интерфейса через Invoke снова.
Вам нужно будет переместить код, который изменяет данные в функции делегата (потому что изменение данных - это то, что запускает обновление управления). Кроме этого, вам не нужно писать ничего лишнего.
Ответ 2
Вы должны иметь возможность сделать что-то вроде:
if (control.InvokeRequired)
{
control.Invoke(delegateWithMyCode);
}
else
{
delegateWithMyCode();
}
InvokeRequired - это свойство в элементах управления, чтобы узнать, находитесь ли вы в правильном потоке, затем Invoke вызовет делегат в правильном потоке.
UPDATE: Вообще-то, на моей последней работе мы сделали что-то вроде этого:
private void SomeEventHandler(Object someParam)
{
if (this.InvokeRequired)
{
this.Invoke(new SomeEventHandlerDelegate(SomeEventHandler), someParam);
}
// Regular handling code
}
который устраняет необходимость блокировки else и подтягивает код.
Ответ 3
Поскольку у меня нет тестового примера, я не могу гарантировать это решение, но мне кажется, что сценарий, подобный тому, который использовался для обновления индикаторов выполнения в разных потоках (использование делегата), будет подходит здесь.
public delegate void DataBindDelegate();
public DataBindDelegate BindData = new DataBindDelegate(DoDataBind);
public void DoDataBind()
{
DataBind();
}
Если привязка данных должна выполняться определенным потоком, то пусть этот поток выполнит работу!
Ответ 4
Если вызов потока является "незаконным" (т.е. вызов DataBind влияет на элементы управления, которые не были созданы в потоке, из которого он вызывается), вам необходимо создать делегат, чтобы даже если решение/подготовка для DataBind не выполняются в потоке, создающем управление, любая результирующая их модификация (то есть DataBind()) будет.
Вы бы назвали мой код из рабочего потока следующим образом:
this.BindData.Invoke();
Это приведет к тому, что исходный поток выполнит привязку, которая (предположим, что это поток, создавший элементы управления), должна работать.
Ответ 5
В WPF и Silverlight инфраструктура привязки заботится о переключении на поток пользовательского интерфейса.