C# UI事件如何到达WPF调度程序?
我正在开发的当前应用程序是另一个商业应用程序的插件。在我的插件中,我可以使用C# UI事件如何到达WPF调度程序?,c#,.net,wpf,multithreading,dispatcher,C#,.net,Wpf,Multithreading,Dispatcher,我正在开发的当前应用程序是另一个商业应用程序的插件。在我的插件中,我可以使用Execute()方法创建一个自定义Command类,当用户决定运行自定义命令时,父应用程序将调用该方法 此API提供的对象不是线程安全的,因此我只能从应用程序启动的Execute()线程访问它们。但是,我尝试执行的一些任务需要一段时间才能完成,我希望向用户显示一个进度窗口 我可以通过启动另一个线程来显示窗口,从而创建一个功能正常、响应迅速的进度窗口。这要求我手动启动该线程的WPF调度程序,如中所述 我可以在进程进行时拖
Execute()
方法创建一个自定义Command
类,当用户决定运行自定义命令时,父应用程序将调用该方法
此API提供的对象不是线程安全的,因此我只能从应用程序启动的Execute()
线程访问它们。但是,我尝试执行的一些任务需要一段时间才能完成,我希望向用户显示一个进度窗口
我可以通过启动另一个线程来显示窗口,从而创建一个功能正常、响应迅速的进度窗口。这要求我手动启动该线程的WPF调度程序,如中所述
我可以在进程进行时拖动此窗口。但是,如果在任务运行时与窗口内的任何内容进行交互,例如单击窗口,它将冻结
我发现,如果我在实际的命令.Execute()
线程中实例化并显示一个WPF窗口,那么该窗口在命令退出后将保持可见和响应。因此,本机程序似乎有一个WPF调度程序在命令线程上运行。我通过从Execute()
连接到Dispatcher.CurrentDispatcher.Hooks.OperationPosted
验证了这一点。当我与本机应用程序交互时,Execute()
方法退出后,它继续发送消息
因此,我认为正在发生的是,当我单击窗口时,本机应用程序的调度程序正在处理这个单击。这个调度程序不知道我的窗口,甚至无法访问它,因为它是在另一个线程中创建的。此外,该调度器无论如何也无法执行任何操作,因为它的关联线程在执行耗时任务的Execute()
方法中很忙
那么,有人能解释一下,点击WPF对象或以其他方式与WPF对象交互最终是如何将其添加到相关的调度程序队列中的吗?是否有某种方法可以重定向此消息,以便当用户单击我的进度窗口时,事件get被发送到正确的调度程序
更新
下面是一些示例代码,我一直在使用这些代码试图弄清楚到底发生了什么
当用户调用我的自定义命令时,本机应用程序将调用Command.Execute()
。ProgressWindow只是一个带有ProgressBar和按钮的简单窗口。按钮只是有一个空的onClick处理程序,我在其中设置了一个断点
WorkerClass.DoWork()
在另一个线程上打开一个ProgressWindow
。然后,它通过在for循环中循环,在每次迭代时更新窗口中的进度条来做一些虚假的工作
public class Command
{
public void Execute()
{
Thread.CurrentThread.Name = "Command Thread";
WorkerClass.DoWork();
}
}
public class WorkerClass
{
//Creates the new progress window thread
public static void DoWork()
{
Thread newprogWindowThread = new Thread(new ThreadStart(ShowProgressWindow));
newprogWindowThread.Name = "Progress Window Thread";
newprogWindowThread.SetApartmentState(ApartmentState.STA);
newprogWindowThread.IsBackground = true;
//Starts New Progress Window Thread
using (_progressWindowWaitHandle = new AutoResetEvent(false))
{
//Starts the progress window thread
newprogWindowThread.Start();
//Wait for progress window thread to notify that the window is up
_progressWindowWaitHandle.WaitOne();
}
//Do some fake work
for (int i = 1; i <= 100; i++)
{
//Do Some work
Thread.Sleep(100);
//Updates the progress window
//This method queues the update to the
//actual Dispatcher of the window.
progWindow.UpdateStatus("Item " + i.ToString(), i, 100);
}
MessageBox.Show("Work Finished");
}
private static ProgressWindow progWindow;
internal static EventWaitHandle _progressWindowWaitHandle;
private static void ShowProgressWindow()
{
//Creates and shows progress window
progWindow = new ProgressWindow("Running Task...");
progWindow.Show();
//Subscribes to window closed event
progWindow.Closed += progWindow_Closed;
//Notifies other thread the progress window is open when the dispatcher starts up
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(new Func<bool>(_progressWindowWaitHandle.Set));
//Starts the WPF dispatcher
System.Windows.Threading.Dispatcher.Run();
}
private static void progWindow_Closed(object sender, EventArgs e)
{
//When window is closed shuts down WPF dispatcher
//this will release thread from Dispatcher.Run() above
//and exit the ShowProgressWindow() method and exit the secondary thread
ProgressWindow window = (ProgressWindow)sender;
window.Dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
}
}
公共类命令
{
public void Execute()
{
Thread.CurrentThread.Name=“命令线程”;
WorkerClass.DoWork();
}
}
公营工人班
{
//创建新的进度窗口线程
公共静态无效工作()
{
线程newprogWindowThread=新线程(新线程开始(ShowProgressWindow));
newprogWindowThread.Name=“进度窗口线程”;
newprogWindowThread.SetApartmentState(ApartmentState.STA);
newprogWindowThread.IsBackground=true;
//启动新的进度窗口线程
使用(_progressWindowWaitHandle=new AutoResetEvent(false))
{
//启动进度窗口线程
newprogWindowThread.Start();
//等待进度窗口线程通知窗口已打开
_progressWindowWaitHandle.WaitOne();
}
//做些假工作
对于(int i=1;识别号)。所有WPF UI元素都派生自DispatcherObject
,并引用“它们的”Dispatcher
。它们不能对无关的Dispatcher
s进行操作,也不能相互关联,甚至不能被无关的Dispatcher操作。我仍然不清楚您描述的场景。另外,请记住Dispatcher。如果当前线程不存在任何Dispatcher,则CurrentDispatcher
将创建一个新的Dispatcher,从而调用Dispatcher.CurrentDispatcher
从后台线程将不会返回对预期Dispatcher实例的引用。是的,我知道我从matters调用CurrentDispatcher的线程。我从Execute()调用它方法。不是我的第二个线程。谢谢!您能澄清您的问题或添加示例代码吗?@HighCore请参阅我的Updatery,不要创建创建窗口背景的线程(newprogWindowThread.IsBackground=true;),据我所知,消息队列仅为前台线程创建