将选项卡项添加到选项卡控件时出现WPF Dispatcher问题

时间:2011-04-08 15:51:51

标签: c# wpf dispatcher

运行此代码时出现错误:

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

tabcontrol1被硬编码到xaml中,标签项是在运行时构建的。 我收到了一个错误:

  

TargetInvocationException是   未处理的异常已被抛出   调用的目标。

我很想听到有关这方面的任何想法。 感谢

更新

内部异常:

  

{“调用线程无法访问   这个对象因为一个不同的线程   拥有它。“}

完整的方法代码:

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 个答案:

答案 0 :(得分:1)

你可以看到你的tbItem是在不同的线程上创建的,即使它尝试将它发送回TAbControl的主要gui线程。

为什么不提取需要更长时间的部分(你使用的是线程),一旦你得到结果,继续创建tbItem并将其添加到GUI线程中的TabControl

示例:

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. 

}

没有编译,请检查语法

答案 1 :(得分:0)

检查InnerException属性以找出原因。 TargetInvocationException只是wpf运行时的包装器。你的lambda可能会抛出,但没有实际的例外,你无法分辨。

修改

您正在另一个线程中创建TabItem,因此即使您使用调度程序进行实际添加,GUI线程也无法访问它。正如您已使用上一个代码段发布的那样,您必须在GUI线程中创建TabItem。只在不同的线程中进行计算,一旦结果返回,在GUI线程中实际创建TabItem(必要时通过Dispatcher)。

答案 2 :(得分:0)

问题是你是在一个单独的线程上创建你的UIElements。这是不允许的。

您可以在后台线程(对datasource.Where(i => i.Category == worker);的调用)上进行处理,但不幸的是,每个UI元素都需要在主用户界面线程上完全构建和使用。

在您的情况下,这意味着在Dispatcher调用内部的UI线程上构建ListBox和Grid。

我建议将其重写为:

// 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); 
                }));