Любое решение для исключения исключений из незаконной перекрестной резьбы?

Когда вы связываете данные в С#, поток, который изменяет данные, также приводит к изменению элемента управления. Но если этот поток не тот, на котором был создан элемент управления, вы получите исключение операции "Незаконный перекрестный поток".

Есть ли способ предотвратить это?

Ответы

Ответ 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 инфраструктура привязки заботится о переключении на поток пользовательского интерфейса.