C#WPF.Net内核无法从其他线程关闭窗口
目前我正在.net core上开发WPF。 我的应用程序必须启动Cef core才能运行UI(而不是使用WPF表单)。 在此之前,我想显示一个简单的WPF窗口,上面写着“加载…” 所以在应用程序启动时,我必须像这样启动一个线程C#WPF.Net内核无法从其他线程关闭窗口,c#,wpf,C#,Wpf,目前我正在.net core上开发WPF。 我的应用程序必须启动Cef core才能运行UI(而不是使用WPF表单)。 在此之前,我想显示一个简单的WPF窗口,上面写着“加载…” 所以在应用程序启动时,我必须像这样启动一个线程 Thread thread = new Thread(() => { try { DisplayLoader = true;
Thread thread = new Thread(() =>
{
try
{
DisplayLoader = true;
var f = new Loading();
f.Loaded += (a, b) =>
{
Task.Run(() =>
{
while (DisplayLoader)
Thread.Sleep(250);
f.Dispatcher.BeginInvoke(() =>
{
f.Close();
});
f.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate ()
{
f.Close();
}));
});
};
f.Show();
Dispatcher.Run();
}
catch
{
Loader.Close();
}
});
问题是,当DisplayLoader变为false时,我看到Dispatcher也调用了Close函数,但是什么也没有发生。关于stackOverflow,我已经了解了很多答案,但没有一个有效
线程开始下面是这个函数,它将调用Cef并显示一个Cef窗口
thread.Start();
var assembly = Assembly.GetExecutingAssembly();
CefApp
.Run(assembly)
加载CefApp时,DisplayLoader将设置为false
protected override void OnLoadEnd(CefBrowser browser, CefFrame frame, int httpStatusCode)
{
base.OnLoadEnd(browser, frame, httpStatusCode);
if (frame.IsValid)
{
if (App.DisplayLoader)
{
App.DisplayLoader = false;
}
}
}
编辑:
这个问题实际上来自CefAppBuilder,它嵌入了CEFCUE的C++代码,然后可能会导致一些问题。只要不要修改C invoke函数中的任何C#变量就可以了。执行
窗口的线程必须是UI线程,必须是STA线程
必须使用线程将线程标记为STA。SetApartmentState
:
App.xaml
private void Run(object sender, StartupEventArgs e)
{
Thread uiThread = new Thread(DoWork);
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.IsBackground = true;
uiThread.Start();
}
private TaskCompletionSource TaskCompletionSource { get; set; }
private async void Run(object sender, StartupEventArgs e)
{
Window splashScreen = new SplashScreenWindow();
splashScreen.Show();
await InitializeCefAppAsync();
splashScreen.Close();
}
private async Task InitializeCefAppAsync()
{
this.TaskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.LongRunning);
var assembly = Assembly.GetExecutingAssembly();
CefApp.Loaded += OnCefAppLoaded;
// Consider to implement an awaitable CefApp.InitializeAsync method
// instead of calling Run directly. This way you can remove the TaskCompletionSource pattern
CefApp.Run(assembly);
return this.TaskCompletionSource.Task;
}
private void OnLoaded(object sender, EventArgs e)
{
this.TaskCompletionSource.SetResult(true);
}
但我推荐的方法是异步执行初始化。这避免了创建额外UI线程的开销,并且在代码行和可读性方面更加紧凑:
App.xaml
private void Run(object sender, StartupEventArgs e)
{
Thread uiThread = new Thread(DoWork);
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.IsBackground = true;
uiThread.Start();
}
private TaskCompletionSource TaskCompletionSource { get; set; }
private async void Run(object sender, StartupEventArgs e)
{
Window splashScreen = new SplashScreenWindow();
splashScreen.Show();
await InitializeCefAppAsync();
splashScreen.Close();
}
private async Task InitializeCefAppAsync()
{
this.TaskCompletionSource = new TaskCompletionSource<bool>(TaskCreationOptions.LongRunning);
var assembly = Assembly.GetExecutingAssembly();
CefApp.Loaded += OnCefAppLoaded;
// Consider to implement an awaitable CefApp.InitializeAsync method
// instead of calling Run directly. This way you can remove the TaskCompletionSource pattern
CefApp.Run(assembly);
return this.TaskCompletionSource.Task;
}
private void OnLoaded(object sender, EventArgs e)
{
this.TaskCompletionSource.SetResult(true);
}
private TaskCompletionSource TaskCompletionSource{get;set;}
专用异步无效运行(对象发送器、StartupEventArgs e)
{
Window splashScreen=新的splashScreen窗口();
splashScreen.Show();
等待初始化eceFappAsync();
splashScreen.Close();
}
专用异步任务初始化eceFappaSync()
{
this.TaskCompletionSource=新的TaskCompletionSource(TaskCreationOptions.LongRunning);
var assembly=assembly.getExecutionGassembly();
CefApp.load+=oncefappload;
//考虑实现一个可等待的CEFAP.IMALIZIASEYNC方法
//而不是直接调用Run。这样可以删除TaskCompletionSource模式
CefApp.Run(组装);
返回此.TaskCompletionSource.Task;
}
已加载私有void(对象发送方、事件参数e)
{
this.TaskCompletionSource.SetResult(true);
}
我真的相信,使用异步任务会更好。您是否处理过基于任务的异步?如何启动线程以及如何设置DisplayLoader
?根据您发布的代码,您的问题是不可复制的。幸运的是,我的应用程序实际上是开源的:如果您想重新生成问题,只需克隆代码即可。TranslatorApp.cs是DisplayLoader变为false的地方(无论由于Cef的缓慢,它总是在加载开始后运行)