样式和模板
NoesisGUI的样式和模板是指一组功能(样式,模板,触发器和情节提要),这些功能使开发人员和设计人员可以创建引人注目的视觉效果并为其产品创建一致的外观。尽管开发人员和/或设计人员可以在逐个应用程序的基础上广泛地自定义外观,但是必须使用强大的样式和模板模型才能在应用程序内和应用程序之间进行维护和共享。NoesisGUI提供了该模型。
样式
由Style类表示的样式是一个非常简单的实体。它的主要功能是将可以单独设置的属性值组合在一起。您可以在多个元素之间共享这组值。
StylingTutorialImg1.jpg通过设置六个属性来自定义上一幅图像中的文本。如果没有Style,则需要在所有文本上重复这些相同的分配,如下所示:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBlock Text="John Doe" FontSize="18" FontWeight="Bold"
Foreground="Crimson" Background="LightYellow" Padding="20,5" Margin="5"/>
<TextBlock Text="251 Amazing Road" FontSize="18" FontWeight="Bold"
Foreground="Crimson" Background="LightYellow" Padding="20,5" Margin="5"/>
<TextBlock Text="Great City, ST 23145" FontSize="18" FontWeight="Bold"
Foreground="Crimson" Background="LightYellow" Padding="20,5" Margin="5"/>
<TextBlock Text="(555) 123.4224" FontSize="18" FontWeight="Bold"
Foreground="Crimson" Background="LightYellow" Padding="20,5" Margin="5"/>
</StackPanel>
但是,使用Style,可以添加一个间接级别,将它们设置在一个位置,并将每个TextBlock指向该新元素,如以下代码片段所示。
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel.Resources>
<Style x:Key="TextStyle">
<Setter Property="TextBlock.FontSize" Value="18"/>
<Setter Property="TextBlock.FontWeight" Value="Bold"/>
<Setter Property="TextBlock.Foreground" Value="Crimson"/>
<Setter Property="TextBlock.Background" Value="LightYellow"/>
<Setter Property="TextBlock.Padding" Value="20,5"/>
<Setter Property="TextBlock.Margin" Value="5"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="John Doe" Style="{StaticResource TextStyle}"/>
<TextBlock Text="251 Amazing Road" Style="{StaticResource TextStyle}"/>
<TextBlock Text="Great City, ST 23145" Style="{StaticResource TextStyle}"/>
<TextBlock Text="(555) 123.4224" Style="{StaticResource TextStyle}"/>
</StackPanel>
样式使用设置器的集合来设置目标属性。创建Setter只是指定依赖项属性的名称及其所需值。
如果要强制将样式仅应用于特定类型,则可以相应地设置其TargetType属性。而且,您不再需要在Setters中的属性名称前面加上类型名称。将TargetType应用于样式还为您提供了另一个功能。如果省略其Key,则Style将隐式应用于同一范围内该目标类型的所有元素。与命名样式相反,这通常称为键入样式。键入的样式的范围由样式资源的位置确定。
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="Crimson"/>
<Setter Property="Background" Value="LightYellow"/>
<Setter Property="Padding" Value="20,5"/>
<Setter Property="Margin" Value="5"/>
</Style>
</StackPanel.Resources>
<TextBlock Text="John Doe"/>
<TextBlock Text="251 Amazing Road"/>
<TextBlock Text="Great City, ST 23145"/>
<TextBlock Text="(555) 123.4224"/>
</StackPanel>
样式还可以通过使用触发器,根据一个或多个条件定义元素的某些值。例如,如果我们希望文本更改其前景色并在鼠标指针悬停时向右移动一点,我们将添加以下代码:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="Crimson"/>
<Setter Property="Background" Value="LightYellow"/>
<Setter Property="Padding" Value="20,5"/>
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="Margin" Value="10,5,0,5"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Text="John Doe"/>
<TextBlock Text="251 Amazing Road"/>
<TextBlock Text="Great City, ST 23145"/>
<TextBlock Text="(555) 123.4224"/>
</StackPanel>
更好的是,我们可以使用一些动画使过渡更加平滑。这要归功于EnterActions和ExitActions触发器属性。
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="18"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="Crimson"/>
<Setter Property="Background" Value="LightYellow"/>
<Setter Property="Padding" Value="20,5"/>
<Setter Property="Margin" Value="5"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.1" To="Blue"
Storyboard.TargetProperty="Foreground.Color"/>
<ThicknessAnimation Duration="0:0:0.1" To="10,5,0,5"
Storyboard.TargetProperty="Margin"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Duration="0:0:0.2" To="Crimson"
Storyboard.TargetProperty="Foreground.Color"/>
<ThicknessAnimation Duration="0:0:0.2" To="5"
Storyboard.TargetProperty="Margin"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBlock Text="John Doe"/>
<TextBlock Text="251 Amazing Road"/>
<TextBlock Text="Great City, ST 23145"/>
<TextBlock Text="(555) 123.4224"/>
</StackPanel>
image.png
范本
模板使您可以用可以想象的任何东西完全替换控件的可视树,同时保持其所有功能不变。每个控件的源代码都与它的默认可视化树表示形式完全分开。控件模板由ControlTemplate类表示,该类从抽象FrameworkTemplate类派生而来,该抽象FrameworkTemplate类定义了VisualTree内容属性,即,指定了控件所需外观的元素树。
接下来,我们将使用模板来重新设计公共Button控件的外观。
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse Stroke="Black" Fill="Silver"/>
</Grid>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource ButtonTemplate}" Width="100" Height="100" Content="Rounded!"/>
</Grid>
现在,我们有了一个代表按钮的简单圆圈,尽管内容(在这种情况下为文本)消失了。如果要创建可广泛使用的控件模板,则需要做一些工作以尊重目标控件的各种属性。我们可以在控件模板中添加一个TextBlock,并使用数据绑定来显示Button的内容。当然,Button可以包含非文本Content,因此使用TextBlock进行显示会造成人为的限制。为了确保所有类型的Content都能正确显示在模板中,我们可以使用ContentPresenter,它是专门为此目的设计的。
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse Stroke="Black" Fill="Silver"/>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource ButtonTemplate}" Width="100" Height="100" Content="Rounded!"/>
</Grid>
使用此模板,按钮失去了一些交互性反馈,用户没有视觉参考,无法知道按钮是否响应鼠标输入。与样式一样,模板可以使触发器具体化,因此我们将使用它们为按钮的不同状态生成不同的表示形式。
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse x:Name="Circle" Stroke="Black" Fill="Silver"/>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Red"/>
<Setter TargetName="Circle" Property="Fill" Value="Pink"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Green"/>
<Setter TargetName="Circle" Property="Fill" Value="PaleGreen"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource ButtonTemplate}" Width="100" Height="100" Content="Rounded!"/>
</Grid>
StylingTutorialImg3.jpg
在本节的开头,我们解释了控件是无外观的并且具有完全独立于其外观的实现。但这并非完全正确。一些控件具有内置逻辑,这些逻辑仅基于其可视树中某些元素的存在而适用。要找到它们,它会以PART_XXX的形式查找特定的名称,有时还会查找特定的类型。如果找到了此类元素,则会对其施加额外的行为。每个控件的特定名称和行为都不同。
例如,如果一个进度控制模板具有命名的元素PART_Indicator和PART_Track,控制确保的宽度PART_Indicator保持的正确的百分比PART_Track的宽度,基于进度的值,最小和最大的特性。
主题
尽管为简单起见,到目前为止,所有控件模板都直接应用于元素,但更常见的是在Style内设置Control的Template属性,然后将该风格应用于所需的元素。除了将模板与任意属性设置组合在一起的便利之外,这样做还具有重要的优点:
- 它为您提供了默认模板的效果。例如,当默认情况下将类型化的样式应用于元素,并且该样式包含自定义控件模板时,将在不对那些元素进行任何显式标记的情况下应用它。
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse x:Name="Circle" Stroke="Black" Fill="Silver"
Width="100" Height="50"/>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Red"/>
<Setter TargetName="Circle" Property="Fill" Value="Pink"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Green"/>
<Setter TargetName="Circle" Property="Fill" Value="PaleGreen"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
</Style>
</StackPanel.Resources>
<Button Content="First"/>
<Button Content="Second" Margin="0,5"/>
<Button Content="Third"/>
</StackPanel>
StylingTutorialImg4.jpg
- 它还使您能够提供控制模板外观的默认但可覆盖的属性值。换句话说,它使您能够尊重模板化父级的属性,但仍提供自己的默认值。
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse x:Name="Circle"
Stroke="{TemplateBinding BorderBrush}"
Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
Content="{TemplateBinding Content}"
Margin="{TemplateBinding Padding}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Red"/>
<Setter TargetName="Circle" Property="Fill" Value="Pink"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Circle" Property="Stroke" Value="Green"/>
<Setter TargetName="Circle" Property="Fill" Value="PaleGreen"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Background" Value="Silver"/>
<Setter Property="Padding" Value="10"/>
<Setter Property="Template" Value="{StaticResource ButtonTemplate}"/>
</Style>
</StackPanel.Resources>
<Button Content="First"/>
<Button Content="Second" Margin="0,5"/>
<Button Content="Third" BorderBrush="Blue" Background="SkyBlue" Padding="30"/>
</StackPanel>
StylingTutorialImg5.jpg
全局风格
Noesis为所有控件提供了一个简约的默认主题。如果您想更改应用程序的外观,我们建议创建一个ResourceDictionary,其中包含应用程序中出现的所有控件的样式和模板。可以在初始化时通过以下操作全局设置此字典:
C ++
Ptr<ResourceDictionary> style = Noesis::GUI::LoadXaml<ResourceDictionary>("MyStyle.xaml");
Noesis::GUI::SetApplicationResources(style);
C#
ResourceDictionary style = (ResourceDictionary)Noesis.GUI.LoadXaml("MyStyle.xaml");
Noesis.GUI.SetApplicationResources(style);
注意
在Unity中,此属性在“ Noesis设置”面板中显示为“应用程序资源”
使用应用程序框架时,可以将应用程序的Resources属性用于相同的目的。MergedDictionaries是用于将整个XAML添加到目标字典的有用属性。
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="XamlPlayer.App" StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="AquaStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Resources scoped at the Application level should be defined here. -->
<SolidColorBrush x:Key="Background0" Color="#FF2F3F4F" />
<SolidColorBrush x:Key="Background1" Color="SlateGray" />
<SolidColorBrush x:Key="Foreground0" Color="White" />
<SolidColorBrush x:Key="Foreground1" Color="SkyBlue" />
<SolidColorBrush x:Key="Foreground2" Color="Black" />
<SolidColorBrush x:Key="Border" Color="LightSlateGray" />
</ResourceDictionary>
</Application.Resources>
</Application>
注意
样式编写起来很复杂,需要时间才能获得所需的结果。NoesisGUI中提供了几种样式以供参考
局部样式
FrameworkElement是控件继承的基类,它具有Resources属性,可用于添加本地资源。下面的示例显示三个按钮,每个按钮具有不同的样式。
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Nocturnal Style" Width="200" Height="60" Margin="0,5">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/NocturnalStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Button.Resources>
</Button>
<Button Content="Agile Style" Width="200" Height="60" Margin="0,5">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/AgileStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Button.Resources>
</Button>
<Button Content="Windows Style" Width="200" Height="60" Margin="0,5">
<Button.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/WindowsStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Button.Resources>
</Button>
</StackPanel>
StylingTutorialImg6.jpg
注意
尽可能避免使用局部样式。如果在本地字典中找不到请求的资源,则下一步查找是检查全局字典。这是将由多个页面引用的所有特定于应用程序的资源放入应用程序导航结构的最佳位置。
控件只能在其Style属性中设置一种样式,因此,如果需要局部覆盖一些属性,请记住以局部样式定义BasedOn,以从全局字典中定义的样式继承其余属性。如果省略BasedOn,则属性值将回退到Noesis主题定义的默认样式。
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<Style x:Key="BigButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="30"/>
<Setter Property="Padding" Value="20,10"/>
</Style>
<Style x:Key="RedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BigButtonStyle}">
<Setter Property="Background" Value="Red"/>
</Style>
<Style x:Key="BlueButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BigButtonStyle}">
<Setter Property="Background" Value="Blue"/>
</Style>
<ControlTemplate x:Key="CircularButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"/>
</Grid>
</ControlTemplate>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Template" Value="{StaticResource CircularButtonTemplate}"/>
</Style>
</Grid.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Button"/>
<Button Content="Red Button" Style="{StaticResource RedButtonStyle}" Margin="0,10"/>
<Button Content="Blue Button" Style="{StaticResource BlueButtonStyle}"/>
</StackPanel>
</Grid>
StylingTutorialImg7.jpg
请注意,BigButtonStyle是基于Button以前定义的任何键入样式的。这通常是指全局词典中定义的样式。
在BigButtonStyle之前将Button的本地定义的键入样式移动到该样式,将使示例中的所有按钮都继承自该样式。
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid.Resources>
<ControlTemplate x:Key="CircularButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"/>
</Grid>
</ControlTemplate>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Template" Value="{StaticResource CircularButtonTemplate}"/>
</Style>
<Style x:Key="BigButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="30"/>
<Setter Property="Padding" Value="20,10"/>
</Style>
<Style x:Key="RedButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BigButtonStyle}">
<Setter Property="Background" Value="Red"/>
</Style>
<Style x:Key="BlueButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource BigButtonStyle}">
<Setter Property="Background" Value="Blue"/>
</Style>
</Grid.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="Button"/>
<Button Content="Red Button" Style="{StaticResource RedButtonStyle}" Margin="0,10"/>
<Button Content="Blue Button" Style="{StaticResource BlueButtonStyle}"/>
</StackPanel>
</Grid>
StylingTutorialImg8.jpg
网友评论