2013-05-15 4 views
1

У меня очень сложный UserControl, который необходимо создать во время выполнения. Это создание замораживает графический интерфейс около 5 секунд (что неприемлемо).Создайте комплекс UserControl во время выполнения без замораживания GUI

Я пытался переместить эту операцию в Фоновой работнику и в конечном итоге с этим Exception:

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

Я знаю, что я не могу использовать поток MTA для создания элемента UserControl/UI. Я попытался использовать комбинацию BackgroundWorker и Dispatcher, но это не сработало.


Сначала попробуйте

private void LetsGo() 
{ 
    var backgroundWorker = new BackgroundWorker(); 

    backgroundWorker.DoWork += backgroundWorker_DoWork; 
    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted; 

    backgroundWorker.RunWorkerAsync(); 
} 

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    DispatcherOperation dispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke(new Action(this.GenerateControlAsync), DispatcherPriority.Background); 
} 

private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    if (e.Cancelled) 
    { 
     // Cancelled 
    } 
    else if (e.Error != null) 
    { 
     //Exception Thrown 
    } 
    else 
    { 
     //Completed 
    } 
} 

private void GenerateControlAsync() { 
    this.Control = new TimeConsumingUserControl(); 
} 

Код выше не работает, метод this.GenerateControlAsync не выполняется.


Второй попробовать

private async void GenerateControl() 
{ 
    this.Control = await Dispatcher.CurrentDispatcher.InvokeAsync<UserControl>(this.GenerateControlAsync); 
} 

private UserControl GenerateControlAsync() 
{ 
    return new TimeConsumingUserControl(); 
} 

этот пример работает, но он держит замораживание GUI поток.


Я использую WPF и .net Framework 4.5.

Обратите внимание, что метод GenerateControlAsync() не просто создает экземпляр UserControl, .

Чтобы ответить на вопрос @HighCore «s: На самом деле XAML кодекс UserControl преобразуется из XML-файлов с помощью XSLT и Codebehind генерируется с использованием CodeDOM. Все вещи должны быть скомпилированы и завернуты в сборку. Я использую assembly.CreateInstance(), чтобы получить экземпляр UserControl. Эта строка выбрасывает исключение. В моем графическом интерфейсе у меня есть ContentControl, который имеет привязку к UserControl в моей ViewModel. Данные для генерации, такие как xml-файлы, которые необходимо преобразовать, извлекаются из веб-службы.

Вот почему выполнение этого метода занимает немного больше времени, чем кто-то может ожидать.

+1

'Есть гораздо больше логики.' - Какая логика? Вы должны отделить пользовательский интерфейс от данных и бизнес-логики, и у вас больше не будет этих проблем. Кстати, создание элементов пользовательского интерфейса в процедурном коде не очень хорошая идея с точки зрения MVVM. Для этого и предназначен XAML. –

+0

Я просто хотел избежать обсуждения. Фактически XAML-код UserControl преобразуется из xml-файлов через XSLT, а Codebehind генерируется с использованием CodeDOM. Все вещи должны быть скомпилированы и завернуты в сборку. Я использую assembly.CreateInstance(), чтобы получить экземпляр UserControl. Эта строка выбрасывает исключение. В моем графическом интерфейсе у меня есть ContentControl, который имеет привязку к UserControl в моем ViewModel – Joel

+0

. В WPF нет необходимости в любом из них, вы могли бы решить свои потребности с помощью некоторых 'DataTemplate' и' XAMLReader', но если вы уже (что просто неправильно ИМО), то я не думаю, что вы можете сделать это, чтобы улучшить его. Вы можете создавать/манипулировать элементами пользовательского интерфейса в потоке пользовательского интерфейса. Поэтому остальная часть пользовательского интерфейса станет безответственной, пока это происходит. Люди, похоже, не понимают, что концепция WPF «динамического интерфейса» полностью отличается от большинства архаичных интерфейсов пользовательского интерфейса динозавров, и эти виды хаков совершенно не нужны в WPF. –

ответ

1

Из описания всех шагов, связанных с созданием элемента управления, похоже, что вы объединяете много работы, которая не обязательно должна выполняться в одном потоке и пытаться сделать все это на любом пользовательском интерфейсе. или фоновый поток. Вместо этого вы должны выполнять минимальный объем работы, необходимый для потока пользовательского интерфейса (фактическое создание экземпляра UserControl) и делать все остальное на рабочем потоке. Вместо одного асинхронного блока работы вы должны сделать 2 шага, которые с асинхронным ожиданием очень просты. Это должно выглядеть следующим образом:

var dynamicAssembly = await this.GenerateControlAssemblyAsync(); 
this.Control = this.GenerateControlFromAssembly(dynamicAssembly); 

Благодаря тому, как ожидает работает вторая линия будет автоматически запускаться на исходном (UI) потоке, поэтому нет необходимости в каких-либо Dispatcher вызовов. В GenerateControlAssemblyAsync вы должны использовать Task.Run и сделать в этом весь другой код. GenerateControlFromAssembly не должен делать ничего, кроме экземпляра экземпляра UC.

+0

спасибо, он работает. мое решение выглядит так: var token = wait Task.Factory.StartNew (this.GenerateControlAsync); – Joel

1

Вам необходимо выполнить сборку сборки. Генерация сборки занимает слишком много времени, и вам нужно поместить все в другой поток, и только генерация компонента DIRECT Ui в том же потоке.

Существует классный метод, который может загружать Xaml из потока и делать это в кусках, не забивая пользовательский интерфейс. Посмотрите: http://msdn.microsoft.com/en-us/library/aa346591.aspx

Смежные вопросы