代码之家  ›  专栏  ›  技术社区  ›  myermian

WPF多线程:使用Dispatcher但UI仍然挂起?

  •  2
  • myermian  · 技术社区  · 14 年前

    虽然我使用的是调度器,但我的UI挂起时有点问题,在我进一步处理之前,我想知道这是否是我处理数据检索的方式。

    现在我的主窗口正在创建视图和视图模型。然后,在新线程内部(使用调度程序)设置View.DataContext=ViewModel。一个非常大的可观测集合是在绑定启动时懒洋洋地创建的,而绑定的启动正是导致增长放缓的原因。然而,似乎其他一些应该在慢波出现之前出现的UI项实际上并没有出现。

       private void ButtonClick(Object sender, RoutedEventArgs e)
       {
            MyView view = new MyView();
            MyViewModel vm = new MyViewModel();
    
            TabItem tabItem = new TabItem();
            tabItem.Header = "MyView";
            tabItem.Content = view;
    
            MyTabCollection.Items.Add(tabItem);
    
            Window working = new Working();
            working.Show();
    
            ThreadStart thread = delegate()
            {
                DispatcherOperation operation = Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new Action(delegate()
                    {
                        view.DataContext = vm;
                        ((FrameworkElement)view.Parent).Focus();
                        working.Close();
                    }
                    )
                );
            };
    
            Thread theThread = new Thread(thread);
            theThread.Start();
        }
    

    这基本上是说它应该创建一个视图和一个视图模型,然后将该视图添加到我拥有的选项卡集合(这意味着它至少应该显示新的选项卡)。而且,它还应该显示一个“工作…”窗口。之后,应该有一个单独的线程将ViewModel链接到视图,关注该选项卡并关闭工作窗口。问题是,第一部分直到所有工作完成才显示;选项卡不显示,工作窗口直到新线程实际完成后才显示(这会导致工作窗口立即显示/关闭)。我想这可能与我检索数据的方式有关,但我不确定。它是这样做的:

    1. 创建视图
    2. 创建内容设置为视图的TabItem,并将TabItem添加到TabCollection。
    3. 创建/显示“工作…”窗口
    4. Dispatcher:设置View.DataContext=ViewModel。此事件触发数据绑定,而数据绑定又获取ObservableCollection。由于OC是惰性创建的,所以现在正在创建它(这是瓶颈)。<--这是不是搞乱了我单独的线程/调度程序?
    5. 关闭“工作…”窗口
    3 回复  |  直到 14 年前
        1
  •  5
  •   Jon Skeet    14 年前

    您的额外线程所做的只是将另一个调用封送回调度程序线程。想必你真的想 在额外的线程上,或者没有必要创建它。

    理想情况下,您的额外线程应该适当地获取所有数据,只留下您在dispatcher线程中实际连接所有数据。重要的是决定你需要在UI线程上做哪些工作,以及你需要在后台线程上做哪些工作。

        2
  •  2
  •   Ray Burns    14 年前

    显然你对这个问题的分析是正确的。您的视图模型在需要时懒洋洋地加载数据,直到Dispatcher回调时才会发生这种情况,此时您又回到UI线程上,并且一切都被锁定。

    在我看来,解决方案是在数据访问层做线程:

    对于总数等:同样的想法。当数据进入总量时,发生事件(对于DependencyProperty或使用INotifyPropertyChanged自动)。

    请注意,有时在检索到实际数据之前,操作必须阻塞。我认为在这种情况下最简单的事情是在数据层提供方法来强制同步加载数据。

        3
  •  0
  •   Dean Chalk    14 年前

    你的 DispatcherPriority 设置为 Normal Background 因为这可能会改善渲染效果