WPF中登录窗口的跳转处理

标签: WPF, 窗体跳转

博客分类: 示例

在WPF应用设计中,常常需要在主窗口之前设置一个前置登录窗口,为此整理了一下可行的方案。
示例源码:Jess.Sample.LoginWindow

方案一:添加Program.cs,模仿Winform初始代码

不做整理,个人不推荐,既然用了WPF,就尽量不把Winform的东西引入进来。

方案二:在主窗体MainWindow的构造函数中处理登录操作

此方案相对局限,若单纯只有个登录操作,可以使用此法 —— 可依据需要调整InitializeComponent();的先后顺序。

``` csharp

public partial class MainWindow : Window
{
    public MainWindow()
    {
        WindowLogin win = new WindowLogin();
        if (!(win.ShowDialog() ?? false))
        {
            App.Current.Shutdown();
            return;
        }

        InitializeComponent();
    }
}

```

方案三:重写ApplicationOnStartup方法

注意事项:

  • OnStartup中关闭窗体,会导致进入不了主窗体,因此需要手动控制ShutdownMode【默认值:ShutdownMode.OnLastWindowClose
  • 不得在App构造函数中,进行UI显示操作,因为这会导致一些锁的释放,引发OnStartup提前触发【OnStartup是在Application的构造函数中异步调用的】

官方Window.cs源码的窗体关闭流程中有一段以下代码:

``` csharp

if (((App.Windows.Count == 0) && (App.ShutdownMode == ShutdownMode.OnLastWindowClose))
    || ((App.MainWindow == this) && (App.ShutdownMode == ShutdownMode.OnMainWindowClose)))
{
    App.CriticalShutdown(0);
}

```

由此可见,默认情况下,在OnStartup中调用关闭窗体,会直接导致Shutdown的调用。


鉴于此,主要有以下修改方式【只要避免内部调用Shutdown即可】:

保证登录窗体关闭时,不会满足Shutdown调用条件

  • 全局自己手动控制Shutdown:使用ShutdownMode.OnExplicitShutdown,在需要退出应用时,调用App.Current.Shutdown();
  • 在登录窗体前后,切换ShutdownMode:登录前改为ShutdownMode.OnExplicitShutdown,窗体关闭后,恢复为ShutdownMode.OnLastWindowClose
  • 控制只有主窗体关闭时,才退出程序:指定MainWindow,手动启动MainWindow,不在依赖StartupUri

全局手动控制Shutdown

  • 设置ShutdownMode为OnExplicitShutdown;
  • 在需要退出应用的窗体中,重写OnClosed方法,手动调用App.Current.Shutdown()

``` csharp

public partial class App : Application
{
    public App()
    {
        this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        WindowLogin win = new WindowLogin();
        if (!(win.ShowDialog() ?? false))
        {
            App.Current.Shutdown();
            return;
        }

        base.OnStartup(e);
    }    
}

```


``` csharp

public partial class MainWindow : Window
{
    public MainWindow()
    {       
        InitializeComponent();
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        App.Current.Shutdown();
    }
}

```

窗体显示前后切换ShutdownMode

  • 直接在登录窗体前后设置ShutdownMode即可:

``` csharp

public partial class App : Application
{     
    protected override void OnStartup(StartupEventArgs e)
    {          
        this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
        WindowLogin win = new WindowLogin();
        if (!(win.ShowDialog() ?? false))
        {
            this.Shutdown();
            return;
        }
        this.ShutdownMode = ShutdownMode.OnLastWindowClose;

        base.OnStartup(e);
    }
}

```

指定App主窗体MainWindow

  • 删除App.xaml文件中是StartupUri属性设置。
  • 设置主窗体与程序关闭模式。

``` csharp

public partial class App : Application
{
    public App()
    {
        this.MainWindow = new MainWindow();
        this.ShutdownMode = ShutdownMode.OnMainWindowClose;
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        WindowLogin win = new WindowLogin();
        if (!(win.ShowDialog() ?? false))
        {
            this.Shutdown();
            return;
        }

        base.OnStartup(e);

        this.MainWindow.Show();
    }
}

```

补充说明

在上面前两种的OnStartup的处理中,有个隐藏的问题,他们仍然会去创建MainWindow。如果想避免初始化MainWindow,有以下两种方式:

  • 在调用Shutdown之后调用Environment.Exit(0);,强制退出。
  • 重写ApplicationOnNavigating方法,设置事件参数的Cancel属性。

``` csharp

protected override void OnNavigating(NavigatingCancelEventArgs e)
{            
    e.Cancel = true;
    base.OnNavigating(e);
}

```


掘:奇葩史