在使用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中规范视觉样式的更多相关文章

  1. WPF教程十二:了解自定义控件的基础和自定义无外观控件

    这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...

  2. WPF教程十五:数据模板的使用(重发)

    数据模板 数据模板是一段如何显示绑定在VM对象的XAML代码.数据模板可以包含任意元素的组合,基于Binding来显示不同的信息. 在实际的开发中数据模板的应用场景很多,同样一个控件可以根据不同的绑定 ...

  3. WPF教程十四:了解元素的渲染OnRender()如何使用

    上一篇分析了WPF元素中布局系统的MeasureOverride()和ArrangeOverride()方法.本节将进一步深入分析和研究元素如何渲染它们自身. 大多数WPF元素通过组合方式创建可视化外 ...

  4. WebGL简易教程(十四):阴影

    目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 3. 结果 4. 参考 ...

  5. 无废话ExtJs 入门教程十九[API的使用]

    无废话ExtJs 入门教程十九[API的使用] extjs技术交流,欢迎加群(201926085) 首先解释什么是 API 来自百度百科的官方解释:API(Application Programmin ...

  6. 无废话ExtJs 入门教程十六[页面布局:Layout]

    无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...

  7. 无废话ExtJs 入门教程十五[员工信息表Demo:AddUser]

    无废话ExtJs 入门教程十五[员工信息表Demo:AddUser] extjs技术交流,欢迎加群(201926085) 前面我们共介绍过10种表单组件,这些组件是我们在开发过程中最经常用到的,所以一 ...

  8. 无废话ExtJs 入门教程十四[文本编辑器:Editor]

    无废话ExtJs 入门教程十四[文本编辑器:Editor] extjs技术交流,欢迎加群(201926085) ExtJs自带的编辑器没有图片上传的功能,大部分时候能够满足我们的需要. 但有时候这个功 ...

  9. 无废话ExtJs 入门教程十二[下拉列表联动:Combobox_Two]

    无废话ExtJs 入门教程十二[下拉列表联动:Combobox_Two] extjs技术交流,欢迎加群(201926085) 不管是几级下拉列表的联动实现本质上都是根据某个下拉列表的变化,去动态加载其 ...

随机推荐

  1. 【JDK命令行 一】手动编译Java源码与执行字节码命令合集(含外部依赖引用)

    写作目标 记录常见的使用javac手动编译Java源码和java手动执行字节码的命令,一方面用于应对 Maven 和 Gradle 暂时无法使用的情况,临时生成class文件(使用自己的jar包):另 ...

  2. 【三】Kubernetes学习笔记-Pod 生命周期与 Init C 介绍

    一.容器生命周期 Init C(初始化容器)只是用于 Pod 初始化的,不会一直随着 Pod 生命周期存在,Init C 在初始化完成之后就会死亡. 一个 Pod 可以有多个 Init C,也可以不需 ...

  3. Django部署uwsgi 与 nginx配置

    1.nginx文件的配置 路径:/etc/nginx/conf.d/ example.conf 启动:service nginx [start]/[restart]/[stop] upstream d ...

  4. KVO后[obj class]与object_getClass(id obj)的结果竟会不一致?

    说说背景,研究下面的代码时,KVO后[obj class]与object_getClass(id obj)的结果竟会不一致? PersonModel *aPersonModel = [[PersonM ...

  5. java中存储mysql数据库时间类型【date、time、datetime、timestamp】

    在MySQL中对于时间的存储自己见表的时候都是设置的varchar类型的,感觉挺方便的. 昨天拿别人建好的表写代码,发现这张表中时间类型为datetime的,凭感觉试了一下不行,网上查了刚开始试了好几 ...

  6. SQL Server 动态创建表结构

    需求是,在word里面设计好表结构(主要在word中看起来一目了然,方便维护),然后复制sql 里面,希望动态创建出来 存储表结构的表 CREATE TABLE [dbo].[Sys_CreateTa ...

  7. lms框架应用服务接口和服务条目详解

    目录 应用接口的定义 服务路由特性 服务条目 根据服务条目生成webAPI 服务条目的治理特性 缓存拦截 服务条目的例子 应用接口的实现 开源地址与文档 应用接口的定义 服务应用接口是微服务定义web ...

  8. 台积电5nm光刻技术

    台积电5nm光刻技术 在IEEE IEDM会议上,台积电发表了一篇论文,概述了其5nm工艺的初步成果.对于目前使用N7或N7P工艺的客户来说,下一步将会采用此工艺,因为这两种工艺共享了一些设计规则.新 ...

  9. ONNX 实时graph优化方法

    ONNX 实时graph优化方法 ONNX实时提供了各种图形优化来提高模型性能.图优化本质上是图级别的转换,从小型图简化和节点消除,到更复杂的节点融合和布局优化. 图形优化根据其复杂性和功能分为几个类 ...

  10. Single Shot Multibox Detection (SSD)实战(下)

    Single Shot Multibox Detection (SSD)实战(下) 2. Training 将逐步解释如何训练SSD模型进行目标检测. 2.1. Data Reading and In ...