2016-12-30 30 views
0

Я хочу создать Grid элемент на другом потоке (создавая всю сетку дорого) и обновлять StackPanel через Dispatcher. Но вызов Dispatcher всегда бросает InvalidOperationException, независимо от того, что я делаю.Dispatcher.Invoke() с параметром всегда бросает InvalidOperationException

Вот мой код:

Grid grid = new Grid(); 
Dispatcher.Invoke(() => stackPanel.Children.Add(grid)); 

Что я пробовал:

  1. Closing over a variable [не работает]

    Grid grid = new Grid(); 
    Grid closedOverGrid = grid; 
    Dispatcher.Invoke(new Action(() => stackPanel.Children.Add(closedOverGrid))); 
    
  2. Using BeginInvoke [Didn не работает]

    //declaring this in another thread. 
    Grid grid = new Grid(); 
    AddToPanel(grid); 
    
    private void AddToPanel(Grid grid) 
    { 
        Dispatcher.BeginInvoke((Action)(() => 
        { 
         stackPanel.Children.Add(grid); 
        })); 
    } 
    
  3. Using a full declaration with DispatcherPriority [не работает]

    Grid grid = new Grid(); 
    
    System.Windows.Application.Current.Dispatcher.BeginInvoke(
        DispatcherPriority.Background, 
        new Action(() => stackPanel.Children.Add(grid))); 
    
  4. Tried the .Freeze() method [не работает]

    Grid grid = new Grid(); 
    grid.Freeze(); // Not possible. 
    

ли это на самом деле не представляется возможным, или я что-то упускаю? Спасибо за ваши ответы/комментарии.

+2

Вы не должны создавать 'Grid' (и любой элемент пользовательского интерфейса) в потоке, отличном от UI, потому что, как только вы это сделаете, его нельзя использовать в потоке пользовательского интерфейса. Это стандартное поведение 'DispatcherObject' (обратите внимание, что текущий диспетчер запоминается внутри конструктора и никогда не изменяется). –

ответ

1

Доступ к элементу управления, в котором он был создан , был создан, поэтому создание элемента управления на фоновом потоке, а затем попытка его использования или изменения его в потоке пользовательского интерфейса не является вариантом. Вот почему вы получаете исключение InvalidOperationException.

Действительно ли это невозможно, или я что-то упускаю?

Это действительно возможно создать элемент управления на STA нить:

The calling thread must be STA, because many UI components require this

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

Итак, нет, вы должны создать все свои элементы управления в той же теме. Это поток, на котором было создано родительское окно, т. Е. Обычно основной поток.

Есть некоторые очень ограниченные исключения из этого правила. Дополнительную информацию можно найти в следующем сообщении в блоге: https://blogs.msdn.microsoft.com/dwayneneed/2007/04/26/multithreaded-ui-hostvisual/. Если ваш элемент управления не требует какой-либо интерактивности, вы можете, например, использовать HostVisual, как описано в этом сообщении.

Вы также можете запустить полное окно верхнего уровня в своем потоке: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/.

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