Не требуется еще один вызов ( + фоновый работник)
Я искал все выше и ниже для вызова необходимых связанных сообщений о переполнении стека... это помогло мне многому научиться... но у меня есть пара вопросов... не только связанных с вызовом требуется, но и фоновый работник.. терпите меня, пожалуйста..:)
мое приложение делает что-то длинное и нуждается в обновлении графического интерфейса в процессе (индикатор выполнения, строка состояния, текстовые поля).. Я использовал поток, но он выдал страшное межпоточное исключение при обновлении интерфейса.. я недавно (вроде) научился правильно использовать invokerequired... [ Автоматизация шаблона кода InvokeRequired].. код, который я использовал из этого поста:
public static partial class CHelper
{
public static void InvokeIfRequired(this Control oCtrl, MethodInvoker fnAction)
{
if (oCtrl.InvokeRequired)
{
oCtrl.Invoke(fnAction);
}
else
{
fnAction();
}
}
}
public partial class Form1 : Form
{
public void Test()
{
this.InvokeIfRequired(() =>
{
Text = "Window Title";
button1.Text = "Hello";
});
button1.InvokeIfRequired(() =>
{
Text = "Window Title";
button1.Text = "Hello";
});
}
}
теперь вот что я заметил... this.InvokeIfRequired и button1.InvokeIfRequired оба делают одно и то же.. почему это так? я ожидал, что текст в button1.InvokeIfRequired будет соответствовать свойству текста button1... но вместо этого он ссылается на родительскую форму... мне это кажется глупым, не интуитивным и неправильным... или, может быть, я делаю что-то не так...
другой вопрос.. я тогда не получил навык invokerequired, поэтому я прибег к использованию фонового работника.. и использованию события progress для обновления графического интерфейса..
public partial class Form1 : Form
{
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker1.ReportProgress(0, "Hello World");
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null)
{
button1.Text = e.UserState as string;
}
}
}
до сих пор это не вызвало у меня проблем.. я хочу знать, какой из этих двух подходов лучше? и почему? Кроме того, есть ли способ передать данные в предыдущую функцию InvokeIfRequired?
спасибо.. =)
edit 01: Есть ли разница между использованием Invoke для родительской формы или для целевого элемента управления?.. да, form.invoke и control.invoke одинаковы.. но почему это должно быть? это не интуитивно, и дает неправильное впечатление..
1 ответ
Ну, это не имеет значения для элемента управления Button. В Windows есть жесткое правило, согласно которому все дочерние окна окна должны принадлежать одному потоку. Таким образом, по этому правилу методы Begin/Invoke() формы и кнопки будут перенаправлять вызов в правильный поток.
Обратите внимание, что становится неудобно, когда вам нужно обновить свойство компонента, у которого нет свойства Handle. Как и ToolStripButton. Теперь вам нужно выбрать другой элемент управления. Так что предпочитайте последовательность и всегда используйте форму.
И конечно же, сделайте ставку на BackgroundWorker. Он обладает способностью помочь вам сделать это правильно, ограничив количество способов, которыми вы можете стрелять ногой.