从其他线程和奇怪的行为中使用WPF Extended Toolkit MessageBox [英] Using WPF Extended Toolkit MessageBox from other threads and curious behavior

查看:114
本文介绍了从其他线程和奇怪的行为中使用WPF Extended Toolkit MessageBox的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在从其他线程使用WPF扩展工具包(版本2.1.0.0)MessageBox时遇到麻烦.命名空间是:Xceed.Wpf.Toolkit.MessageBox

I am having trouble using the WPF Extended Toolkit (version 2.1.0.0) MessageBox from other threads. The namespace is: Xceed.Wpf.Toolkit.MessageBox

我用工具包MessageBox替换了常规的MessageBoxs(System.Windows.MessageBox),并在从另一个线程启动一个时出现错误. System.Windows.MessageBox没有此类问题.我看到这篇文章报告了该问题,但似乎没有后续措施:

I replaced my regular MessageBoxs (System.Windows.MessageBox) with the Toolkit MessageBox and get errors when I launch one from another thread. The System.Windows.MessageBox has no such problems. I saw this posting that reports the problem, but there seems to be no follow up:

https://wpftoolkit.codeplex.com/workitem/21046

我猜有个解决方法.此处提供了一个显示问题的示例,但这是我的简单示例:

I'm guessing there is a work around. An example is presented there that shows the problem, but here is my simple example:

首先,我包装Toolkit.MessageBox.我这样做主要是因为我正在应用样式(尽管我已经对此进行了评论以表明这不是问题)

First, I wrap the Toolkit.MessageBox. I do this primarily because I'm applying style (although I've commented that out to show that's not the problem)

public class CustomMessageBox
{
    //static DummyUserControl1 _ctrl = new DummyUserControl1();

    public static MessageBoxResult Show(string msgText, Style styleArg = null)
    {
        Cursor saveCursor = Mouse.OverrideCursor;
        Mouse.OverrideCursor = null;

        //Style style = styleArg != null ? styleArg : _ctrl.FindResource("MessageBoxStyle1") as Style;
       // MessageBoxResult result = Xceed.Wpf.Toolkit.MessageBox.Show(msgText, "", MessageBoxButton.OK, style);

        MessageBoxResult result = Xceed.Wpf.Toolkit.MessageBox.Show(msgText, "", MessageBoxButton.OK);
        Mouse.OverrideCursor = saveCursor;
        return result;
    }


}

主窗口上只有两个按钮,下面是代码:

The main window just has two buttons on it, and here's the code behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }



    private void btnMainThreadMsgBox_Click(object sender, RoutedEventArgs e)
    {
        CustomMessageBox.Show("Hello on main thread");
    }

    private void btnAltThreadMsgBox_Click(object sender, RoutedEventArgs e)
    {

        Thread altThread1 = new Thread(new ThreadStart(AltThread1Proc));

        altThread1.SetApartmentState(ApartmentState.STA);
        altThread1.Priority = ThreadPriority.AboveNormal;
        altThread1.IsBackground = true;

        altThread1.Start();
    }

    public void AltThread1Proc()
    {
        MessageBox.Show("Hello on Alt Thread");
        CustomMessageBox.Show("Hello on alt thread");

    }
}

问题出现在带有CustomMessageBox.Show(...)的AltThreadProc()中.我所指的奇怪行为是这样的:如果先按thead主按钮,然后按Alt线程按钮,则会出现错误:

The problems occur in AltThreadProc() with CustomMessageBox.Show(...). The curious behavior I referred to is this: If you hit the main thead button and then the Alt thread button, you get the error:

由于无法冻结,因此无法跨线程访问Freezable'System.Windows.Media.SolidColorBrush'.

Cannot access Freezable 'System.Windows.Media.SolidColorBrush' across threads because it cannot be frozen.

但是,如果您跳过主线程按钮,而只是按下Alt线程按钮,则会出现错误: 调用线程无法访问该对象,因为其他线程拥有它.

However, if you skip the main thread button and just hit the Alt thread button, you get the error: The calling thread cannot access this object because a different thread owns it.

我很好奇"Freezable"错误的含义,以及为什么您会基于似乎是无害的事件而得到不同的错误:单击/不单击在主线程上生成消息框的按钮.

I'm curious what the "Freezable" error is all about and why you can get different errors based on what would seem to be an innocuous event: clicking/not clicking button that produces message box on main thread.

理想情况下,将System.Windows.MessageBox替换为Xceed.Wpf.Toolkit.MessageBox会很好,但是如果要编写一些额外的代码,那可能是可以接受的.文档以及我提供的有关使用WindowContainer的链接的提示,但我实际上看不到任何有关如何执行此操作的示例.我被Toolkit MessageBox吸引住了,因为它允许您使用MessageBox做一些很酷的事情(在此未显示),例如应用样式,更改OK,CANCEL按钮的文本等.

Ideally, it would be nice to just replace System.Windows.MessageBox with Xceed.Wpf.Toolkit.MessageBox, but if there is some sort of extra code to write, that might be acceptable. The documentation, and the link I provided hints at using a WindowContainer, but I can't really see any examples of how you do that. I was attracted to the Toolkit MessageBox as it allows one to do some cool stuff with MessageBox (which I don't show here) such as apply styles, change the text of the OK, CANCEL button, etc.

任何想法都将不胜感激.

Any ideas would be much appreciated.

谢谢, 戴夫

其他信息: 如果您只有一个窗口,则User1341210的建议效果很好.但是,如果您在自己的线程中有第二个窗口,那么效果就不太好.也许有人可以告诉我我在做什么错.我使用TaskScheduler的建议,但是如果使用的TaskScheduler是第二个窗口之一,则代码将引发异常.也就是说,如果我使用第一个窗口的TaskScheduler,一切正常,但是如果我使用第二个窗口的TaskScheduler,则抛出异常.这是我第二个窗口的代码:

Extra info: User1341210 suggestion works well if you just have one window. However, if you have a second window in it's own thread it doesn't work so well. Perhaps someone can tell me what I'm doing wrong. I use the suggestion of the TaskScheduler, but the code throws an exception if the TaskScheduler used is the one of the second window. That is, all works fine if I use the TaskScheduler of the first window, but throws an exception if I use the TaskScheduler of the second window. Here is the code behind for my second window:

public partial class AltThreadWindow : Window
{
    private TaskScheduler _ui;


    public AltThreadWindow()
    {
        InitializeComponent();
        _ui = TaskScheduler.FromCurrentSynchronizationContext();

    }

    // This constructor is for passing in the TaskScheduler of the mainwindow and works great
    public AltThreadWindow(TaskScheduler scheduler)
    {
        InitializeComponent();
        _ui = scheduler;
    }

    private void btnWindowsMsgBox_Click(object sender, RoutedEventArgs e)
    {
        MessageBox.Show("Standard Windows message box");
    }

    private void btnCustomMsgBox_Click(object sender, RoutedEventArgs e)
    {
        MessageBoxResult result;
        Task.Factory.StartNew(() => { result = CustomMessageBox.Show("Custom MessageBox on separate window"); }, CancellationToken.None,
            TaskCreationOptions.None,
            _ui);
    }


}

注意两个构造函数.默认值分配第二个窗口的TaskScheduler.另一个构造函数允许一个在主窗口的TaskScheduler中传递.
这是我用来从主窗口启动第二个窗口的代码.同样,我在另一个线程上启动第二个窗口,并传入主窗口的TaskScheduler.最好使用第二个窗口的TaskScheduler.

Notice the two constructors. The default one assigns the TaskScheduler of the second window. The other constructor allows one to pas in the TaskScheduler of the main Window.
Here's the code I use to launch the second window from the main window. Again, I'm launching the second window on another thread, and I pass in the TaskScheduler of the main window. It would be nice to use the TaskScheduler of the second window instead.

 _altWindowThread = new Thread(new ThreadStart(AltWinThreadProc));
        _altWindowThread.SetApartmentState(ApartmentState.STA);
        _altWindowThread.Priority = ThreadPriority.AboveNormal;
        _altWindowThread.IsBackground = true;

        _altWindowThread.Start();

和实际的threadproc:

And the actual threadproc:

[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
    public void AltWinThreadProc()
    {
        // Create our context, and install it:
        SynchronizationContext.SetSynchronizationContext(
            new DispatcherSynchronizationContext(
                Dispatcher.CurrentDispatcher));

        _altWindow = new AltThreadWindow(_ui);
        _altWindow.Show();
        System.Windows.Threading.Dispatcher.Run();

    }

注意,这里我传入了MainWindow的TaskScheduler.

Notice here I pass in the TaskScheduler of the MainWindow.

推荐答案

我们在应用程序中遇到了同样的问题(我在codeplex上创建了工作项). 错误消息非常令人困惑,我无法为您提供答案.

we had the same issue in our application (I created the work item on codeplex). The error messages are quite confusing and I cant provide you an answer to that.

但是:

我们没有使用单独的WindowContainer来解决它.而是想出了使用UI调度程序调用单独的任务/线程的方法:

We didn't used a separated WindowContainer to solve it. Instead came up with calling the separate task/thread with the UI scheduler:

Task.Factory.StartNew(
            () => { result = CustomMessageBox.Show(messageText); },
            CancellationToken.None,
            TaskCreationOptions.None,
            _ui);

在从UI上下文执行的方法中分配_ui的位置(例如,Window/Control的构造器:

Where _ui is assigned in a method that is executed from UI context (e.g. Constructor of your Window/Control:

_ui = TaskScheduler.FromCurrentSynchronizationContext();

希望这有助于解决问题的用Xceed.Wpf.Toolkit.MessageBox替换System.Windows.MessageBox".

Hope this helps for solving the "replace System.Windows.MessageBox with Xceed.Wpf.Toolkit.MessageBox" part of your question.

如果希望消息框显示在另一个窗口上,则必须将消息框的所有者"属性设置为另一个窗口.

If you want that the messagebox shows up on another Window you have to set the "Owner" property of the message box to the other window.

最诚挚的问候.

这篇关于从其他线程和奇怪的行为中使用WPF Extended Toolkit MessageBox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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