从入门到精通:揭秘WPF中App.xaml不为人知的8大黑科技
App.xaml 是 WPF 应用程序的入口点和核心配置文件,下面8个比较常用。
1、应用程序级别资源定义
如果有些资源在所有的页面都用到,我们可以把资源放到app.xaml
<Application.Resources>
<ResourceDictionary>
<!-- 全局样式 -->
<Style TargetType="Button">
<Setter Property="FontSize" Value="14"/>
<Setter Property="Margin" Value="5"/>
</Style>
<!-- 全局数据模板 -->
<DataTemplate DataType="{x:Type local:Customer}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Email}"/>
</StackPanel>
</DataTemplate>
<!-- 全局颜色和画笔 -->
<SolidColorBrush x:Key="PrimaryColor" Color="#FF2D7D9A"/>
</ResourceDictionary>
</Application.Resources>2、应用程序生命周期管理
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// 初始化操作
InitializeServices();
// 处理命令行参数
if (e.Args.Contains("-debug"))
{
DebugMode = true;
}
// 创建并显示主窗口
var mainWindow = new MainWindow();
mainWindow.Show();
}
protected override void OnExit(ExitEventArgs e)
{
// 清理资源
CleanupResources();
base.OnExit(e);
}
public static bool DebugMode { get; private set; }
}3、全局异常处理
写代码过程,有时会忘里加try catch,可以在这里捕捉全局异常。
public partial class App : Application
{
public App()
{
// UI线程未处理异常
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
// 非UI线程未处理异常
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
}
private void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// 记录异常
LogException(e.Exception);
// 显示友好错误信息
MessageBox.Show("发生未处理的异常,请联系管理员。", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
// 标记为已处理,防止应用程序崩溃
e.Handled = true;
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = e.ExceptionObject as Exception;
LogException(exception);
// 通常无法恢复,只能记录并退出
if (e.IsTerminating)
{
MessageBox.Show("应用程序即将关闭,原因是未处理的异常。", "致命错误",
MessageBoxButton.OK, MessageBoxImage.Stop);
}
}
}4、主题和皮肤切换
public partial class App : Application
{
public void ChangeTheme(string themeName)
{
// 清除现有资源
Resources.MergedDictionaries.Clear();
// 加载新主题
var themeUri = new Uri(#34;Themes/{themeName}.xaml", UriKind.Relative);
var themeDict = new ResourceDictionary { Source = themeUri };
Resources.MergedDictionaries.Add(themeDict);
// 保存用户偏好
Properties["CurrentTheme"] = themeName;
SaveProperties();
}
}5、多语言/本地化支持
如果系统需要多语言,app也可以提供很好的解决思路。
public partial class App : Application
{
public static readonly IList<string> SupportedLanguages = new List<string> { "en-US", "zh-CN" };
public void ChangeLanguage(string cultureCode)
{
if (!SupportedLanguages.Contains(cultureCode)) return;
var culture = new CultureInfo(cultureCode);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
// 更新资源字典
var dict = new ResourceDictionary();
dict.Source = new Uri(#34;Resources/StringResources.{cultureCode}.xaml", UriKind.Relative);
// 替换现有资源
var oldDict = Resources.MergedDictionaries
.FirstOrDefault(d => d.Source != null && d.Source.ToString().Contains("StringResources."));
if (oldDict != null)
{
Resources.MergedDictionaries.Remove(oldDict);
}
Resources.MergedDictionaries.Add(dict);
// 保存用户偏好
Properties["CurrentLanguage"] = cultureCode;
SaveProperties();
}
}6、应用程序设置持久化
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// 加载用户设置
LoadProperties();
// 应用保存的主题
if (Properties.Contains("CurrentTheme"))
{
ChangeTheme(Properties["CurrentTheme"].ToString());
}
// 应用保存的语言
if (Properties.Contains("CurrentLanguage"))
{
ChangeLanguage(Properties["CurrentLanguage"].ToString());
}
}
private void LoadProperties()
{
// 从隔离存储或配置文件加载
try
{
Properties = IsolatedStorageSettings.ApplicationSettings;
}
catch
{
Properties = new Hashtable();
}
}
private void SaveProperties()
{
// 保存到隔离存储或配置文件
if (Properties is IsolatedStorageSettings settings)
{
settings.Save();
}
}
public Hashtable Properties { get; private set; }
}7、单实例应用程序实现
软件开发一个很常见的需求:只能启动一个软件。也可以在app.xaml里实现。
public partial class App : Application
{
private static Mutex _mutex;
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "MyWpfApplication";
bool createdNew;
_mutex = new Mutex(true, appName, out createdNew);
if (!createdNew)
{
// 应用程序已经在运行
MessageBox.Show("应用程序已经在运行中。");
Current.Shutdown();
return;
}
base.OnStartup(e);
}
protected override void OnExit(ExitEventArgs e)
{
_mutex?.ReleaseMutex();
base.OnExit(e);
}
}8、启动画面(Splash Screen)实现
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// 显示启动画面
var splashScreen = new SplashScreen("Resources/splash.png");
splashScreen.Show(true);
// 模拟初始化耗时
Thread.Sleep(2000);
base.OnStartup(e);
}
}