Проблема диспетчера WPF при добавлении элементов вкладки в элемент управления вкладками - PullRequest
0 голосов
/ 08 апреля 2011

Я получаю сообщение об ошибке при запуске этого кода:

tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); }));   

tabcontrol1 жестко запрограммирован в xaml, а элементы табуляции создаются во время выполнения. Я получаю сообщение об ошибке:

TargetInvocationException был Необработанное исключение было брошено цель вызова.

Я бы хотел услышать любые мысли по этому поводу. Спасибо

UPDATE

внутреннее исключение:

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

полный код метода:

TabItem tbItem = new TabItem();
                tbItem.Header = worker;       

                Grid grid = new Grid();

                ListBox listBox = new ListBox();
                listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                listBox.VerticalAlignment = VerticalAlignment.Stretch;
                listBox.ItemsSource = datasource.Where(i => i.Category == worker);

                grid.Children.Add(listBox);
                tbItem.Content = grid;

                tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() => { tabControl1.Items.Add(tbItem); })); 

Метод вызывается так:

Thread newThread = new Thread(myMethod);
            newThread.SetApartmentState(ApartmentState.STA);
            newThread.Start(); 

ДРУГОЕ ОБНОВЛЕНИЕ

Это работает:

tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, 
                    (Action)(() => 
                    {
                        TabItem tbItem = new TabItem();
                        tbItem.Header = worker;


                        //Grid & ListBox(within tab item)
                        Grid grid = new Grid();

                        ListBox listBox = new ListBox();
                        listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                        listBox.VerticalAlignment = VerticalAlignment.Stretch;
                        listBox.ItemsSource = datasource.Where(i => i.Category == worker);

                        grid.Children.Add(listBox);
                        tbItem.Content = grid;

                        tabControl1.Items.Add(tbItem); 
                    }));                            

Ответы [ 3 ]

1 голос
/ 08 апреля 2011

Как вы можете видеть, ваш tbItem создан в другом потоке, даже если он пытается отправить его обратно в основной поток GUI TAbControl.

почему бы не извлечь часть, которая занимает больше времени (для которой вы используете поток), и как только вы вернете результат, продолжите создание tbItem и добавьте его в TabControl в потоке GUI

Пример:

tabControl.Dispatcher.Invoke calls below function with dataSoruce result it gets 
List<string> result = null;
tabControl.Dispatcher.Invoke((Action<IEnumerable<string>>)ProcessResult, result);

public  void ProcessResult(IEnumerable<string> datasource)
{
   //this is where you do creating TabItem and assigning data source to it and adding to TabControl. 

}

Не скомпилировано, пожалуйста, проверьте синтаксис

0 голосов
/ 08 апреля 2011

Проблема в том, что вы создаете свои элементы UIE в отдельном потоке. Это не разрешено.

Вы можете выполнять свою обработку в фоновом потоке (вызов datasource.Where(i => i.Category == worker);), но, к сожалению, каждый элемент пользовательского интерфейса должен быть построен и полностью использоваться в основном потоке пользовательского интерфейса.

В вашем случае это означает создание ваших ListBox и Grid в потоке пользовательского интерфейса внутри вызова Dispatcher.

Я бы предложил переписать это как:

// Load the data on the background...
var data = datasource.Where(i => i.Category == worker);

// Do all work on the UI thread
tabControl1.Dispatcher.Invoke(DispatcherPriority.Normal, 
                (Action)(() => 
                {
                    TabItem tbItem = new TabItem();
                    tbItem.Header = worker;

                    //Grid & ListBox(within tab item)
                    Grid grid = new Grid();

                    ListBox listBox = new ListBox();
                    listBox.HorizontalAlignment = HorizontalAlignment.Stretch;
                    listBox.VerticalAlignment = VerticalAlignment.Stretch;
                    listBox.ItemsSource = data;

                    grid.Children.Add(listBox);
                    tbItem.Content = grid;

                    tabControl1.Items.Add(tbItem); 
                }));    
0 голосов
/ 08 апреля 2011

Проверьте свойство InnerException, чтобы выяснить причину. TargetInvocationException - это просто оболочка для среды выполнения wpf. Ваша лямбда, вероятно, бросает, но без фактического исключения вы не можете сказать.

редактировать

Вы создаете TabItem в другом потоке, поэтому поток GUI не может получить к нему доступ, даже если вы используете диспетчер для фактического добавления. Как вы уже опубликовали в своем последнем фрагменте, вы должны создать TabItem в ветке GUI. Выполняйте вычисления только в другом потоке, и после возврата результата выполните фактическое создание TabItem в потоке GUI (при необходимости через Dispatcher).

...