如何使用CancellationTokenSource关闭另一个线程上的对话框? [英] How to use CancellationTokenSource to close a dialog on another thread?

查看:230
本文介绍了如何使用CancellationTokenSource关闭另一个线程上的对话框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这与我的其他问题我试图更好地了解CancellationTokenSource模型以及如何在线程边界上使用它.

I am trying to better understand the CancellationTokenSource model and how to use it across thread boundaries.

我有一个主窗口(位于UI线程上),后面的代码在其中进行操作:

I have a main window (on the UI thread) where the code behind does:

 public MainWindow()
        {
            InitializeComponent();

            Loaded += (s, e) => {
                DataContext = new MainWindowViewModel();
                Closing += ((MainWindowViewModel)DataContext).MainWindow_Closing;

            };
        }

在关闭时正确调用CloseWindow代码:

which correctly calls the CloseWindow code when it is closed:

 private void CloseWindow(IClosable window)
        {
            if (window != null)
            {
                windowClosingCTS.Cancel();
                window.Close();
            }
        }

选择菜单项后,将在后台线程上创建第二个窗口:

With the selection of a menu item, a second window is created on a background thread:

    // Print Preview
    public static void PrintPreview(FixedDocument fixeddocument, CancellationToken ct)
    {
        // Was cancellation already requested? 
        if (ct.IsCancellationRequested)
              ct.ThrowIfCancellationRequested();

               ............................... 

            // Use my custom document viewer (the print button is removed).
            var previewWindow = new PrintPreview(fixedDocumentSequence);

            //Register the cancellation procedure with the cancellation token
            ct.Register(() => 
                   previewWindow.Close() 
            );

            previewWindow.ShowDialog();

        }
    }

在MainWindowViewModel中(在UI线程上),我输入:

In the MainWindowViewModel (on the UI thread), I put:

public CancellationTokenSource windowClosingCTS { get; set; }

其构造函数为:

    // Constructor
    public MainMenu()
    {
        readers = new List<Reader>();
        CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
        windowClosingCTS = new CancellationTokenSource();
    }

现在是我的问题.当关闭UI线程上的MainWindow时,windowClosingCTS.Cancel()会导致立即调用用ct注册的委托,即调用 previewWindow.Close(). 现在将其立即返回如果(Windows(!)= null)带有:

Now my problem. When closing the MainWindow on the UI thread, windowClosingCTS.Cancel() causes an immediate call to the delegate registered with ct, i.e. previewWindow.Close() is called. This now throws immediately back to the " If (Windows != null) with:

调用线程无法访问该对象,因为不同 线程拥有它."

"The calling thread cannot access this object because a different thread owns it."

那我在做什么错了?

推荐答案

您的问题是您的预览窗口在另一个线程上运行.触发取消时,您在该线程上而不是在运行预览的线程上执行取消令牌的注册操作.

Your problem is that your preview window runs on another thread. When you trigger cancellation, you execute the registered action of the cancellation token on that thread, not on the thread your preview is running on.

在这些情况下的黄金标准是不使用两个UI线程.这通常会引起麻烦,而您处理这些问题所需要的工作通常是不值得的.

The gold standard in these cases is to not use two UI threads. This will usually cause trouble and the work you need to handle them is usually not worth it.

如果要继续使用解决方案,或者要从后台线程触发取消操作,则必须将关闭操作编组到打开窗口的线程中:

If you want to stay with your solution or if you want to trigger cancellation from a background thread, you have to marshal your close operation to the thread your window is opened in:

Action closeAction = () => previewWindow.Close();
previewWindow.Dispatcher.Invoke(closeAction);

这篇关于如何使用CancellationTokenSource关闭另一个线程上的对话框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆