更新:我想,我需要了解在WPF中启动应用程序之前显示对话框的“正确”,“支持”方式是什么。 < / p>
以下是代码:
public partial class App : Application
{
[STAThread]
public static void Main()
{
var app = new App();
app.InitializeComponent();
new DialogWindow().ShowDialog();
app.Run( new MainWindow() );
}
}
DialogWindow
按预期显示
但关闭后,应用程序立即退出。 MainWindow
根本没有出现!
我做了一些调试并将问题追溯到:
app
的MainWindow,因为此刻没有MainWindow。ShutdownCallback
。app.Run
后,队列中的第一件事就是ShutdownCallback
,这自然会导致应用立即关闭。鉴于此分析,有一个明显的解决方法:在MainWindow
之后立即创建App
,从而使其成为app
的MainWindow,这会阻止DialogWindow
导致应用程序闭合。
然而,这就是困扰我的。
首先,这看起来像是一个肮脏的黑客。我的意思是,没有明确的理由按此顺序创建窗口,我只通过一些调试找到了这个。这不是受支持的方式。
其次,这显然是一个错误。我的意思是,如果显式不支持在关机后创建第二个窗口,它应该抛出一些InvalidOperationException
,对吗?
第三,这不仅是一个错误,而且看起来像一个非常幼稚的错误,就像多线程初学者会创建的那样。
这一切让我相信,也许我在这里找不到根本的东西?也许我根本没有意义?也许这一切都应该以某种不同的方式完成?
以下是一些背景知识:
应用程序必须在启动时进行一些引导。检查这一点,设置异常处理程序,记录 - 你知道,通常的东西。在此过程中,可能需要向用户请求帮助 - 这是对话框的用途。
我绝对不想把所有这些都放在MainWindow.IsVisibleChanged
上执行的某种状态机上。我想保持它简单,简洁和直接 - 引导代码应该是这样的方式,这样就可以很容易地用肉眼发现错误。
答案 0 :(得分:31)
默认情况下,WPF应用程序的ShutdownMode是OnLastWindowClose。在您的代码中,您将显示一个窗口,然后将其关闭。因此,最后一个窗口关闭,应用程序关闭。然后在关闭时,显示另一个窗口。由于应用程序正在关闭,窗口立即关闭。
所以一切都按照您的设计和编程工作。
但是,你想要做一些不同的事情:首先显示为唯一窗口的窗口应该是一个“特殊窗口”,关闭后你要继续执行,显示你的“主窗口”,然后退出应用程序(或与应用程序关联的所有窗口)关闭后。
最简单的方法:首先将关闭模式设置为OnExplicitShutdown,然后在显示主窗口后将其设置为OnLastWindowClose或OnMainWindowClose。在代码中:
public static void Main()
{
var app = new App();
app.InitializeComponent();
app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
new DialogWindow().ShowDialog();
var mainWindow = new MainWindow();
app.MainWindow = mainWindow;
app.Run(mainWindow);
// When the window has loaded, it should then set the app.ShutdownMode to what you actually want.
}
编辑: 我不确定你到底在做什么。您提供的代码将无法编译,因为在正确使用WPF应用程序类(使用App.xaml构建操作作为ApplicationDefinition)时,已经定义了Main方法。如果您只有一个派生自Application的类,则没有InitializeComponent()方法。让代码编译的唯一方法是手动将构建操作更改为Page。但是,在这种情况下,Application.Current == app。
所以会发生以下情况:
app.Run(new DialogWindow()); app.Run(new MainWindow());
,则在创建MainWindow时会出现异常,因为在这种情况下,调度程序循环正常运行。因此,它实际上可以自行关闭,因此在创建MainWindow时,它会抛出异常,因为调度程序循环已经关闭。 所以再一次,没有错误。
因此解决此问题的一种方法是更改为OnExplicitShutdown。然后在步骤4中,没有达到关闭的理由。更好(正如更像普通的WPF应用程序)将具有适当的ApplicationDefinition。从App.xaml中删除StartupUri,而不是处理Startup事件:
private void OnStartup(object sender, StartupEventArgs e)
{
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
new DialogWindow().ShowDialog();
var mainWindow = new MainWindow();
this.ShutdownMode = ShutdownMode.OnLastWindowClose; // or OnMainWindowClose
mainWindow.Show();
}
由于我们在关闭对话框窗口时有OnExplicitShudown,因此应用程序没有理由在此时开始关闭。然后,在创建MainWindow之后,我们再次将窗口作为主窗口和(一个)应用程序窗口。那么我们就可以切换到我们想要的关机模式并显示主窗口。
答案 1 :(得分:2)
看起来确实有些错误。
我通常不会在Main()
中添加任何内容,我会调用no-arg app.Run()
并在OnStartup
方法中调用我需要的所有内容,但这不会改变你看到的行为。
每当我需要在我的主应用程序窗口准备好显示之前显示某些内容时,例如收集输入或显示启动画面,我会在第二个帖子上执行此操作。
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// show splash
var thread = new Thread(() =>
{
Dispatcher.CurrentDispatcher.BeginInvoke
((Action)(() => new MySplashWindow().Show()));
Dispatcher.Run();
}
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
// run configuration steps
// instantiate and show main window
}
显然,如果你在第二个帖子上调用ShowDialog()
,你需要确保在显示主窗口之前得到答案。它的优势在于,您可以在等待特定部分的用户输入时运行其他引导任务;这实际上取决于你的各种任务的顺序。
也许这对你的情况有帮助;也许不是 - 只是一个想法。
答案 2 :(得分:1)
非常翔实的帖子归功于所有贡献。我使用安慰剂窗口将其设置为主窗口但未显示。我还将关闭模式设置为OnLastWindow在打开和关闭所有设置对话框之后,我用实际主窗口替换了安慰剂窗口并调用了App.Run()。这可能不是最佳实践,但它有效,而且工作速度很快。
Application app = new App();
MainWindow y = new MainWindow();
app.MainWindow = y;
y.WindowStartupLocation = WindowStartupLocation.CenterScreen;
app.ShutdownMode = ShutdownMode.OnLastWindowClose;
//do lots of setup work to include authentication
MainWindow x = new MainWindow(containerdata)
app.MainWindow = x;
App.Run()
答案 3 :(得分:0)
如果将Application.ShutdownMode设置为OnExplicitShutdown
,您是否可以避免将ShutdownCallback置于调度程序队列中并继续执行您想要的操作而不考虑Windows?我没有对此进行测试,但它似乎是一个潜在的解决方案,并且使用Application.MainWindow属性,可以动态更改。
答案 4 :(得分:-1)
我有类似的问题。我花了很多时间而无法解决它。我没时间了。
我不知道这是一个正确的解决方案,但我只是隐藏了登录对话框而不是关闭它。它仍在工作