当前位置:首页 > 技术知识 > 正文内容

从入门到精通:揭秘WPF中App.xaml不为人知的8大黑科技

maynowei9个月前 (09-18)技术知识104

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);
    }
}

相关文章

从零搭建网站?5个步骤详解网站建设全流程

在数字化时代,拥有一个专业网站已成为企业或个人品牌展示的核心竞争力。但对于新手而言,网站建设往往显得复杂难懂。本文梳理出5大关键步骤,手把手带你完成从策划到上线的全流程,省时省力不踩坑!一、前期准备:...

Win10系统除了移植Objective C,还要有Swift

IT之家讯Build2015大会最让人震惊的莫属微软推出工具,Win10系统可以移植安卓/iOS应用,特别是后者使用的Objective C编程语言,不过最新消息表明,微软连苹果最新的Swift移植也...

C# 中的多线程同步机制:lock、Monitor 和 Mutex 用法详解

在多线程编程中,线程同步是确保多个线程安全地访问共享资源的关键技术。C# 提供了几种常用的同步机制,其中 lock、Monitor 和 Mutex 是最常用的同步工具。本文将全面介绍这三种同步机制的用...

CPU「离奇」飙到 100%!开发者挖出 Linux 内核 16 年老 Bug:这么多年竟无人发现?

【CSDN 编者按】每一次对旧设备的升级都仿佛是一场跨越时代的冒险。本文作者致力于将基于 PXA166 的 Chumby 8 设备从 Linux 2.6.28 版本升级到现代 6.x 版本,然而,在看...

Navicat Premium 连接 Oracle 数据库

Navicat Premium是一个可多重连接的数据库管理工具,它可让你以单一程序同時连接到 MySQL、SQLite、Oracle 及 PostgreSQL 数据库,让管理不同类型的数据库更加方便。...

ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务

早上同事用PL/SQL连接虚拟机中的Oracle数据库,发现又报了“ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务”错误,帮其解决后,发现很多人遇到过这样的问题,因此写着这里。也...