WPF实现加载初始页面后跳转到主界面并销毁初始页面资源
在 WPF 中实现加载初始页面后跳转到主界面并销毁初始页面资源,可以通过以下步骤实现。这里使用一个启动窗口(SplashScreen)作为初始页面,加载完成后切换到主窗口(MainWindow):
完整实现方案
1. 创建启动窗口 (SplashScreen.xaml)
<!-- SplashScreen.xaml -->
<Window x:Class="YourNamespace.SplashScreen"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"WindowStyle="None" AllowsTransparency="True"Background="Transparent" WindowStartupLocation="CenterScreen"Width="400" Height="300"><Grid><!-- 自定义启动界面内容 --><Border CornerRadius="10" Background="#FF1E1E1E" BorderBrush="#FF3F3F46" BorderThickness="1"><Grid><StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"><TextBlock Text="应用名称" FontSize="24" Foreground="White"HorizontalAlignment="Center" Margin="0,0,0,20"/><ProgressBar IsIndeterminate="True" Height="10" Width="300"Foreground="#FF0EA5E9"/><TextBlock x:Name="StatusText" Text="正在初始化..." Foreground="LightGray" Margin="0,20,0,0"HorizontalAlignment="Center"/></StackPanel></Grid></Border></Grid>
</Window>
2. 创建主窗口 (MainWindow.xaml)
<!-- MainWindow.xaml -->
<Window x:Class="YourNamespace.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="主窗口" Height="450" Width="800"><Grid><!-- 主界面内容 --><TextBlock Text="欢迎使用主界面!" FontSize="24"HorizontalAlignment="Center" VerticalAlignment="Center"/></Grid>
</Window>
3. 修改 App.xaml.cs 核心逻辑
using System;
using System.Threading.Tasks;
using System.Windows;namespace YourNamespace
{public partial class App : Application{private SplashScreen _splashScreen;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);// 创建并显示启动窗口_splashScreen = new SplashScreen();_splashScreen.Show();// 异步初始化应用Task.Run(() => InitializeApplication()).ContinueWith(t => {// 初始化完成后切换到主界面Dispatcher.Invoke(() => SwitchToMainWindow());}, TaskScheduler.FromCurrentSynchronizationContext());}private void InitializeApplication(){// 模拟初始化操作(实际应用中替换为真实初始化逻辑)UpdateStatus("正在加载配置...");Task.Delay(1000).Wait();UpdateStatus("正在连接数据库...");Task.Delay(1500).Wait();UpdateStatus("正在准备界面...");Task.Delay(800).Wait();}private void UpdateStatus(string message){// 更新启动界面状态Dispatcher.Invoke(() => {if (_splashScreen != null){var statusText = _splashScreen.FindName("StatusText") as TextBlock;statusText.Text = message;}});}private void SwitchToMainWindow(){// 创建主窗口var mainWindow = new MainWindow();// 关闭启动窗口并释放资源_splashScreen.Close();_splashScreen = null;// 强制垃圾回收释放启动窗口资源GC.Collect();GC.WaitForPendingFinalizers();// 显示主窗口mainWindow.Show();}}
}
4. 修改 App.xaml(设置不自动启动主窗口)
<Application x:Class="YourNamespace.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="SplashScreen.xaml" ShutdownMode="OnExplicitShutdown"> <!-- 手动控制关闭 -->
</Application>
关键实现细节说明
-
异步初始化:
- 使用
Task.Run
在后台线程执行初始化操作,避免阻塞UI - 通过
Dispatcher.Invoke
安全更新UI状态
- 使用
-
资源销毁:
- 显式关闭启动窗口:
_splashScreen.Close()
- 移除引用:
_splashScreen = null
- 强制垃圾回收:
GC.Collect()
和GC.WaitForPendingFinalizers()
- 显式关闭启动窗口:
-
状态更新:
- 通过
FindName
查找控件并更新状态文本 - 模拟实际应用中的加载步骤
- 通过
-
应用关闭控制:
- 设置
ShutdownMode="OnExplicitShutdown"
防止启动窗口关闭时自动退出应用
- 设置
进阶优化方案
1. 添加进度反馈
// 在SplashScreen.xaml.cs中添加
public void UpdateProgress(int percent, string message = null)
{if (progressBar != null){progressBar.IsIndeterminate = false;progressBar.Value = percent;}if (!string.IsNullOrEmpty(message) && statusText != null){statusText.Text = message;}
}// 在App.xaml.cs中使用
private void InitializeApplication()
{UpdateProgress(10, "正在加载配置...");// ...UpdateProgress(50, "正在连接数据库...");// ...UpdateProgress(100, "初始化完成");
}
2. 添加淡入淡出动画
private void SwitchToMainWindow()
{// 创建主窗口但不立即显示var mainWindow = new MainWindow();mainWindow.Opacity = 0;// 启动窗口淡出var fadeOut = new DoubleAnimation(0, TimeSpan.FromSeconds(0.5));fadeOut.Completed += (s, e) => {_splashScreen.Close();_splashScreen = null;// 主窗口淡入mainWindow.Show();var fadeIn = new DoubleAnimation(1, TimeSpan.FromSeconds(0.5));mainWindow.BeginAnimation(Window.OpacityProperty, fadeIn);};_splashScreen.BeginAnimation(Window.OpacityProperty, fadeOut);
}
3. 添加超时处理
protected override void OnStartup(StartupEventArgs e)
{// 设置超时时间(30秒)var timeout = TimeSpan.FromSeconds(30);var cts = new CancellationTokenSource(timeout);Task.Run(() => InitializeApplication(cts.Token), cts.Token).ContinueWith(t => {if (t.IsCanceled){Dispatcher.Invoke(() => {MessageBox.Show("初始化超时,请重试");Shutdown();});}else{Dispatcher.Invoke(() => SwitchToMainWindow());}}, TaskScheduler.FromCurrentSynchronizationContext());
}
资源管理最佳实践
-
显式释放资源:
// 在SplashScreen.xaml.cs中 protected override void OnClosed(EventArgs e) {// 释放所有托管资源this.Content = null;base.OnClosed(e); }
-
使用WeakReference:
private WeakReference<SplashScreen> _splashRef;// 创建时 _splashRef = new WeakReference<SplashScreen>(_splashScreen);// 关闭时 if (_splashRef.TryGetTarget(out var splash)) {splash.Close(); } _splashRef = null;
-
图像资源处理:
// 如果启动窗口使用大图 protected override void OnClosed(EventArgs e) {if (Background is ImageBrush brush && brush.ImageSource is BitmapImage bmp){bmp.StreamSource?.Dispose();bmp.UriSource = null;}base.OnClosed(e); }
完整流程图
应用程序启动↓
显示启动窗口(SplashScreen)↓
启动异步初始化任务├── 更新状态消息├── 执行初始化步骤└── 更新进度条↓
初始化完成↓
主线程执行切换:1. 创建主窗口(MainWindow)2. 启动窗口淡出动画3. 关闭启动窗口4. 释放启动窗口资源5. 主窗口淡入动画↓
显示主窗口↓
应用程序运行
常见问题解决
-
启动窗口关闭后应用退出:
- 确保设置
ShutdownMode="OnExplicitShutdown"
- 在
App.xaml
中移除StartupUri
- 确保设置
-
跨线程访问UI元素:
- 始终使用
Dispatcher.Invoke
更新UI - 避免在后台线程直接操作UI元素
- 始终使用
-
资源未释放:
- 检查事件处理程序是否解注册
- 使用内存分析工具检查泄漏
- 确保取消后台任务(使用CancellationToken)
-
启动界面卡顿:
- 将耗时操作放在后台线程
- 避免在UI线程进行大量计算
- 使用异步加载资源
此方案确保了:
- 流畅的用户体验(带进度反馈的启动界面)
- 资源高效管理(显式释放启动窗口资源)
- 平滑的界面切换(可选动画效果)
- 健壮的错误处理(超时机制)
根据实际需求调整初始化逻辑和界面设计,核心是保持启动界面轻量并在完成后彻底释放其资源。