Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#WPF.Net内核无法从其他线程关闭窗口_C#_Wpf - Fatal编程技术网

C#WPF.Net内核无法从其他线程关闭窗口

C#WPF.Net内核无法从其他线程关闭窗口,c#,wpf,C#,Wpf,目前我正在.net core上开发WPF。 我的应用程序必须启动Cef core才能运行UI(而不是使用WPF表单)。 在此之前,我想显示一个简单的WPF窗口,上面写着“加载…” 所以在应用程序启动时,我必须像这样启动一个线程 Thread thread = new Thread(() => { try { DisplayLoader = true;

目前我正在.net core上开发WPF。 我的应用程序必须启动Cef core才能运行UI(而不是使用WPF表单)。 在此之前,我想显示一个简单的WPF窗口,上面写着“加载…” 所以在应用程序启动时,我必须像这样启动一个线程

        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的缓慢,它总是在加载开始后运行)