Поперечная резьба

Я получаю эту Cross-Thread Error при попытке вызвать текстовое поле из другого потока, отличного от основного потока MMI. Я уже понимаю, почему это происходит. Мне бы хотелось узнать ваше мнение о том, как я это решаю. Я использую это, потому что я ненавижу добавлять объявления делегатов по всему коду.

private void SetText(string text)
{           
    if (textBox1.InvokeRequired)
    {
        this.Invoke(new Action<string>(SetText), new object[]{ text });
    }
    else
    {
        this.textBox1.Text = text;
    }
}

это правильный путь к этому? есть ли лучший и короткий путь?

2 ответа

Решение

Ничего плохого в том, что у тебя есть. Если вы не хотите делать рекурсивный вызов, вы можете просто добавить анонимного делегата в Invoke() вызов:

private void SetText(string text)
{
    if (this.InvokeRequired)
    {
        this.Invoke((MethodInvoker)delegate
        {
            this.textBox1.Text = text;
        });
    }
    else
    {
        this.textBox1.Text = text;
    }
}

Это единственный способ сделать это, хотя я бы сделал два изменения:

1) Используйте MethodInvoker, чтобы можно было исключить приведение типов к Func или Action, но продолжайте и используйте рекурсию, чтобы не дублировать код.

2) Добавьте возврат в блок invoke, чтобы у вас не было блока else. Я бы лучше добавил лишнюю строку, чем лишний отступ.

private void SetText(string text)
{           
    if (textBox1.InvokeRequired)
    {
        this.Invoke((MethodInvoker) delegate { SetText(text); });
        return;
    }

    this.textBox1.Text = text;
}

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

private static void InvokeIfRequired(bool required, Action action) {
    // NOTE if there is an interface which contains InvokeRequired 
    //      then use that instead of passing the bool directly.
    //      I just don't remember off the top of my head
    if (required) {
        this.Invoke((MethodInvoker) delegate { action(); });
        return;
    }

    action();
}

private void SetText(string text)
{
    InvokeIfRequired(textBox1.InvokeRequired, () => {
      this.textBox1.Text = text;
    });
}
Другие вопросы по тегам