Не требуется еще один вызов ( + фоновый работник)

Я искал все выше и ниже для вызова необходимых связанных сообщений о переполнении стека... это помогло мне многому научиться... но у меня есть пара вопросов... не только связанных с вызовом требуется, но и фоновый работник.. терпите меня, пожалуйста..:)

мое приложение делает что-то длинное и нуждается в обновлении графического интерфейса в процессе (индикатор выполнения, строка состояния, текстовые поля).. Я использовал поток, но он выдал страшное межпоточное исключение при обновлении интерфейса.. я недавно (вроде) научился правильно использовать 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. Он обладает способностью помочь вам сделать это правильно, ограничив количество способов, которыми вы можете стрелять ногой.

Другие вопросы по тегам