• 【.NET深呼吸】将XAML放到WPF程序之外


    上一篇水文中,老周说了一下纯代码编写 WPF 的大概过程。不过,还是不够的,本篇水文中咱们还要更进一步。

    XAML 文件默认是作为资源打包进程序中的,而纯代码编写又导致一些常改动的东西变成硬编码了。为了取得二者平衡,咱们还要把一些经常修改的东西放到 XAML 文件中,不过 XAML 文件不编译进程序里,而是放到外部,运行阶段加载。比如一些对象属性、画刷、样式、字体之类的,直接改文件保存就行,修改之后不用重新编译项目。

    要在运行阶段加载 XAML,咱们只需认识一个类就OK—— XamlReader,调用它的 Load 方法就能从 XAML 文件加载对象了。

    下面老周就边演示边唠叨一下相关的问题。

    一、新建项目。可以参照上一篇中的做法,用控制台应用程序项目,然后修改项目文件。也可以直接建 WPF 项目。都可以。

     

     

    二、自定义窗口类,从 Window 派生。当然,你直接用 Window 类也可以的。

    复制代码
    public class MyWindow : Window
    {
        const string XAML_FILE = "MyWindow.xaml";
    
        public MyWindow()
        {
            Title = "加载外部XAML";
            Height = 150;
            Width = 225;
            // 从XAML文件加载
            using FileStream fsIn = new(XAML_FILE, FileMode.Open, FileAccess.Read);
            FrameworkElement layout = (FrameworkElement)XamlReader.Load(fsIn);
            // 两个按钮要处理事件
            Button btn1 = (Button)layout.FindName("btn1");
            Button btn2 = (Button)layout.FindName("btn2");
            btn1.Click += OnClick1;
            btn2.Click += OnClick2;
            Content = layout;
        }
    
        private void OnClick2(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("第二个按钮");
        }
    
        private void OnClick1(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("第一个按钮");
        }
    }
    复制代码

    这个不复杂,咱们关注加载 XAML 部分。通过文件流 FileStream 读取文件,而后在 XamlReader.Load 中加载。Load 方法返回的是 object 类型的对象,咱们要适当地进行类型转换。这个例子里面其实加载上来的是 Grid 类,但这里我只转换为 FrameworkElement 就可以了,毕竟我后面只用到了 FindName 方法。Find 出来的是两个 Button 对象,最后处理一下 Click 事件。

     

    三、在项目中添加 MyWindow.xaml 文件。

    复制代码
    <Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          Margin="12">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
        Grid.RowDefinitions>
        <Button Name="btn1" Grid.Row="0" Margin="5,8">按钮AButton>
        <Button Name="btn2" Grid.Row="1" Margin="5,8">按钮BButton>
    Grid>
    复制代码

    这里顺便说一下,保存 XAML 文件时最好用 UTF-8 编码,不然可能会报错。方法是在 VS 里,【文件】-【XXX 另存为】。在保存文件对话框中,点“保存”按钮右边的箭头,选择“编码保存”。

    编码选 UTF-8 无签名(或带签名的也行)。

    另一种方法是用记事本打开,再以 UTF-8 保存。

     

    四、在项目中添加 styles.xaml。

    复制代码
    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <Style TargetType="Button">
            <Setter Property="Background" Value="Red"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="Padding" Value="5"/>
            <Setter Property="FontFamily" Value="楷体"/>
            <Setter Property="FontSize" Value="17"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush" Value="Yellow"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                CornerRadius="5">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                              Margin="{TemplateBinding Padding}"/>
                        Border>
                    ControlTemplate>
                Setter.Value>
            Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="Green"/>
                Trigger>
                <Trigger Property="IsPressed" Value="True">
                    <Setter Property="Background" Value="DarkSlateGray"/>
                Trigger>
            Style.Triggers>
        Style>
    ResourceDictionary>
    复制代码

    里面包含一个 Button 控件模板。

     

    五、在 Main 方法中,初始化 Application 类,并且从外部 XAML 中加载资源字典。

    复制代码
    [STAThread]
    static void Main(string[] args)
    {
        Application app = new();
        using FileStream extFile = new FileStream("styles.xaml", FileMode.Open, FileAccess.Read);
        ResourceDictionary dic = (ResourceDictionary)XamlReader.Load(extFile);
        app.Resources = dic;
        app.Run(new MyWindow());
    }
    复制代码

    由于是在 app 处加载的资源,所以按钮样式会应用到整个程序。

     

    六、打开项目文件(*.csproj),我们要做点手脚。

    复制代码
    
        
        
    
    
        copy /y *.xaml $(OutDir)" />
    
    复制代码

    老周解释一下加了颜色的部分。

    1、Page 表示XAML文件最终生成二进制文件,且塞进目标程序集中。加了 Remove 表示排除这一行为。说人话就是:本项目不编译 XAML 文件。

    2、None 表示该项目中 XAML 文件“啥也不是”,编译时不做任何处理。

    3、PostBuild 任务指定一条命令,在生成项目之后执行。此处是把项目目录下的 XAML 文件复制到输出目录。$(OutDir) 在 VS 中表示宏(也是 MSBuild 的属性)。在命令实际执行时,替换为实际目录路径,如 bin\Debug\net7.0-windows。

    也可以用 $(TargetDir),不过 TargetDir 替换的是完整路径,OutDir 是用相对路径的。

     

    现在生成一下项目,若没有问题,在输出目录下除了程序文件,还有那两个 XAML 文件。运行一下。

    关闭程序,用记事本打开 styles.xaml 文件,把按钮的背景色改成橙色。

    保存并关闭文件,重新运行程序。

    咱们并没有重新编译程序。接下来用记事本打开 MyWindow.xaml 文件,改一下按钮上的文本。

    保存并关闭文件,不用编译代码,再次运行程序。

     

    这样就很方便修改了,不必每次都重新编译。 

    下一篇老周还会说说纯代码写 WPF 的模板问题。三维图形就看心情了。因为 3D 图形的构造和一般控件应用差不多,就是用代码建立 WPF 对象树。

  • 相关阅读:
    WPS回应套娃式收费:AI功能投入比较大且福利期已到;Sam Altman辟谣下周发GPT-5和搜索引擎 | 极客头条
    docker安装【zookeeper】&【kafka】&【provectuslabs/kafka-ui】记录
    打造千万级流量秒杀第十六课 漏斗模型:如何将并发流量过滤和串行化?
    正交序列扩频_解扩
    视频怎么批量压缩?5个好用的电脑软件和在线网站
    Javascript知识【jQuery-validation插件】
    数据可视化之对外经济发展,近五年我国对外货物进出口总额持续上涨
    炒鸡详细的Vm安装Linux和Linux客户端使用以及​Linux下的目录结构
    【数据可视化】免费开源BI工具DataEase实现了SQL数据集和Excel数据集关联?(什么?快别挡着我,冲!)
    知识点2--CMS项目首页
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/17486037.html