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

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

maynowei7个月前 (09-18)技术知识77

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

相关文章

微软明年要停止SQL Server 2005的技术支持了

站长之家(Chinaz.com)12月28日消息据外媒消息称,微软将于明年停止为SQL Server 2005提供技术支持,即不再为其提供新的安全补丁、新功能、应用升级等服务。且表示在停止技术支持后,...

Xamarin.Android使用教程:列表视图和适配器(2)

昨天我们已经一起学习了第1部分,这是探索Xamarin.Android的列表视图和适配器的的第2部分。在今天的文章中我们将探讨列表视图项排列使用BaseAdapter,还有自定义布局。让我们深入到代码...

go语言并发原语RWMutex实现原理及闭坑指南

1.RWMutex常用方法Lock/UnlockRLock/RUnlockRLocker 为读操作返回一个Locker接 口的对象2. RWMutex使用方法 func main() { var c...

Oracle标准化部署手册(oracle19c客户端)

很久之前写过一篇11g的windows安装手册, 这次是19c的windows安装手册,面向没有数据库安装部署经验的开发人员或想学习数据库的新手。希望能给想从事dba的入门人员小小的帮助。 毕竟每个高...

Oracle中泄露“天机”的TNS(在oracle中发出的下列查询)

数据库的安全是长期存在的问题。在目前大量的数据泄露事件以及漏洞面前,大家看到的大都是SQl注入、越权操作、缓冲区溢出等这些具体漏洞。往往却忽视了造成这些问题的前提,黑客想要入侵数据库一定会尝试获取数据...

6 张图带你彻底搞懂分布式事务 XA 模式

XA 协议是由 X/Open 组织提出的分布式事务处理规范,主要定义了事务管理器 TM 和局部资源管理器 RM 之间的接口。目前主流的数据库,比如 oracle、DB2 都是支持 XA 协议的。mys...