将选项卡项添加到选项卡控件时WPF分派器问题

本文关键字:选项 WPF 分派 问题 添加 控件 | 更新日期: 2023-09-27 17:49:43

运行此代码时出现错误:

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

tabcontrol1被硬编码到xaml中,TAB项/s是在运行时构建的。我得到一个错误:

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

将选项卡项添加到选项卡控件时WPF分派器问题

正如你所看到的,你的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. 
}

未编译,请检查语法

检查InnerException属性,找出原因。TargetInvocationException只是wpf运行时的一个包装器。你的lambda可能会抛出异常,但如果没有实际的异常,你无法判断。

编辑

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

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

你可以在后台线程(调用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); 
                }));