C# WPF. Net Ядро не может закрыть окно из другого потока - PullRequest
0 голосов
/ 22 апреля 2020

В настоящее время я работаю над WPF на ядре. net. Мое приложение должно запустить ядро ​​Cef для запуска пользовательского интерфейса (вместо использования формы 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 становясь ложным, я видел, что 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, он встроил код C ++ из CefGlue, а затем может вызвать некоторые проблемы с C# функция. Только не изменяйте никакую переменную C# в функции вызова C, тогда все в порядке.

1 Ответ

1 голос
/ 22 апреля 2020

Поток, который выполняет Window, должен быть потоком пользовательского интерфейса, который должен быть потоком STA.

Вы должны пометить поток как STA, используя Thread.SetApartmentState:

App.xaml

private void Run(object sender, StartupEventArgs e)
{
  Thread uiThread = new Thread(DoWork);
  uiThread.SetApartmentState(ApartmentState.STA);
  uiThread.IsBackground = true;
  uiThread.Start();
}

Но мой рекомендуемый подход заключается в асинхронном выполнении инициализации. Это позволяет избежать затрат на создание дополнительных потоков пользовательского интерфейса, а также более компактно с точки зрения строк кода и читабельности:

App.xaml

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...