Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.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应用程序中找到使用自己的UI线程运行的窗口_C#_Wpf_Multithreading_Xaml_Splash Screen - Fatal编程技术网

C# 如何在WPF应用程序中找到使用自己的UI线程运行的窗口

C# 如何在WPF应用程序中找到使用自己的UI线程运行的窗口,c#,wpf,multithreading,xaml,splash-screen,C#,Wpf,Multithreading,Xaml,Splash Screen,我有一个应用程序,它使用一个WPF窗口和一个自己的调度程序作为启动启动窗口。此启动屏幕将向用户显示信息,并且是最顶部的窗口。我不想将其作为应用程序.MainWindow,但必须在创建主窗口之前显示它 在启动期间或应用程序运行期间的任何时候,后台工作人员都可以检测到致命错误,并需要在应用程序终止之前显示消息框。此消息框必须位于任何打开的窗口前面 当此错误发生在启动窗口可见时,消息框位于启动屏幕后面。使用闪屏作为所有者或隐藏闪屏可以解决这个问题,但我找不到闪屏。它不在应用程序.Current.Win

我有一个应用程序,它使用一个WPF
窗口
和一个自己的
调度程序
作为启动启动窗口。此启动屏幕将向用户显示信息,并且是最顶部的窗口。我不想将其作为
应用程序.MainWindow,但必须在创建主窗口之前显示它

在启动期间或应用程序运行期间的任何时候,后台工作人员都可以检测到致命错误,并需要在应用程序终止之前显示消息框。此消息框必须位于任何打开的窗口前面

当此错误发生在启动窗口可见时,消息框位于启动屏幕后面。使用闪屏作为所有者或隐藏闪屏可以解决这个问题,但我找不到闪屏。它不在
应用程序.Current.Windows
集合中,我猜是因为它有一个不同的
调度程序

有人知道如何在不将窗口传递给后台工作人员的情况下获取窗口吗

下面的代码再现了该问题。将所有需要的引用传递给工作者很容易,但这不是我在实际应用程序中想要做的

App.xaml

  <Application
     x:Class="Sandbox.App"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
  </Application>

App.xaml.cs

     using System;
     using System.Linq;
     using System.Threading;
     using System.Windows;
     using System.Windows.Controls;
     using System.Windows.Media;
     using System.Windows.Threading;

     namespace Sandbox
     {
        public partial class App : Application
        {
           protected override void OnStartup(StartupEventArgs e)
           {
              base.OnStartup(e);

              var closeSplashEvent = App.LanuchSplashScreen();
              App.StartThreadInDifferentAssemblyWithoutRefToThis();

              // ...

              this.MainWindow = new Window { Title="MainWindow",  Width = 800, Height = 600, WindowStartupLocation = WindowStartupLocation.CenterScreen };
              this.MainWindow.Show();

              //  ...

              App.CloseSplashScreen(closeSplashEvent, TimeSpan.FromSeconds(5));
           }

           private static void StartThreadInDifferentAssemblyWithoutRefToThis()
           {
              ThreadPool.QueueUserWorkItem(_ =>
              {
                 // ...
                 Thread.Sleep(1000);

                 Application.Current.Dispatcher.Invoke((ThreadStart) delegate
                 {
                    // how to find the splash screen ???
                    var owner = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.Title == "SplashScreen") ?? Application.Current.MainWindow;
                    MessageBox.Show(owner, "Should be in front of splash screen!", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                 });
              });
           }

           private static ManualResetEvent LanuchSplashScreen()
           {
              Dispatcher splashDispatcher = null;
              var startupEvent = new ManualResetEvent(false);
              var splashThread = new Thread(() =>
              {
                 splashDispatcher = Dispatcher.CurrentDispatcher;
                 startupEvent.Set();
                 Dispatcher.Run();
              });
              splashThread.SetApartmentState(ApartmentState.STA);
              splashThread.Start();
              startupEvent.WaitOne();

              Window aniSplashWindow = null;
              splashDispatcher.Invoke((ThreadStart)delegate
              {
                 aniSplashWindow = new Window
                 {
                    Width = 320, Height = 240, AllowsTransparency = true, Background = Brushes.Transparent, Topmost = true, WindowStyle = WindowStyle.None, WindowStartupLocation = WindowStartupLocation.CenterScreen,
                    Title="SplashScreen", Content = new Border { BorderBrush = Brushes.Black, BorderThickness = new Thickness(1), Background = Brushes.White, CornerRadius = new CornerRadius(5) }
                 };
                 aniSplashWindow.Show();
              });

              var closeSplashEvent = new ManualResetEvent(false);
              ThreadPool.QueueUserWorkItem(_ =>
              {
                 closeSplashEvent.WaitOne();
                 splashDispatcher.Invoke((ThreadStart) delegate
                 {
                    aniSplashWindow.Close();
                    splashDispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
                 });
              });

              return closeSplashEvent;
           }

           private static void CloseSplashScreen(EventWaitHandle closeSplashEvent, TimeSpan closeSplashTimeout)
           {
              ThreadPool.QueueUserWorkItem(_ =>
              {
                 Thread.Sleep(closeSplashTimeout);
                 closeSplashEvent.Set();
              });
           }
        }
     }
使用系统;
使用System.Linq;
使用系统线程;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Media;
使用System.Windows.Threading;
名称空间沙盒
{
公共部分类应用程序:应用程序
{
启动时受保护的覆盖无效(StartupEventArgs e)
{
基础。启动时(e);
var closeSplashEvent=App.LanuchSplashScreen();
App.startThread无差异sembly而不引用此();
// ...
this.MainWindow=新窗口{Title=“MainWindow”,宽度=800,高度=600,WindowsStartUpLocation=WindowsStartUpLocation.CenterScreen};
this.MainWindow.Show();
//  ...
应用程序CloseSplashScreen(closeSplashEvent,TimeSpan.FromSeconds(5));
}
private static void startThread无差异sembly未引用此()
{
ThreadPool.QueueUserWorkItem(=>
{
// ...
睡眠(1000);
Application.Current.Dispatcher.Invoke((ThreadStart)委托
{
//如何找到启动屏幕???
var owner=Application.Current.Windows.OfType().FirstOrDefault(w=>w.Title==“SplashScreen”)??Application.Current.MainWindow;
MessageBox.Show(所有者,“应该在启动屏幕前面!”,“Error”,MessageBoxButton.OK,MessageBoxImage.Error);
});
});
}
专用静态手动重置事件LANUCHSPLASH屏幕()
{
Dispatcher=null;
var startupEvent=新手动重置事件(错误);
var splashtread=新线程(()=>
{
splashDispatcher=Dispatcher.CurrentDispatcher;
startupEvent.Set();
Dispatcher.Run();
});
SetApartmentState(ApartmentState.STA);
splashtread.Start();
startupEvent.WaitOne();
窗口aniSplashWindow=null;
splashDispatcher.Invoke((ThreadStart)委托
{
aniSplashWindow=新窗口
{
宽度=320,高度=240,AllowTransparency=真,背景=画笔。透明,最顶端=真,WindowsStyle=WindowsStyle。无,WindowsStartUpLocation=WindowsStartUpLocation.CenterScreen,
Title=“SplashScreen”,内容=新边框{BorderBrush=画笔。黑色,BorderThickness=新厚度(1),背景=画笔。白色,CornerRadius=新CornerRadius(5)}
};
aniSplashWindow.Show();
});
var closeSplashEvent=新手动重置事件(假);
ThreadPool.QueueUserWorkItem(=>
{
closeSplashEvent.WaitOne();
splashDispatcher.Invoke((ThreadStart)委托
{
aniSplashWindow.Close();
splashDispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);
});
});
返回事件;
}
私有静态无效CloseSplashScreen(EventWaitHandle closeSplashEvent,TimeSpan closeSplashTimeout)
{
ThreadPool.QueueUserWorkItem(=>
{
线程睡眠(关闭超时);
closeSplashEvent.Set();
});
}
}
}

我假设启动屏幕只存在一次。那为什么不让它成为一个单身汉呢


最简单的解决方案是通过全局(静态)属性公开它。或者,(如果您创建了一些SplashScreen类),您可以通过MEF或其他合成框架导出和导入它。

我认为将它们传递给worker比将splash设置为静态或单例更好。静态/单例需要工作人员知道启动屏幕/应用程序,这是我不喜欢的依赖项。MEF或IoC也将允许解决该问题。关键是,我真的不相信当WPF应用程序有自己的UI线程时,它不可能在WPF应用程序中找到当前的活动窗口。。。