我在使用其他线程的WPF扩展工具包(版本2.1.0.0)MessageBox时遇到问题。命名空间是:Xceed.Wpf.Toolkit.MessageBox
我用Toolkit MessageBox替换了我的常规MessageBoxs(System.Windows.MessageBox),并在从另一个线程启动时遇到错误。 System.Windows.MessageBox没有这样的问题。我看到这个帖子报告了问题,但似乎没有后续行动:
https://wpftoolkit.codeplex.com/workitem/21046
我猜测有一个解决方法。这里展示了一个显示问题的例子,但这是我的简单示例:
首先,我包装Toolkit.MessageBox。我之所以这样做主要是因为我正在应用风格(虽然我已经评论说明了这不是问题)
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;
}
}
主窗口上面只有两个按钮,后面是代码:
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线程按钮,你会收到错误:
无法访问Freezable' System.Windows.Media.SolidColorBrush'跨线程,因为它不能被冻结。
但是,如果您跳过主线程按钮并且只需点击Alt线程按钮,则会收到错误: 调用线程无法访问此对象,因为另一个线程拥有它。
我很好奇" Freezable"错误就是为什么你可以根据看似无害的事件得到不同的错误:点击/不点击在主线程上产生消息框的按钮。
理想情况下,将System.Windows.MessageBox替换为Xceed.Wpf.Toolkit.MessageBox会很好,但是如果要编写某种额外的代码,这可能是可以接受的。文档和我提供的链接提示使用WindowContainer,但我真的看不到你如何做到这一点的任何例子。我被Toolkit MessageBox所吸引,因为它允许用MessageBox做一些很酷的东西(我不会在这里展示),例如应用样式,更改OK,CANCEL按钮的文本等。
非常感谢任何想法。
谢谢, 戴夫
额外信息: 如果您只有一个窗口,User1341210建议很有效。但是,如果你在自己的主题中有第二个窗口,它就不能很好地工作。也许有人可以告诉我我做错了什么。我使用TaskScheduler的建议,但如果使用的TaskScheduler是第二个窗口之一,则代码会抛出异常。也就是说,如果我使用第一个窗口的TaskScheduler,一切正常,但如果我使用第二个窗口的TaskScheduler则抛出异常。这是我的第二个窗口背后的代码:
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。
_altWindowThread = new Thread(new ThreadStart(AltWinThreadProc));
_altWindowThread.SetApartmentState(ApartmentState.STA);
_altWindowThread.Priority = ThreadPriority.AboveNormal;
_altWindowThread.IsBackground = true;
_altWindowThread.Start();
实际的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。
答案 0 :(得分:2)
我们在应用程序中遇到了同样的问题(我在codeplex上创建了工作项)。 错误消息非常混乱,我无法为您提供答案。
可是:
我们没有使用单独的WindowContainer来解决它。而是通过UI调度程序调用单独的任务/线程:
Task.Factory.StartNew(
() => { result = CustomMessageBox.Show(messageText); },
CancellationToken.None,
TaskCreationOptions.None,
_ui);
在从UI上下文执行的方法中分配_ui(例如,窗口/控件的构造函数:
_ui = TaskScheduler.FromCurrentSynchronizationContext();
希望这有助于解决"用Xceed.Wpf.Toolkit.MessageBox替换System.Windows.MessageBox"你的问题的一部分。
如果您希望消息框显示在另一个窗口上,您必须设置"所有者"消息框的属性到另一个窗口。
最好的问候。