所以我正在开发一个控制台项目,它应该在某个时刻显示一个WPF窗口,在这个窗口中我可以看到图形的可视化表示,同时继续运行算法。
我到目前为止我可以创建一个Window并在另一个线程中打开它,但是一旦我调用Dispatcher.Run()
,控制台就会被阻止。到目前为止我的方法:
第1步:创建一个线程,一旦运行就为自己创建Application
和SynchronizationContext
第2步:使用sync-context调用应用程序的方法(它是提供这些方法的继承自定义类),使用传输类创建窗口的线程。 期望:它应该创建一个由独立UI线程拥有的Window实例。
第3步:使用线程的sync-context调用应用程序上的ShowWindow()
方法,该方法显示Window(确实有效),然后运行Dispatcher。因为它是使用线程的sync-context调度的,所以它不应该锁定Console线程。 确实如此。
第4步:使用Window的调度程序调用图表的更新方法。
好吧,在我的想法中,这应该非常好用,但Dispatcher以某种方式锁定了Console线程,而不是UI线程。我在这里忽略了什么吗?
自定义应用:
internal sealed class CrossThreadApplication : Application
{
private SynchronizationContext _context;
///=================================================================================================
/// <summary> Constructor. </summary>
///
/// <param name="context"> The context. </param>
///=================================================================================================
public CrossThreadApplication(SynchronizationContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
_context = context;
}
///=================================================================================================
/// <summary> Shows the window. </summary>
///
/// <exception cref="ArgumentNullException"> Thrown when one or more required arguments are
/// null. </exception>
///
/// <param name="window"> The window. </param>
///=================================================================================================
public void ShowWindow(Window window)
{
if (window == null) throw new ArgumentNullException(nameof(window));
_context.Send(state =>
{
((Window)state).Show();
System.Windows.Threading.Dispatcher.Run();
}, window);
}
///=================================================================================================
/// <summary> Creates a new object. </summary>
///
/// <param name="handle"> The creation handle for a Window. </param>
///
/// <returns> An object. </returns>
///=================================================================================================
public void Create(CreationHandle<Window> handle)
{
_context.Send(state =>
{
CreationHandle<Window> hnd = (CreationHandle<Window>) state;
hnd.Set(Activator.CreateInstance(hnd.CreationType));
}, handle);
}
}
承载UI线程并与应用程序交互的UIHost类
static UIHost()
{
HostThread = new Thread(Start);
HostThread.SetApartmentState(ApartmentState.STA);
HostThread.Name = "UI Thread";
CreationEvent = new ManualResetEvent(false);
HostThread.Start(CreationEvent);
}
private static void Start(object o)
{
ManualResetEvent ev = (ManualResetEvent) o;
SynchronizationContext context = new SynchronizationContext();
SynchronizationContext.SetSynchronizationContext(context);
_application = new CrossThreadApplication(context);
ev.Set();
_application.Run();
}
///=================================================================================================
/// <summary> Executes the user interface operation. </summary>
///
/// <param name="windowType"> The window type. </param>
/// <param name="reset"> The reset. </param>
///
/// <returns> An object. </returns>
///=================================================================================================
internal static object RunUI(Type windowType, ManualResetEvent reset)
{
CreationEvent.WaitOne();
CreationHandle<Window> handle = new CreationHandle<Window>();
_application.Create(handle);
_application.ShowWindow(handle.Get());
reset.Set();
return handle.Get();
}
问题出现在CrossThreadApplication.ShowWindow()
*.Dispatcher.Run();
。
为什么会这样?我怎样才能使这个工作?它必须以某种方式。