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

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

maynowei8个月前 (09-18)技术知识94

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

相关文章

第四章:产品设计(2.3)PRD写作 - 原型设计

2.3、原型设计(界面线框图)当我们逐渐清晰了产品的需求后,并梳理了产品的各个频道及页面,那么这一步就要开始验证这些想法的具体界面表现和方案的可行性了。原型设计是帮助我们更细致的思考,并做各项需求的评...

ExpandListView 的一种巧妙写法(三十的另一种写法)

ExpandListView大家估计也用的不少了,一般有需要展开的需求的时候,大家不约而同的都想到了它然后以前自己留过记录的一般都会找找以前自己的代码,没有记录习惯的就会百度、谷歌,这里吐槽一下,好几...

Win10桌面/手机版最深层次开发功能挖掘

IT之家讯 Win10开发者预览版为我们提供了一个Win10大框架的早期概览,使开发者与热心用户都可以提前感受Win10带来的新特性,尝试新工具,而作为开发者,最关心的莫过于Windows多平台通用应...

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

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

C++ 原子操作与锁的深度解析:为什么原子操作并非万金油?

大噶好,我是henry,今天来和大家浅浅聊一下为啥C++原子操作并非万能钥匙,原因有三,且听我娓娓道来:一、原子操作的线程安全性C++11 的 std::atomic 确实为单个变量的线程安全操作提供...

PL/SQL Developer连接Oracle数据库详解

序言:oracle数据库比较难搞,好不容易安装上了,但是怎么连接呢,直接在服务器里用自带的命令行操作太繁琐,所以PL/SQL Developer客户端的好处就显而易见了,今天和大家聊聊客户端具体配置方...