Поперечная резьба
Я получаю эту 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;
});
}