Avalonia 学习笔记07. Control Themes(控件主题)

news/2025/9/23 19:52:25/文章来源:https://www.cnblogs.com/ggds/p/19107934

在本章节中,我们的目标是创建一个可复用的、带图标的按钮控件,以简化我们在视图(View)中编写的XAML代码。当前,每创建一个带图标的按钮,都需要在 <Button> 内部嵌套一个 <StackPanel> 和两个 <Label>,这非常繁琐。

我们将创建一个名为 IconButton 的新控件,它天生就包含一个图标区域和一个内容区域,使得我们可以像这样使用它:<IconButton IconText="..." Content="..."/>。我们将通过控件主题(ControlTheme)来实现这个功能,这是一种深度自定义控件外观的强大方式。

7.1 Controls\IconButton.axaml

首先,我们在项目中新建一个名为 Controls 的文件夹。然后右键点击该文件夹,选择“添加” -> “新建项”,在 Avalonia 分类中选择 Templated Control(模板化控件),并将其命名为 IconButton.axaml

创建完成后,我们会得到一个 .axaml 文件和一个对应的 .axaml.cs 后台代码文件。

我们的目标是让 IconButton 拥有标准按钮的所有外观和行为,并在此基础上增加一个图标。最简单的方式就是复制 Avalonia Fluent 主题中 Button 的默认模板,然后进行修改。

以下代码就是从 Avalonia 源码中复制并修改而来的 Button 的 ControlTheme

这个初始的模板可以在这个链接获取:https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Themes.Fluent/Controls/Button.xaml

关键修改点解释:

  1. <ControlTheme x:Key="{x:Type IconButton}" TargetType="IconButton">

    • 用途:这行代码声明了我们正在定义一个控件主题。TargetType="IconButton" 指定了这个主题是为我们自己的 IconButton 控件设计的。它会成为 IconButton 的默认外观。
  2. <ContentPresenter.ContentTemplate>

    • 用途:我们不再让 ContentPresenter 简单地显示内容,而是为它提供了一个 DataTemplate(数据模板)。这个模板定义了内容的具体结构:一个水平排列的 StackPanel,里面包含一个用于显示图标的 Label 和一个用于显示主要内容的 ContentControl
  3. 图标绑定:Content="{Binding $parent[IconButton].IconText}"

    • 用途:这是 DataTemplate 内部的绑定语法。$parent[IconButton] 的意思是“从当前位置向上查找,找到第一个名为 IconButton 的父控件”,然后 .IconText 表示绑定到该控件的 IconText 属性。这样,我们在XAML中设置的 IconText 就能正确地显示为图标了。
    • 注意Label 的 Classes="icon" 是为了能让 AppDefaultStyles.axaml 中定义的图标字体样式应用到这个 Label 上。
  4. 内容和数据上下文绑定

    • 用途<ContentControl DataContext="{...}" Content="{...}" /> 这一部分是为了修复一个在视频后面会遇到的 DataContext(数据上下文)问题。当我们在 IconButton 内部放置一个需要绑定到视图模型(ViewModel)的控件时(比如侧边栏可以折叠的文字),这个设置可以确保数据上下文被正确地传递下去,让绑定能够正常工作。
<!-- 备注:这是 IconButton 的视觉模板定义文件。 -->
<!-- 它决定了 IconButton 在界面上看起来是什么样子。 -->
<ResourceDictionary xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:ClassModifier="internal"><!-- Design.PreviewWith 用于在设计器中预览控件效果,不影响程序运行 --><Design.PreviewWith><Border Padding="20"><StackPanel Spacing="20"><IconButton IconText="&#xe7f2;" Content="Click Me!" /><IconButton IconText="&#xe3ee;" Classes="accent" Content="Click Me!" /><Button Content="Click Me!" /><Button Classes="accent" Content="Click Me!" /></StackPanel></Border></Design.PreviewWith><!-- 这是 IconButton 控件的主题定义 --><ControlTheme x:Key="{x:Type IconButton}" TargetType="IconButton"><!-- 下面是按钮在各种状态下的默认样式设置(背景、前景、边框等) --><Setter Property="Background" Value="{DynamicResource ButtonBackground}" /><Setter Property="Foreground" Value="{DynamicResource ButtonForeground}" /><Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrush}" /><Setter Property="BorderThickness" Value="{DynamicResource ButtonBorderThemeThickness}" /><Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" /><Setter Property="Padding" Value="{DynamicResource ButtonPadding}" /><Setter Property="HorizontalAlignment" Value="Left" /><Setter Property="VerticalAlignment" Value="Center" /><Setter Property="RenderTransform" Value="none" /><Setter Property="Transitions"><Transitions><TransformOperationsTransition Property="RenderTransform" Duration="0:0:.075" /></Transitions></Setter><!-- Template 定义了控件的内部结构 (ControlTemplate) --><Setter Property="Template"><ControlTemplate><ContentPresenter x:Name="PART_ContentPresenter"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"CornerRadius="{TemplateBinding CornerRadius}"Padding="{TemplateBinding Padding}"RecognizesAccessKey="True"HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"><!-- 这里是我们自定义的内容模板,用于显示图标和文字 --><ContentPresenter.ContentTemplate><DataTemplate DataType="x:Object"><StackPanel Orientation="Horizontal" Spacing="8"><!-- 这个 Label 用于显示图标,它的 Content 绑定到 IconButton 的 IconText 属性 --><Label Classes="icon" Content="{Binding $parent[IconButton].IconText}"></Label><!-- 这个 ContentControl 用于显示 IconButton 的主要内容,并修复了 DataContext 的问题 --><ContentControl DataContext="{Binding $parent[IconButton].DataContext}" Content="{Binding $parent[IconButton].Content}" /></StackPanel></DataTemplate></ContentPresenter.ContentTemplate></ContentPresenter></ControlTemplate></Setter><!-- 下面是按钮在不同交互状态(如鼠标悬浮、按下)下的样式变化 --><Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource ButtonBackgroundPointerOver}" /><Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPointerOver}" /><Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPointerOver}" /></Style><Style Selector="^:pressed"><Setter Property="RenderTransform" Value="scale(0.98)" /></Style><Style Selector="^:pressed  /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource ButtonBackgroundPressed}" /><Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushPressed}" /><Setter Property="Foreground" Value="{DynamicResource ButtonForegroundPressed}" /></Style><Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource ButtonBackgroundDisabled}" /><Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderBrushDisabled}" /><Setter Property="Foreground" Value="{DynamicResource ButtonForegroundDisabled}" /></Style><!-- 这是对拥有 "accent" 样式的按钮的特殊处理 --><Style Selector="^.accent"><Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" /><Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrush}" /><Setter Property="Foreground" Value="{DynamicResource AccentButtonForeground}" /></Style><Style Selector="^:pointerover /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPointerOver}" /><Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPointerOver}" /><Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPointerOver}" /></Style><Style Selector="^:pressed  /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundPressed}" /><Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushPressed}" /><Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundPressed}" /></Style><Style Selector="^:disabled /template/ ContentPresenter#PART_ContentPresenter"><Setter Property="Background" Value="{DynamicResource AccentButtonBackgroundDisabled}" /><Setter Property="BorderBrush" Value="{DynamicResource AccentButtonBorderBrushDisabled}" /><Setter Property="Foreground" Value="{DynamicResource AccentButtonForegroundDisabled}" /></Style></Style></ControlTheme>
</ResourceDictionary>

 

7.2 Controls\IconButton.axaml.cs

这是 IconButton 的后台代码文件。

关键修改点解释:

  1. public class IconButton : Button

    • 用途:我们将基类从默认的 TemplatedControl 修改为了 Button。这是至关重要的一步。通过继承 Button,我们的 IconButton 自动获得了按钮的所有核心功能,例如 Click 事件、Command 绑定、可点击性等。它现在“是”一个按钮了。
  2. IconTextProperty

    • 用途:我们在这里定义了一个新的 StyledProperty(样式化属性),名为 IconTextStyledProperty 是 Avalonia 中的一种特殊属性,它支持数据绑定、样式设置和在模板中使用。这使得我们可以在 XAML 文件中像这样 <IconButton IconText="..."/> 来给它赋值。
// 备注:这是 IconButton 的后台逻辑代码文件。
using Avalonia;
using Avalonia.Controls;namespace AvaloniaApplication2.Controls;// 关键:让 IconButton 继承自 Button,这样它就拥有了按钮的所有功能
public class IconButton : Button
{// 定义一个名为 IconText 的新属性,这样我们就可以在 XAML 中设置它// StyledProperty 是一种支持数据绑定和样式的特殊属性public static readonly StyledProperty<string> IconTextProperty = AvaloniaProperty.Register<IconButton, string>(nameof(IconText));// 这是 IconText 属性的常规 C# 包装器public string IconText{get => GetValue(IconTextProperty);set => SetValue(IconTextProperty, value);}
}

 

7.3 Styles\AppDefaultStyles.axaml

关键修改点解释:

  1. :is(Button) 选择器
    • 用途:我们将之前所有针对 Button 的样式选择器,例如 Style Selector="Button",都修改为了 Style Selector=":is(Button)"
    • 原因:is() 是一个伪类选择器,它会匹配所有符合括号内条件的控件。:is(Button) 不仅会匹配标准的 <Button>,还会匹配任何继承自 Button 的控件。因为我们的 IconButton 继承自 Button,所以这个修改可以确保我们为普通按钮编写的通用样式(如圆角、字体大小、颜色等)也能自动应用到 IconButton 上,保持了应用的视觉统一性。
<Styles xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"><Design.PreviewWith><Border Padding="20" Background="{DynamicResource PrimaryBackgroundGradient}" Width="200"><!-- 此处预览代码未更改 --><StackPanel Spacing="12"><Image Source="{SvgImage /Assets/Images/logo.svg}" Width="200"></Image><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xE2C2;"></Label><Label Classes="akko" Content="Home"></Label></StackPanel></Button><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xE346;"></Label><Label Classes="akko" Content="Process"></Label></StackPanel></Button><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xE7F2;"></Label><Label Classes="akko" Content="Actions"></Label></StackPanel></Button><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xE3EE;"></Label><Label Classes="akko" Content="Macros"></Label></StackPanel></Button><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xEB7A;"></Label><Label Classes="akko" Content="Reporter"></Label></StackPanel></Button><Button HorizontalAlignment="Stretch"><StackPanel Orientation="Horizontal"><Label Classes="icon" Content="&#xE03A;"></Label><Label Classes="akko" Content="History"></Label></StackPanel></Button><Button><Label Classes="icon-only" Content="&#xE272;"></Label></Button><Button Classes="transparent" Grid.Row="1"><Label Classes="icon-only" Content="&#xE272;"></Label></Button></StackPanel></Border></Design.PreviewWith><!-- 未更改的样式 --><Style Selector="Window"><!-- <Setter Property="FontFamily" Value="{DynamicResource AkkoPro}"></Setter> --></Style><Style Selector="Border"><Setter Property="Transitions"><Transitions><DoubleTransition Property="Width" Duration="0:0:1"></DoubleTransition></Transitions></Setter></Style><Style Selector="Label.icon, Label.icon-only"><Setter Property="FontFamily" Value="{DynamicResource Phosphor-Fill}"></Setter><Setter Property="Margin" Value="0 2 5 0"></Setter><Setter Property="FontSize" Value="19"></Setter></Style><Style Selector="Label.icon-only"><Setter Property="Margin" Value="0"></Setter></Style><Style Selector="Button, Label.akko"><Setter Property="FontFamily" Value="{DynamicResource AkkoPro}"></Setter></Style><!-- 关键修改:将 "Button" 选择器改为 ":is(Button)",以使其能应用到 IconButton --><Style Selector=":is(Button)"><Setter Property="FontSize" Value="20"></Setter><Setter Property="CornerRadius" Value="10"></Setter><Setter Property="Foreground" Value="{DynamicResource PrimaryForeground}"></Setter><Setter Property="Background" Value="{DynamicResource PrimaryBackground}"></Setter></Style><Style Selector=":is(Button) /template/ ContentPresenter"><Setter Property="RenderTransform" Value="scale(1)"></Setter><Setter Property="Transitions"><Transitions><BrushTransition Property="Foreground" Duration="0:0:0.1"></BrushTransition><BrushTransition Property="Background" Duration="0:0:0.1"></BrushTransition><TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.1"></TransformOperationsTransition></Transitions></Setter></Style><Style Selector=":is(Button).transparent:pointerover Label"><Setter Property="RenderTransform" Value="scale(1.2)"></Setter></Style><Style Selector=":is(Button):pointerover /template/ ContentPresenter"><Setter Property="Foreground" Value="{DynamicResource PrimaryHoverForeground}"></Setter><Setter Property="Background" Value="{DynamicResource PrimaryHoverBackground}"></Setter></Style><Style Selector=":is(Button).active /template/ ContentPresenter"><Setter Property="Background" Value="{DynamicResource PrimaryActiveBackground}"></Setter></Style><Style Selector=":is(Button).transparent"><Setter Property="Background" Value="Transparent"></Setter></Style><Style Selector=":is(Button).transparent Label.icon-only"><Setter Property="FontFamily" Value="{DynamicResource Phosphor}"></Setter></Style><Style Selector=":is(Button).transparent:pointerover /template/ ContentPresenter"><Setter Property="Background" Value="Transparent"></Setter></Style>
</Styles>

 

7.4 App.axaml

关键修改点解释:

  1. <MergeResourceInclude Source="/Controls/IconButton.axaml"/>
    • 用途:这行代码的作用是将我们刚刚创建的 IconButton.axaml 文件(它是一个资源字典)合并到应用的主资源中。
    • 原因:如果不进行这一步,整个应用程序将不知道 IconButton 的样式定义在哪里,导致 IconButton 无法被正确渲染,会显示为一个没有样式的空白控件。这一步使得 IconButton 的主题在整个应用范围内都是可用的。
<Application xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="AvaloniaApplication2.App"xmlns:local="clr-namespace:AvaloniaApplication2"RequestedThemeVariant="Default"><!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --><Application.DataTemplates><local:ViewLocator></local:ViewLocator></Application.DataTemplates><Application.Styles><FluentTheme /><StyleInclude Source="Styles/AppDefaultStyles.axaml"></StyleInclude></Application.Styles><!-- 在这里添加了对 IconButton 样式文件的引用 --><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><!-- 这行代码将 IconButton.axaml 中定义的样式合并到整个应用中 --><MergeResourceInclude Source="/Controls/IconButton.axaml"></MergeResourceInclude></ResourceDictionary.MergedDictionaries></ResourceDictionary><!-- 此处其他资源未更改 --><SolidColorBrush x:Key="PrimaryForeground">#CFCFCF</SolidColorBrush><SolidColorBrush x:Key="PrimaryBackground">#14172D</SolidColorBrush><LinearGradientBrush x:Key="PrimaryBackgroundGradient" StartPoint="0%, 0%" EndPoint="100%, 0%"><GradientStop Offset="0" Color="#111214"></GradientStop><GradientStop Offset="1" Color="#151E3E"></GradientStop></LinearGradientBrush><SolidColorBrush x:Key="PrimaryHoverBackground">#333B5A</SolidColorBrush><SolidColorBrush x:Key="PrimaryActiveBackground">#6633dd</SolidColorBrush><SolidColorBrush x:Key="PrimaryHoverForeground">White</SolidColorBrush><FontFamily x:Key="AkkoPro">/Assets/Fonts/AkkoPro-Regular.ttf#Akko Pro</FontFamily><FontFamily x:Key="AkkoProBold">/Assets/Fonts/AkkoPro-Bold.ttf#Akko Pro</FontFamily><FontFamily x:Key="Phosphor">/Assets/Fonts/Phosphor.ttf#Phosphor</FontFamily><FontFamily x:Key="Phosphor-Fill">/Assets/Fonts/Phosphor-Fill.ttf#Phosphor</FontFamily></Application.Resources>
</Application>

 

7.5 App.axaml.cs

关键修改点解释:

  1. [assembly: XmlnsDefinition(...)]
    • 用途:这是一个程序集级别的特性(Attribute),它将一个 C# 命名空间(AvaloniaApplication2.Controls)映射到一个 XML 命名空间(https://github.com/avaloniaui)。
    • 原因:这是一个非常有用的“语法糖”。添加它之后,我们就可以在 XAML 中直接使用 <IconButton />,而不需要先在文件顶部定义一个像 xmlns:c="clr-namespace:AvaloniaApplication2.Controls" 这样的前缀,然后再使用 <c:IconButton />。它让我们的自定义控件使用起来和 Avalonia 的内置控件一样方便、自然。
using System;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Metadata; // 需要引入这个命名空间
using AvaloniaApplication2.Data;
using AvaloniaApplication2.Factories;
using AvaloniaApplication2.ViewModels;
using Microsoft.Extensions.DependencyInjection;// 关键:添加这个程序集特性,让我们可以不带前缀地在 XAML 中使用 IconButton
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "AvaloniaApplication2.Controls")]namespace AvaloniaApplication2;public partial class App : Application
{// 此文件中的其他代码在本节教程中未发生变更public override void Initialize(){AvaloniaXamlLoader.Load(this);}public override void OnFrameworkInitializationCompleted(){var collection = new ServiceCollection();collection.AddSingleton<MainViewModel>();collection.AddTransient<ActionsPageViewModel>();collection.AddTransient<HomePageViewModel>();collection.AddTransient<MacrosPageViewModel>();collection.AddTransient<ProcessPageViewModel>();collection.AddTransient<ReporterPageViewModel>();collection.AddTransient<HistoryPageViewModel>();collection.AddTransient<SettingsPageViewModel>();collection.AddSingleton<Func<ApplicationPageNames, PageViewModel>>(x => name => name switch{ApplicationPageNames.Home => x.GetRequiredService<HomePageViewModel>(),ApplicationPageNames.Process => x.GetRequiredService<ProcessPageViewModel>(),ApplicationPageNames.Macros => x.GetRequiredService<MacrosPageViewModel>(),ApplicationPageNames.Actions => x.GetRequiredService<ActionsPageViewModel>(),ApplicationPageNames.Reporter => x.GetRequiredService<ReporterPageViewModel>(),ApplicationPageNames.History => x.GetRequiredService<HistoryPageViewModel>(),ApplicationPageNames.Settings => x.GetRequiredService<SettingsPageViewModel>(),_ => throw new InvalidOperationException()});collection.AddSingleton<PageFactory>();var services = collection.BuildServiceProvider();if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop){desktop.MainWindow = new MainView{DataContext = services.GetService<MainViewModel>()};}base.OnFrameworkInitializationCompleted();}
}

 

7.6 Views\MainView.axaml

关键修改点解释:

  • 替换为 <IconButton>:这里是应用我们新控件最直观的地方。之前所有左侧菜单的按钮都是由 <Button><StackPanel><Label/><Label/></StackPanel></Button> 这样的复杂结构组成的。
  • 简化XAML:现在,我们用一行简洁的 <IconButton> 就完成了同样的功能。图标通过 IconText 属性设置,而需要折叠的文字 Label 则直接作为 IconButton 的内容(Content)传入。这使得 XAML 代码大大减少,并且更易于阅读和维护。
<Window xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d" d:DesignWidth="1400" d:DesignHeight="800"Width="1400" Height="800"MinWidth="1400" MinHeight="800 "x:Class="AvaloniaApplication2.MainView"xmlns:vm="clr-namespace:AvaloniaApplication2.ViewModels"xmlns:view="clr-namespace:AvaloniaApplication2.Views"x:DataType="vm:MainViewModel"Title="AvaloniaApplication2"><Design.DataContext><vm:MainViewModel></vm:MainViewModel></Design.DataContext><Grid Background="{DynamicResource PrimaryBackground}" ColumnDefinitions="Auto, *"><ContentControl Grid.Column="1" Content="{Binding CurrentPage}" /><Border Padding="20" Background="{DynamicResource PrimaryBackgroundGradient}"><Grid RowDefinitions="*, Auto"><StackPanel Spacing="12"><Image PointerPressed="InputElement_OnPointerPressed" Source="{SvgImage /Assets/Images/logo.svg}" Width="220" IsVisible="{Binding SideMenuExpanded}"></Image><Image PointerPressed="InputElement_OnPointerPressed" Source="{SvgImage /Assets/Images/icon.svg}" Width="22" IsVisible="{Binding !SideMenuExpanded}"></Image><!-- 关键修改:将原来的复杂 Button 结构替换为简洁的 IconButton --><IconButton IconText="&#xE2C2;" HorizontalAlignment="Stretch" Classes.active="{Binding HomePageIsActive}" Command="{Binding GoToHomeCommand}"><Label Classes="akko" Content="Home" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton><IconButton IconText="&#xE346;" HorizontalAlignment="Stretch" Classes.active="{Binding ProcessPageIsActive}" Command="{Binding GoToProcessCommand}"><Label Classes="akko" Content="Process" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton><IconButton IconText="&#xE7F2;" HorizontalAlignment="Stretch" Classes.active="{Binding ActionsPageIsActive}" Command="{Binding GoToActionsCommand}"><Label Classes="akko" Content="Actions" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton><IconButton IconText="&#xE3EE;" HorizontalAlignment="Stretch" Classes.active="{Binding MacrosPageIsActive}" Command="{Binding GoToMacrosCommand}"><Label Classes="akko" Content="Macros" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton><IconButton IconText="&#xEB7A;" HorizontalAlignment="Stretch" Classes.active="{Binding ReporterPageIsActive}" Command="{Binding GoToReporterCommand}"><Label Classes="akko" Content="Reporter" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton><IconButton IconText="&#xE03A;" HorizontalAlignment="Stretch" Classes.active="{Binding HistoryPageIsActive}" Command="{Binding GoToHistoryCommand}"><Label Classes="akko" Content="History" IsVisible="{Binding SideMenuExpanded}"></Label></IconButton></StackPanel><!-- 这个设置按钮未在本节修改,但因为它也是Button,所以会受到 :is(Button) 样式的影响 --><Button Classes="transparent" Grid.Row="1" Classes.active="{Binding SettingsPageIsActive}" Command="{Binding GoToSettingsCommand}"><Label Classes="icon-only" Content="&#xE272;"></Label></Button></Grid></Border></Grid></Window>

 

7.7 Views\SettingsPageView.axaml

与 MainView 类似,SettingsPageView 中的所有带图标的按钮也被替换成了我们新的 IconButton

关键修改点解释:

  • 代码简化:这里的修改效果更加明显。对于那些内容只是简单文本的按钮,例如“Release License”,之前的XAML结构被极大地简化了。
  • 统一接口:现在,无论是只需要文本的按钮,还是需要图标+文本的按钮,我们都使用同一个 IconButton 控件,通过 IconText 和 Content 属性来控制其显示,使得API非常统一和清晰。
<UserControl xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:vm="clr-namespace:AvaloniaApplication2.ViewModels"mc:Ignorable="d" d:DesignWidth="1100" d:DesignHeight="900"Background="{DynamicResource PrimaryBackground}"Foreground="{DynamicResource PrimaryForeground}"x:DataType="vm:SettingsPageViewModel"x:Class="AvaloniaApplication2.Views.SettingsPageView"><Design.DataContext><vm:SettingsPageViewModel></vm:SettingsPageViewModel></Design.DataContext><Grid ColumnDefinitions="*, *" RowDefinitions="Auto, *"><!-- Header 未更改 --><Grid Name="HeaderGrid" Grid.ColumnSpan="2"><Image Source="{SvgImage /Assets/Images/background-settings.svg}" Height="160" Stretch="UniformToFill"></Image><StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"><Label HorizontalAlignment="Center" Content="Settings"></Label><Label HorizontalAlignment="Center" Content="Version 3.0.0.2 Beta"></Label><Label HorizontalAlignment="Center" Content="Compiled Jul 07 2025"></Label></StackPanel></Grid><!-- Left side content --><StackPanel Grid.Column="0" Grid.Row="1" Spacing="10" Margin="15"><!-- General --><StackPanel><Label Content="General"></Label><Grid ColumnDefinitions="*, Auto" RowDefinitions="Auto, Auto, Auto"><!-- Release license --><TextBlock TextWrapping="Wrap" Text="Remove license of BatchProcess from this machine and release the license back to the server ready to be transferred to another machine."></TextBlock><!-- 关键修改:替换为 IconButton --><IconButton IconText="&#xE2FE;" Content="Release License" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton><!-- Skip Files --><TextBlock Grid.Row="1" Grid.Column="0" TextWrapping="Wrap" Text="Skip files if only Open, Save (Optional) and Close are Valid actions."></TextBlock><CheckBox Grid.Row="1" Grid.Column="1"></CheckBox><!-- Duplicate Entries --><TextBlock Grid.Row="2" Grid.Column="0" TextWrapping="Wrap" Text="Allow duplicate entries of the same file in project list"></TextBlock><CheckBox Grid.Row="2" Grid.Column="1"></CheckBox></Grid></StackPanel><!-- Location --><StackPanel><Label Content="Location"></Label><Grid ColumnDefinitions="*, Auto"><StackPanel><TextBlock TextWrapping="Wrap" Text="Add or remove the locations to search for Reporter Templates, Macros, Actions and other custom files or templates."></TextBlock><TextBlock TextWrapping="Wrap" Text="All sub-directories will be searched automatically"></TextBlock></StackPanel><Button Grid.Column="1" Content="+ Folder" HorizontalAlignment="Stretch"></Button></Grid><ListBox ItemsSource="{Binding LocationPaths}"></ListBox></StackPanel></StackPanel><!-- Right Side Content --><StackPanel Grid.Column="1" Grid.Row="1" Spacing="10" Margin="15"><!-- SolidWorks Host (未更改) --><StackPanel><Label Content="SolidWorks Host"></Label><TextBlock TextWrapping="Wrap">BatchProcess can work locally on the current machine, or on any machine accessibleover the network or even internet.<LineBreak /><LineBreak />Enter the machines IP address, network name or localhost for this machine.</TextBlock><ComboBox></ComboBox><Label Content="Connection established"></Label></StackPanel><!-- PDM Enterprise --><StackPanel Spacing="15"><Label Content="PDM Enterprise"></Label><TextBlock TextWrapping="Wrap" Text="If you are using PDM Enterprise enter the credentials below and test login. BatchProcess can then automatically handle checking in and out files from PDM Enterprise."></TextBlock><Grid ColumnDefinitions="*, *, *"><ComboBox HorizontalAlignment="Stretch"></ComboBox><TextBox Grid.Column="1"></TextBox><TextBox Grid.Column="2"></TextBox></Grid><StackPanel Orientation="Horizontal"><!-- 关键修改:替换为 IconButton --><IconButton IconText="&#xE23E;" Content="Login" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton><IconButton IconText="&#xE094;" Content="Refresh Vault" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton></StackPanel><Label Content="Connection Established"></Label></StackPanel><!-- Setting Cache --><StackPanel Spacing="15"><Label Content="Setting Cache"></Label><TextBlock TextWrapping="Wrap">Various settings are stored locally including Processes, Actions, Macros, Reports and History. <LineBreak /><LineBreak />If you are experiencing issues you can try clearing the cache (this won't remove the license).</TextBlock><StackPanel Orientation="Horizontal"><!-- 关键修改:替换为 IconButton --><IconButton IconText="&#xEC54;" Content="Clear Cache" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton><IconButton IconText="&#xE5DE;" Content="Export Cache" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton><IconButton IconText="&#xE20C;" Content="Import Cache" Grid.Column="1" HorizontalAlignment="Stretch"></IconButton></StackPanel></StackPanel></StackPanel></Grid>
</UserControl>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/913692.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二手站网站怎做韩国外贸平台

在达梦数据库系统中&#xff0c;死锁是指两个或多个事务相互等待对方释放资源&#xff0c;从而造成循环等待的现象&#xff0c;严重影响数据库的正常运行。以下是使用达梦数据库进行死锁排查和解决的具体步骤&#xff1a; 死锁查看 查询当前死锁信息 SELECT lc.lmode, lc.ta…

网站建设比赛方案阿里巴巴网站架构

大家都知道&#xff0c;在Mac上进行文件拖拽是一件非常方便的事情。然而&#xff0c;随着我们在工作和生活中越来越多地使用电脑&#xff0c;我们对于这个简单操作的需求也越来越高。为了让您的文件拖拽体验更加高效和便捷&#xff0c;今天我们向大家介绍一款强大的工具——Dro…

南宁建设厅网站是什么学校网站建设实训总结

91. 请描述一下Intent 和 IntentFilter ?Intent是组件的通讯使者,可以在组件间传递消息和数据。 IntentFilter是intent的筛选器,可以对intent的action,data,catgory,uri这些属性进行筛选,确定符合的目标组件🚀🚀🚀🚀🚀🚀92. 阐述什么是IntentService?有何优…

php网站开发技术前景品牌建设的最高境界是培育客户的

图片来源&#xff1a;Thomas Hainmller, Marlene Bartos来源&#xff1a;生物谷摘要&#xff1a;最近&#xff0c;一项刊登在国际杂志Nature上的研究报告中&#xff0c;来自弗莱堡大学的科学家们通过研究开发出了一种新型模型来解释大脑如何储存一些“有形事件”&#xff08;ta…

网站tkd优化如何鉴别网站有没有做301重定向

任何简单或复杂的算法都可以由三种基本结构组成&#xff1a;顺序结构&#xff0c;选择结构&#xff0c;循环结构。 顺序结构 比较一般的结构&#xff0c;程序从上到下执行。 选择结构 我们从最简单的单路选择开始&#xff0c;符合条件的进入语句序列&#xff0c;不符合条件的…

dedecms网站根目录重庆专业网站设计服务

题目&#xff1a; 给定一个包含 n 个整数的数组 nums 和一个目标值 target&#xff0c;判断 nums 中是否存在四个元素 a&#xff0c;b&#xff0c;c 和 d &#xff0c;使得 a b c d 的值与 target 相等&#xff1f;找出所有满足条件且不重复的四元组。 注意&#xff1a; …

网站设计策划方案wordpress 移动导航呼出

一、网络加密的方式及实现 1、常见的加密算法 常见的密钥加密算法类型大体可以分为三类:对称加密、非对称加密、单向加密。 对称加密算法采用单密钥加密&#xff0c;在通信过程中&#xff0c;数据发送方将原始数据分割成固定大小的块&#xff0c;经过密钥和加密算法逐个加密…

网站个人备案 企业备案提供手机网站制作哪家好

nvm安装后nvm -v有效&#xff0c;node指令无效 环境变量配置无问题 推荐方案 下载你需要的node版本 Index of /dist/ (nodejs.org) 下载后解压到你的nvm存储版本的位置 cmd进入切换你的使用版本&#xff08;此时你的nodejs是从网上下载的&#xff0c;npm文件是存在的&…

江门 网站设计wordpress添加留言板

3月25日vim相关操作 题目1&#xff1a; 1&#xff09;将/etc/hosts网络配置文件复制到/tmp/mydir下&#xff1b; 2&#xff09;使用vim编辑器打开hosts文件&#xff0c;按i进入编辑模式&#xff0c;将本机IP地址和主机名(client1)映射。 3&#xff09;按下esc键回到命令模式…

matter 协议的架构;

Matter 协议栈分为多个层级: 应用层:定义设备的业务逻辑(如门锁、灯光控制等)。 数据模型层:通过“集群(Cluster)”组织属性、命令和事件,确保不同厂商设备的互操作性。 交互模型层:定义客户端与服务端之间的…

matter 协议解析;

Matter 协议(原名 Project CHIP,Connected Home over IP)是由 Connectivity Standards Alliance (CSA) 推出的开源应用层标准,旨在为智能家居设备、移动应用和云服务之间提供统一的通信协议,实现不同厂商 IoT 设备…

相机标定(Camera Calibration)原理及步骤:从 “像素模糊” 到 “毫米精准” 的关键一步 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Nordic 的支持对Matter 协议的支持;

Nordic Semiconductor 提供全面的 Matter 解决方案,支持 nRF54LM20A、nRF54L15、nRF54L10、nRF52840、nRF5340 等 SoC,结合 nRF Connect SDK,可开发基于 Thread、Bluetooth LE 和 Wi-Fi 的 Matter 设备。Nordic 还为…

常州网站推广多少钱404网站页面进入

前言 看了大量的多源融合室内定位论文,都绕不开卡尔曼滤波和扩展卡尔曼滤波算法。相当经典,但是又缺少代码。 由于计算机专业不学这些算法,因此理解起来难度还有点大。因此业余抽空复现了下,话不多说,直接上代码。 蓝牙和IMU的卡尔曼滤波融合 from filterpy.kalman imp…

广东网站建设专业公司个人主页搭建

软件开发人员是具有创建软件程序的创意和技术技能的专业人员&#xff0c;是一个具有高回报和挑战性的职业选择。如今&#xff0c;软件开发人员几乎在每个行业工作。随着世界变得越来越数字化&#xff0c;越来越需要具有技术背景的人来创建特定的软件应用程序。 如果您考虑做一…

搭建一个网站的流程社区微网站建设方案ppt模板下载

[react] 说说你对Error Boundaries的理解 错误边界是React16新推出的一种错误处理的方式&#xff0c;在v16之前&#xff0c;React的抛错会导致页面显示的错误&#xff0c;v16修改这种方式成了组件如果产生了错误&#xff0c;那么从这个组件到根组件都会因为错误而崩溃掉&#…

企业网站无锡天津制作企业网站

大型语言模型&#xff08;LLM&#xff09;的兴起不仅为获取知识和解决问题开辟了新的可能性&#xff0c;而且催生了一些新型智能系统&#xff0c;例如旨在辅助用户完成特定任务的AI Copilot以及旨在自动化和自主执行复杂任务的AI Agent&#xff0c;使得编程、创作等任务变得高效…

优秀网站案例wordpress图片无法居中显示

最近发现好像写这种基础博客的很少&#xff0c;文章大部分都是几年前的&#xff0c;之前对于时间这块都是直接使用day.js 来处理&#xff0c;废话不多说&#xff0c;直接进入正题 const now new Date();//初始值 now.getFullYear()//年 now.getMonth() 1 //月 now.getDate()…

移动网站建设厂家北京商城网站开发

导语&#xff1a;工欲善其事&#xff0c;必先利其器&#xff1b;士欲宣其义&#xff0c;必先读其书。后台开发作为互联网技术领域的掌上明珠&#xff0c;一直都是开发者们的追逐的高峰。本文将从后台开发所涉及到的技术术语出发&#xff0c;基于系统开发、架构设计、网络通信等…

网站制作视频教程下载重庆网站建设培训班

1.前端的操作&#xff1a;对象接收json数据方式&#xff1a;将所需要传的数据转化为json数据&#xff0c;并将这些数据以post方式传到后台的controller层&#xff0c;然后controller层接收json数据&#xff0c;并且是以对象的形式进行接收。这里面是springmvc自动控制将这些数据…