Создать элемент в фоновом потоке и добавить в основной интерфейс - PullRequest
1 голос
/ 16 декабря 2009

У меня проблема с многопоточностью в WPF. Я хочу создать сложный пользовательский интерфейс, а затем добавить его в главное окно. Пока этот сложный пользовательский интерфейс создается, я хочу показать индикатор выполнения в моем главном окне. Я думаю, что это может быть сделано только с потоками. Но есть проблема. Созданный элемент нельзя добавить в главное окно, поскольку он создан в отдельном потоке. Кто-нибудь знает, есть ли возможность перенести элементы UIE, созданные в фоновом потоке, в основной поток. Если я пытаюсь простым способом, он говорит, что к объекту нельзя получить доступ, потому что он находится в отдельном потоке. Я уже сделал мою строку прогресса прогрессивной.

Я надеюсь, что следующий пример немного лучше объяснит, что я хочу.

StackPanel tcForm = new StackPanel();
Semaphore loadedSema = new Semaphore(0,1);
Thread thread = new Thread(new ThreadStart(delegate(){
           //Formular should be created in background               
           tcForm.Children.Add(new Formular());
           ProgressBar.AddProgress();
           //...other things
           loadedSema.Release();
}));
thread.start();
loadedSema.WaitOne();

new Formular() работает очень долго, поэтому я подумал о создании в фоновом режиме.

Также невозможно добавить Formular в переменную и затем добавить ее в основной поток.

//this is also impossible

//in background-thread
form = new Formular

//in main-thread
tcForm.Children.Add(form);

Я надеюсь, что есть способ для этого. Было бы неплохо, если есть несколько советов,

Спасибо, Мартин

Ответы [ 5 ]

3 голосов
/ 16 декабря 2009

Вы должны использовать Dispatcher.Invoke метод

...
        this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(new Formular());
           ProgressBar.AddProgress();};)
....

EDIT
Вы можете создать объект Fromular () перед отправкой, если он работает долго

var f = new Formular();
this.Dispatcher.Invoke(delegate{ tcForm.Children.Add(f);
               ProgressBar.AddProgress();};)
1 голос
/ 16 декабря 2009

Я мало что знаю о WPF, но я только что узнал о BackGroundWorker, который, вероятно, сделает всю работу за вас.

http://dotnetperls.com/backgroundworker

Вам просто нужно обработать событие WorkerCompleted, которое возникает после задачи и должно выполняться в главном потоке. Он также может сообщать о прогрессе для обновления вашего индикатора выполнения.

Пример:

    void worker_Start()
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork +=
            new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

        worker.RunWorkerAsync("MyArg");

    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
         e.Result = new Formular();
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.Controls.Add((Control)e.Result);
    }
1 голос
/ 16 декабря 2009

Если все, что вы хотите сделать, это обновить индикатор выполнения (или аналогичный), то вы должны создать весь пользовательский интерфейс заранее в главном потоке, а затем отправить обновления статуса из фонового потока в основной поток, используя формы Вызвать метод (например, отправить int, чтобы сообщить о прогрессе от 0 до 100%)

Я не думаю, что есть способ разделять элементы управления окнами между потоками.

РЕДАКТИРОВАТЬ: Хорошо, теперь я вижу, что это помечено WPF. Ответ остается тем же, но вместо вызова элемента управления вы используете класс Dispatcher (каждый графический элемент содержит ссылку на соответствующего диспетчера). Вы также можете использовать класс BackgroundWorker , как предлагается в другом ответе.

0 голосов
/ 20 мая 2011

Вы можете XAML сериализовать ваши элементы пользовательского интерфейса и затем отправить их обратно в основной поток. Не уверен, что быстрее десериализовать в основном потоке, чем создавать их там в первую очередь.

0 голосов
/ 16 декабря 2009

Нет - это невозможно. WPF в основном однопоточный.

Однако вы должны задаться вопросом, почему создание интерфейса занимает так много времени. WPF довольно быстрый. «Обычное» создание контроля не должно быть узким местом.

Может быть, вы можете оптимизировать создание других объектов; попробуйте профилировать ваше приложение.

И попробуйте построить свой пользовательский интерфейс снизу вверх: последнее действие должно добавить ваш элемент управления в форму.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...