【问题标题】:Dispatcher.CurrentDispatcher returns nullDispatcher.CurrentDispatcher 返回 null
【发布时间】:2018-05-17 12:01:27
【问题描述】:

我正在尝试关闭我在与主宿主线程不同的线程中创建的 WPF 窗口(主线程是我无法控制的 PDM 应用程序)。主机应用程序引用了我的程序集(它是一个插件)。 我不知道为什么 Dispatcher 总是为空。在主机应用程序上创建 WaitView 对我来说不是一个选项。

谢谢大家!

    var WaitViewModel = new MVVM.ViewModels.WaitViewModel();
                        MVVM.Views.WaitView WaitView = default(MVVM.Views.WaitView);
                        Dispatcher dispatcher = default(Dispatcher); 
                        var thread = new Thread(new ThreadStart(() =>
                        {
                            dispatcher = Dispatcher.CurrentDispatcher; 
                            WaitView = new MVVM.Views.WaitView();
                            WaitView.Topmost = true;
                            WaitView.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                            WaitView.DataContext = WaitViewModel;
                            WaitView.Show();
                            System.Windows.Threading.Dispatcher.Run();
                        }));
                        thread.SetApartmentState(ApartmentState.STA);
                        thread.IsBackground = true;
                        thread.Start();


'unrelated code here
if (dispatcher != null)
dispatcher.Invoke(()=>
{
WaitView.Close();
});

【问题讨论】:

标签: c# multithreading dispatcher


【解决方案1】:

两种方法:

  1. 通过构造函数将视图的调度程序传递给视图模型。

    public MyClass
    {
        public MyClass(Dispatcher dispatcher)
        {
             // use your view's dispatcher.
        }
    {
    
  2. 使用应用程序默认调度程序。

    Dispatcher dispatcher = App.Current.Dispatcher;
    

为了清楚起见,真正的视图模型不会使用调度程序,因为它位于 UI 线程上。不过,您可以使用常规方法并让视图的调度程序在视图上执行它们。

【讨论】:

  • App.Current 为我返回 null。我已经尝试过了。我的 dll 加载到一个不是 .NET 程序集的主机应用程序中。
  • @JLILIAmen 仅仅因为 App.Current.Dispatcher 在您的 incorrect 代码中为您返回 null,这还不足以成为拒绝投票的充分理由
【解决方案2】:

您应该在创建线程之前获取调度程序,然后将其传递给线程。

本着不要那样做的精神,您不应该在其他线程中创建任何形式的 UI 元素,即使它们被标记为 STA。生成只运行到永恒的子线程并不是那么好,因此可能是多个消息泵。所以,你的基础设计有点缺陷。

解决这个问题,您的其他问题就会消失。

我希望您不是因为试图让您的窗口看起来像是不同进程的一部分的控制台应用程序所做的一切?

【讨论】:

  • 我的 dll 是通过第三方应用程序加载的。
  • 我不明白为什么我应该在创建线程之前抓住调度程序。该视图将在该线程中创建。只有该线程应该更新视图,因此我试图获取该线程的调度程序的原因。我希望我没有遗漏什么。
  • 我在这里别无选择。如果我在主线程上运行视图,它就会冻结。
  • @JLILIAmen 经验表明,当您从工作线程内部调用 Dispatcher.CurrentDispatcher 时,它与 UI 线程不同,并且当您稍后尝试使用它来编组到用户界面。但不要相信我的话,相信 Enigmativity 的。考虑到你已经声明你收到了null,你对整件事相当傲慢,更不用说因为不足的理由而否决了每个人的答案。
【解决方案3】:

解决方案是从后面的视图代码中处理关闭视图。

我已向 ViewModel 添加了一个名为 CloseRequest 的属性。

查看后面的代码:

  WaitViewModel WaitViewModel;
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // get data context 
             WaitViewModel = this.DataContext as WaitViewModel;
            WaitViewModel.PropertyChanged += WaitViewModel_PropertyChanged;
        }

        private void WaitViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if(e.PropertyName == "CloseRequest")
            {
                Dispatcher dispatcher = this.Dispatcher;
                if (WaitViewModel.CloseRequest)
                    dispatcher.Invoke(() => { 
                    this.Close();
                    });
            }
        }

【讨论】:

  • 所以你抄袭了我和其他人所说的话,然后对其他人投反对票?这是你抄袭的反对票
  • @MickyD 我没有抄袭你说的话。一开始我什至不明白。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-21
  • 2020-06-19
相关资源
最近更新 更多