WPF教程十:如何使用Style和Behavior在WPF中规范视觉样式
在使用WPF编写客户端代码时,我们会在VM下解耦业务逻辑,而剩下与功能无关的内容比如动画、视觉效果,布局切换等等在数量和复杂性上都超过了业务代码。而如何更好的简化这些编码,WPF设计人员使用了Style和Behavior来帮助我们构建一致性、组织性好的代码。
这一章的目的是理解我们使用行为和资源的目标。使用这2个内容使我们创建封装一些通用用户界面功能的行为。比如启动故事板,加入重力的动画效果,我们要把思维给打开,我们做的东西是为了通用,而不是为了业务,因为业务在这个时刻只存在于VM中。(即使个人能力所限,或者实际情况所限,V下面还是有业务代码。但是我们心中要有这个自信,我做WPF开发,那么在未来我也能设计出来堪比WPF这种优秀的的框架,如果没有自信和信心,别人一说就受到了打击,那么什么时间才能成为大佬,别说成为大佬了,可能自己慢慢的就放弃了把),跑题了,简单来说就是我们使用行为和样式设计出来可以添加到各种控件的通用效果。这里不想考虑更多的内容,比如自定义控件。
先讲样式和触发器,我们设计窗体只有暗色风格,在此风格下的按钮都是黑底白字。
1)什么是样式,先来段代码:
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior"
mc:Ignorable="d" Topmost="True" Background="#000000"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel Height="30" Orientation="Horizontal">
<Button Margin="3" Content="我是按钮A" Foreground="#F5FFFA" Background="#696969" BorderBrush="#2F4F4F"/>
<Button Margin="3" Content="我是按钮B" Foreground="#F5FFFA" Background="#696969" BorderBrush="#2F4F4F"/>
</StackPanel>
</Grid>
</Window>
实际效果如下图:
我们看到如果这里有N个按钮,那么所有的代码上都要写自己属性对应的样式。我们使用资源可以规划一些统一的样式。而统一的样式,就被我们放到了资源里面。我们一点一点改进我们的代码,修改代码如下。
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior"
mc:Ignorable="d" Topmost="True" Background="#000000"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2F4F4F"/>
<Setter Property="Margin" Value="3"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button Content="我是按钮A"/>
<Button Content="我是按钮B"/>
</StackPanel>
</Grid>
</Window>
我们看到了我们在Window节点的Resources下添加了一个Style,并且设置了TargetType为Button。在Button元素内,我删除了对应的代码。这个时候我们启动程序。发现程序的效果是一样的。那么这个时候我们在添加其他按钮,就自动使用了这个样式。
如果在使用Style的时候,不指定Key,那么所有加载了资源的元素都会默认使用这个资源。我们给Style指定一个Key,并设置一个Button的Style观察效果,代码如下:
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior"
mc:Ignorable="d" Topmost="True" Background="#000000"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button Style="{StaticResource DarkButtonStyle}" Content="我是按钮A"/>
<Button Content="我是按钮B"/>
</StackPanel>
</Grid>
</Window>
·
我们发现没有样式添加了Key之后,没有缺少Key的TargetType等于Button的资源后,没有引用Style的Button被修改回系统默认的了。而我们使用Style={StaticResource }资源的样式的Button外观就变成了我们资源中定义的。
样式中还有一个关键的点,是样式的继承。从一个样式中继承公共的部分后,可以实现自己特殊部分的样式,比如我们在继承DarkButtonStyle的样式实现一个警告的按钮的样式。假设统一的警告按钮风格是字体会更粗。我们需要添加一个新的样式继承自DarkButtonStyle并FontWeight属性,同时使警告的控件引用该样式,代码如下:
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior" Background="#000000"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
</Style>
<Style x:Key="WarningDarkButtonStyle" TargetType="Button" BasedOn="{StaticResource DarkButtonStyle}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button Content="我是按钮A" Style="{StaticResource DarkButtonStyle}"/>
<Button Content="我是按钮B" Style="{StaticResource WarningDarkButtonStyle}"/>
</StackPanel>
</Grid>
</Window>
这样我们就实现了样式的继承,但是代码中,为了通用,还是尽量减少样式的继承,因为要改动代码的话,涉及的一旦包含继承关系,在修改外观时就需要考虑改动样式资源带来的影响,但是会让长期稳定迭代的代码更加结构化。一般都是一个控件的几种形态,建议用样式的继承。
2)什么是触发器。
我们在控件引用资源后,我们发现虽然外观修改了,但是鼠标经过,等其他事件时,控件依然没有对应我们要的风格。为了简化对应的事件代码,WPF提出了触发器的概念,在这里我们可以使用触发器来方便的维护控件的外观。
我们在前面代码的基础上添加触发器,如果按钮被禁用,则修改前景色为红色:
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior" Background="#000000"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="WarningDarkButtonStyle" TargetType="Button" BasedOn="{StaticResource DarkButtonStyle}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button x:Name="AButton" Content="我是按钮A" Style="{StaticResource DarkButtonStyle}"/>
<Button Content="我是按钮B" Style="{StaticResource WarningDarkButtonStyle}" Click="SetButtonADisableButton_OnClick"/>
</StackPanel>
</Grid>
</Window>
using System.Windows; namespace StyleAndBehavior
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void SetButtonADisableButton_OnClick(object sender, RoutedEventArgs e)
{
AButton.IsEnabled = false;
}
}
}
从这个代码中,我们看到了当我们点击按钮B时,按钮A的被设置了Disable无法使用,同时前景色被改成了白色(背景色的变化我们目前先不关注。后面会讲样式的重写,这里只关注我们前景色的变化)。
我们在资源上尝试添加其他触发器,完整代码如下,就会发现触发器可以帮助我们通过监听属性的变化直接修改样式。我们的Button获取焦点,和单击按下后,前景色都会发生变化。
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior" Background="#000000"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Yellow"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="WarningDarkButtonStyle" TargetType="Button" BasedOn="{StaticResource DarkButtonStyle}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button x:Name="AButton" Content="我是按钮A" Style="{StaticResource DarkButtonStyle}"/>
<Button Content="我是按钮B" Style="{StaticResource WarningDarkButtonStyle}" Click="SetButtonADisableButton_OnClick"/>
</StackPanel>
</Grid>
</Window>
还有一种是满足多个属性同时变更要求的触发器,MultiTriggers。使用这个可以监听多个属性的变化满足条件时设置对应触发器绑定的属性。
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior" Background="#000000"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Yellow"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Foreground" Value="Orange"/>
</MultiTrigger>
</Style.Triggers>
</Style>
<Style x:Key="WarningDarkButtonStyle" TargetType="Button" BasedOn="{StaticResource DarkButtonStyle}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button x:Name="AButton" Content="我是按钮A" Style="{StaticResource DarkButtonStyle}"/>
<Button Content="我是按钮B" Style="{StaticResource WarningDarkButtonStyle}" Click="SetButtonADisableButton_OnClick"/>
</StackPanel>
</Grid>
</Window>
我们使用了MultiTrigger来实现多属性变化的触发器,用来设置对应场景下的UI变化。我们这里设置了前景色为橙色。
因为还没有讲到MVVM所以还有一个DataTrigger这里就先不讲了。后面写自定义控件时通过MVVM会讲到这个DataTrigger的使用。原理是一样的。只是使用DataTrigger绑定时监听的时VM对象下的属性。
接下来是事件触发器。事件触发器需要传入一个故事板对象,我们可以使用事件触发器来实现一个鼠标移入时字体慢慢变大, 鼠标移出时字体慢慢变小的动画效果。
代码已经实现了,但是因为最近搬家写代码用的电脑不一样,这个电脑没有录屏软件,所以实际效果没法录屏,复制代码跑起来看看啦。
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior" Background="#000000"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="DarkButtonStyle" TargetType="Button">
<Setter Property="Foreground" Value="#F5FFFA" />
<Setter Property="Background" Value="#696969"/>
<Setter Property="BorderBrush" Value="#2f4f4f"/>
<Setter Property="Margin" Value="3"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Red" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="Blue"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Yellow"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Foreground" Value="Orange"/>
</MultiTrigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard >
<Storyboard>
<DoubleAnimation Duration="0:0:1.0" Storyboard.TargetProperty="FontSize" To="22"> </DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:1.0" Storyboard.TargetProperty="FontSize" To="12"></DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions> </EventTrigger>
</Style.Triggers>
</Style>
<Style x:Key="WarningDarkButtonStyle" TargetType="Button" BasedOn="{StaticResource DarkButtonStyle}">
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<Button x:Name="AButton" Content="我是按钮A" Style="{StaticResource DarkButtonStyle}"/>
<Button Content="我是按钮B" Style="{StaticResource WarningDarkButtonStyle}" Click="SetButtonADisableButton_OnClick"/>
</StackPanel>
</Grid>
</Window>
到了这一个章节更为关键的内容了,行为的使用。
对于行为,很多人学的很迷糊,我之前也是。就是拿行为绑定几个命令到后台的VM上。其他的大部分场景都没有用过了。导致无法发挥出来WPF设计人员设计行为的优势,这里我们也尝试自己写一下行为。
对行为的支持被放到了System.Windows.Interactivity.dll中。他是使用行为的基础。行为主要是为了封装一些UI功能,从而可以不必编写代码就能够把行为应用到元素上。举个例子,我们实现一个TextBox的输入水印效果。
我们新建一个类库工程起名叫做CustomBehaviorLibrary。来存放我们的行为,通过在该工程上右键=》管理Nuget程序包=》搜索System.Windows.Interactivity.WPF并安装。如果使用WPF下的控件,注意必须要同时有PresentationCore、PresentationFramework、WindwsBase这三个库的引用。缺少的可以Alt+Enter手动引用一下。
我们创建TextBoxWatermarkBehavior类,并继承自Behavior类,我们在Behavior上右键F12,看到里面有一个AssociatedObject名字的对象,这个就是我们要用来添加行为的对象。我们先使用propdp添加名字为Watermark的string类型的依赖项属性。用来作为我们的水印显示文本。
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media; namespace CustomBehaviorLibrary
{
public class TextBoxWatermarkBehavior : Behavior<TextBox>
{
private bool _hasContent = true;
public string Watermark
{
get { return (string)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
} // Using a DependencyProperty as the backing store for Watermark. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WatermarkProperty =
DependencyProperty.Register("Watermark", typeof(string), typeof(TextBoxWatermarkBehavior), new PropertyMetadata(default(string))); protected override void OnAttached()
{
base.OnAttached();
var textbox = AssociatedObject;
textbox.Loaded += Textbox_Loaded;
} protected override void OnDetaching()
{
base.OnDetaching();
}
private void Textbox_Loaded(object sender, RoutedEventArgs e)
{
var textbox = sender as TextBox;
if (string.IsNullOrEmpty(textbox.Text))
{
textbox.Foreground = Brushes.Gray;
textbox.Text = Watermark;
_hasContent = false;
}
textbox.GotFocus -= Textbox_GotFocus;
textbox.LostFocus -= Textbox_LostFocus;
textbox.GotFocus += Textbox_GotFocus;
textbox.LostFocus += Textbox_LostFocus;
} private void Textbox_LostFocus(object sender, RoutedEventArgs e)
{
var textbox = sender as TextBox;
if (string.IsNullOrEmpty(textbox.Text))
{
_hasContent = false;
textbox.Text = Watermark;
textbox.Foreground = Brushes.Gray;
}
else
{
_hasContent = true;
}
} private void Textbox_GotFocus(object sender, RoutedEventArgs e)
{
var textbox = sender as TextBox;
if (!_hasContent)
{
textbox.Text = "";
textbox.Foreground = Brushes.Black;
}
}
}
}
这样我们的行为就创建好了,这个时候,我们在主工程下使用这个行为。
1)主工程添加对CustomBehaviorLibrary工程的引用;
2)主工程在NuGet添加对System.Windows.Interactivity.WPF的引用。
3)注意在使用的窗体下添加命名空间
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:customBehavior="clr-namespace:CustomBehaviorLibrary;assembly=CustomBehaviorLibrary"
4)添加TextBox控件,并添加Interactivity下的Behaviors。 在Behaviors中添加我们自定义的TextBoxWatermarkBehavior 并设置我们添加的依赖项属性。设置水印内容。代码如下:
<Window x:Class="StyleAndBehavior.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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:local="clr-namespace:StyleAndBehavior"
mc:Ignorable="d" Topmost="True" Background="#000000"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:customBehavior="clr-namespace:CustomBehaviorLibrary;assembly=CustomBehaviorLibrary"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel VerticalAlignment="Top" Height="30" Orientation="Horizontal">
<TextBox MinWidth="200">
<i:Interaction.Behaviors>
<customBehavior:TextBoxWatermarkBehavior Watermark="我是水印,请输入内容"/>
</i:Interaction.Behaviors>
</TextBox>
<TextBox MinWidth="200">
<i:Interaction.Behaviors>
<customBehavior:TextBoxWatermarkBehavior Watermark="我是另外一个TextBox水印,请输入内容"/>
</i:Interaction.Behaviors>
</TextBox>
</StackPanel>
</Grid>
</Window>
这样我们就完成了对行为的使用。这里写的比较简单,其实还有很多相关的知识可以扩展,因为行为是一个比较独立的内容,所以单独在行为中可以扩展的通用的东西特别多。而i:Interaction.Triggers也是在这里的,但是我之前都是直接绑定VM下的Command所以这个等讲到VM和Command的时候在讲这个吧用法是一样的。目前这一章就讲这么多,行为这里配置和引用稍微复杂了一些,但是学习是一个持续的过程,每天进步一点,掌握这个知识点,不要急,WPF的知识就那么多,每天投入一点,几年时间慢慢的也就精通了。
我创建了一个C#相关的交流群。用于分享学习资料和讨论问题。欢迎有兴趣的小伙伴:QQ群:542633085
WPF教程十:如何使用Style和Behavior在WPF中规范视觉样式的更多相关文章
- WPF教程十二:了解自定义控件的基础和自定义无外观控件
这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...
- WPF教程十五:数据模板的使用(重发)
数据模板 数据模板是一段如何显示绑定在VM对象的XAML代码.数据模板可以包含任意元素的组合,基于Binding来显示不同的信息. 在实际的开发中数据模板的应用场景很多,同样一个控件可以根据不同的绑定 ...
- WPF教程十四:了解元素的渲染OnRender()如何使用
上一篇分析了WPF元素中布局系统的MeasureOverride()和ArrangeOverride()方法.本节将进一步深入分析和研究元素如何渲染它们自身. 大多数WPF元素通过组合方式创建可视化外 ...
- WebGL简易教程(十四):阴影
目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 3. 结果 4. 参考 ...
- 无废话ExtJs 入门教程十九[API的使用]
无废话ExtJs 入门教程十九[API的使用] extjs技术交流,欢迎加群(201926085) 首先解释什么是 API 来自百度百科的官方解释:API(Application Programmin ...
- 无废话ExtJs 入门教程十六[页面布局:Layout]
无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...
- 无废话ExtJs 入门教程十五[员工信息表Demo:AddUser]
无废话ExtJs 入门教程十五[员工信息表Demo:AddUser] extjs技术交流,欢迎加群(201926085) 前面我们共介绍过10种表单组件,这些组件是我们在开发过程中最经常用到的,所以一 ...
- 无废话ExtJs 入门教程十四[文本编辑器:Editor]
无废话ExtJs 入门教程十四[文本编辑器:Editor] extjs技术交流,欢迎加群(201926085) ExtJs自带的编辑器没有图片上传的功能,大部分时候能够满足我们的需要. 但有时候这个功 ...
- 无废话ExtJs 入门教程十二[下拉列表联动:Combobox_Two]
无废话ExtJs 入门教程十二[下拉列表联动:Combobox_Two] extjs技术交流,欢迎加群(201926085) 不管是几级下拉列表的联动实现本质上都是根据某个下拉列表的变化,去动态加载其 ...
随机推荐
- Pycharm搜索导航之文件名、符号名搜索
1.准备一个工程 向你的工程中添加一个Python文件,并输入一些源码,例如: 2.转到对应文件.类.符号 Pycharm提供的一个很强力的功能就是能够根据名称跳转到任何文件.类.符号所在定义位置. ...
- 拉仇恨!webhook + 企业微信给同事做了个代码提交监听工具
本文案例收录在 https://github.com/chengxy-nds/Springboot-Notebook 大家好,我是小富~ 最近接个任务,用webhook做了个代码提交监听功能,就是有人 ...
- 干货:ANR日志分析全面解析
一.概述 解决ANR一直是Android 开发者需要掌握的重要技巧,一般从三个方面着手. 开发阶段:通过工具检查各个方法的耗时,卡顿情况,发现一处修改一处. 线上阶段:这个阶段主要依靠监控工具发现AN ...
- A100计算能力
A100计算能力 A100 GPU支持新的计算功能8.0.表1比较了NVIDIA GPU架构的不同计算功能的参数. 表1.计算能力:GP100 vs. GV100 vs. GA100. MIG架构 尽 ...
- 基于TensorRT的BERT实时自然语言理解(下)
基于TensorRT的BERT实时自然语言理解(下) BERT Inference with TensorRT 请参阅Python脚本bert_inference.py还有详细的Jupyter not ...
- Firfox、Chrome之python-selenium环境搭建
公共步骤: 一.文件下载 下载地址: python安装包:https://www.python.org/getit/ PyCharm 安装包:http://www.jetbrains.com/pych ...
- .NET平台系列26:在 Windows 上安装 .NET Core/.NET5/.NET6
系列目录 [已更新最新开发文章,点击查看详细] 本文介绍如何在 Windows 上安装 .NET. .NET 由运行时和 SDK 组成. 运行时用于运行 .NET 应用,应用可能包含也可能不包 ...
- vue keep-alive从列表页进入详情页,再返回列表页时,还是之前滚动的位置
//router.js { path: '/oppo-music', component: () => import('@/views/OppoMusic.vue'), meta: { titl ...
- 大家看看大佬对Maven仓库的讲解,有何高明之处?
Maven在某个统一的位置存储所有项目的共享的构件,这个统一的位置,我们就称之为仓库.(仓库就是存放依赖和插件的地方). 分类 maven的仓库只有两大类:1.本地仓库 2.远程仓库,在远程仓库中又分 ...
- 【题解】PIZZA 贪心
题目描述 Michael请N个朋友吃馅饼,但是每个朋友吃且仅吃一个馅饼的1/4.1/2或3/4.请你编程求出Michael至少需要买多少个馅饼. 输入输出格式 输入格式: 输入文件的第一行是整数N:接 ...