简单易学 图文并茂 VB制作WPF自定义控件 范例1
- 格式:pdf
- 大小:420.26 KB
- 文档页数:7
vb用户控件制作讲解与实例1.定义控件的属性、事件和方法,其中属性是最常使用的。
2.保存和读取中间用户设置的属性值。
3.为达到你的预定目的而调用的各种技术手段。
在用户控件中定义的属性、事件、方法,其性质都必须是公用的,也就是说,只有用Public 来定义,这样你才能在主程序代码中使用这些事件和方法,以及设置或获取这些属性值,也只有公用的属性才会在窗体页面相关控件的属性窗口显示出来。
一、属性属性是用户控件最基本的东东,用户控件可以没有事件,可以没有方法,但不能没有属性(当然,技术上来说是可以没有属性的,但这样的控件使中间用户无法进行任何设置,是没有什么意义的)。
那么,如何定义用户控件的属性呢?为用户控件添加属性有两种办法:1.公用变量法:public 变量名称as 类型这里的变量名称就是属性名称。
这样定义的属性一般不会保存属性值,所以常常用作只读属性,在笔者的用户控件中,用于对主程序返回一个必要的值。
例如“四则运算”控件中的“ComputeAnswer”属性:Public ComputeAnswer As String它返回的是计算结果,而计算结果是不需要保存在控件中的,所以把它用公用变量法定义。
再例如消息框控件中的FeedValue 属性:Public FeedValue As Integer '返回值它返回最终用户选中的消息框按纽的编号,这个编号也只需要在主程序中处理,而无需保存在控件中,所以也用公用变量法定义成只读属性。
2.property 过程法:public property Get 过程名称() as 类型……end propertypublic property Let 过程名称(new值as 类型)……end property这里的过程名称就是属性名称。
而property 过程法又有两种:一种是如上所述的标准过程法,另一种就是枚举法。
㈠标准过程法这是用得最多的一种属性定义方法。
wpf 创建用户控件实例的方法摘要:1.WPF 用户控件概述2.创建用户控件实例的方法3.用户控件的属性与事件4.实例:创建一个简单的用户控件5.总结正文:**WPF 创建用户控件实例的方法**在WPF(Windows Presentation Foundation)中,创建用户控件实例的方法有以下几种:**1.WPF 用户控件概述**WPF 用户控件是一种自定义控件,它允许开发者根据需求创建具有特定功能的控件。
用户控件可以在应用程序中重用,从而提高代码的可维护性和可读性。
**2.创建用户控件实例的方法**在WPF 项目中,创建用户控件有以下几种常用方法:(1)使用Visual Studio 创建用户控件:1.在解决方案资源管理器中,右键单击项目名称,选择“添加”>“类”。
2.在弹出的命名窗口中,输入用户控件的类名,例如“MyUserControl”。
3.在类名后添加“UserControl”,表示这是一个用户控件。
4.单击“添加”按钮,Visual Studio 会自动生成一个用户控件的基类。
(2)手动创建用户控件:1.在项目中创建一个空白用户控件(UserControl)。
2.在用户控件的代码文件中,添加所需的UI 元素和代码。
3.为UI 元素设置属性、事件处理程序等。
**3.用户控件的属性与事件**用户控件具有自己的属性、事件和方法,可以通过以下方式访问和修改:- 属性:在用户控件的代码文件中,为UI 元素添加属性,如“公共”属性。
- 事件:为UI 元素添加事件处理程序,如“单击”事件。
- 方法:在用户控件类中添加方法,以实现特定功能。
**4.实例:创建一个简单的用户控件**以下是一个简单的用户控件示例,包括一个按钮和一个文本框:```csharpusing System.Windows;using System.Windows.Media;amespace WPF_UserControl{public partial class MyUserControl : UserControl{public MyUserControl(){InitializeComponent();}public static string InputText{get { return (string)GetValue(InputTextProperty); }set { SetValue(InputTextProperty, value); }}public static readonly DependencyProperty InputTextProperty =DependencyProperty.Register("InputText",typeof(string), typeof(MyUserControl), new UIPropertyMetadata(""));private void Button_Click(object sender, RoutedEventArgs e){MessageBox.Show("输入的文本是:" + InputText);}}}```**5.总结**在WPF 中,创建用户控件实例的方法多种多样。
WPF知识点--⾃定义Button(ControlTemplate控件模板)ControlTemplate是⼀种控件模板,可以通过它⾃定义⼀个模板来替换掉控件的默认模板以便打造个性化的控件。
ControlTemplate包含两个重要的属性:VisualTree该模板的视觉树,⽤来描述控件的外观。
Triggers触发器列表,⾥⾯包含⼀些触发器Trigger,我们可以定制这个触发器列表来使控件对外界的刺激发⽣反应,⽐如⿏标经过时⽂本变成粗体等。
⽰例:<Window.Resources><Style TargetType="Button"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><!-- 定义视觉树 --><Grid><!-- 绘制外圆 --><Ellipse x:Name="ellipse"Width="100"Height="100"Stroke="#FF6347"><Ellipse.Fill><LinearGradientBrush StartPoint="0.5,0" EndPoint="0.443,1.22"><LinearGradientBrush.RelativeTransform><TransformGroup><ScaleTransform CenterX="0.5" CenterY="0.5"/><SkewTransform CenterX="0.5" CenterY="0.5"/><RotateTransform Angle="-50" CenterX="0.5" CenterY="0.5"/><TranslateTransform /></TransformGroup></LinearGradientBrush.RelativeTransform><GradientStop Offset="0" Color="#FF4040"/><GradientStop Offset="1" Color="White"/></LinearGradientBrush></Ellipse.Fill></Ellipse><!-- 绘制内圆 --><Ellipse Width="80"Height="80"Stroke="{x:Null}"><Ellipse.Fill><LinearGradientBrush StartPoint="0.406,1.322" EndPoint="0.563,-0.397"><LinearGradientBrush.RelativeTransform><TransformGroup><ScaleTransform CenterX="0.5"CenterY="0.5"ScaleX="-1"ScaleY="-1"/><SkewTransform AngleX="0" AngleY="0" CenterX="0.5" CenterY="0.5"/><RotateTransform Angle="-50" CenterX="0.5" CenterY="0.5"/><TranslateTransform /></TransformGroup></LinearGradientBrush.RelativeTransform><GradientStop Offset="0" Color="White"/><GradientStop Offset="1" Color="#FF4040"/></LinearGradientBrush></Ellipse.Fill></Ellipse><!-- 使⽤ContentControl或ContentPresenter重写内容 --><!--<ContentControl HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}"Content="{TemplateBinding Content}" />--><ContentPresenter x:Name="contentPresenter"HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/></Grid><!-- 定义触发器 --><ControlTemplate.Triggers><!-- 设置按钮响应事件 --><Trigger Property="IsFocused" Value="True"/><Trigger Property="IsDefaulted" Value="True"/><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="ellipse" Property="Stroke" Value="#FFFFF400"/><Setter TargetName="ellipse" Property="StrokeThickness" Value="1.5"/></Trigger><Trigger Property="IsPressed" Value="True"><Setter TargetName="ellipse" Property="Fill"><Setter.Value><LinearGradientBrush StartPoint="0.5,0" EndPoint="0.443,1.22"><LinearGradientBrush.RelativeTransform><TransformGroup><ScaleTransform CenterX="0.5" CenterY="0.5"/><SkewTransform CenterX="0.5" CenterY="0.5"/><RotateTransform Angle="-50" CenterX="0.5" CenterY="0.5"/><TranslateTransform /></TransformGroup></LinearGradientBrush.RelativeTransform><GradientStop Offset="1" Color="#FF4040"/><GradientStop Offset="0" Color="White"/></LinearGradientBrush></Setter.Value></Setter><Setter TargetName="contentPresenter" Property="Margin" Value="5,5,0,0"/></Trigger><Trigger Property="IsEnabled" Value="False"/></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style></Window.Resources>View Code<Button Content="XButton"/>。
WPF⾃定义控件与样式-⾃定义按钮(Button)⼀、前⾔程序界⾯上的按钮多种多样,常⽤的就这⼏种:普通按钮、图标按钮、⽂字按钮、图⽚⽂字混合按钮。
本⽂章记录了不同样式类型的按钮实现⽅法。
⼆、固定样式的按钮固定样式的按钮⼀般在临时使⽤时或程序的样式⽐较固定时才会使⽤,按钮整体样式不需要做⼤的改动。
2.1 普通按钮-扁平化风格先看效果:定义Button的样式,详见代码:<Style x:Key="BtnInfoStyle" TargetType="Button"><Setter Property="Width" Value="70"/><Setter Property="Height" Value="25"/><Setter Property="Foreground" Value="White"/><Setter Property="BorderThickness" Value="0"/><Setter Property="Background" Value="#43a9c7"/><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Button"><Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels <TextBlock Text="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" VerticalAlignment="Center" HorizontalAlignment="Center"/></Border><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="border" Property="Background" Value="#2f96b4"/></Trigger><Trigger Property="IsPressed" Value="True"><Setter TargetName="border" Property="Background" Value="#2a89a4"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>引⽤⽅法:<Grid Background="White"><StackPanel Orientation="Horizontal" Margin="10" VerticalAlignment="Top"><Button Style="{StaticResource BtnInfoStyle}" Content="信息" Margin="5 0"/></Grid>上述代码实现了Button按钮的扁平化样式,如果你想调整颜⾊风格,通过修改Background的值可实现默认颜⾊,⿏标经过颜⾊以及⿏标按下颜⾊。
WPF控件开发之自定义控件Windows Presentation Foundation(WPF)控件模型的扩展性极大减少了创建新控件的需要。
但在某些情况下,仍可能需要创建自定义控件。
本主题讨论可最大限度减少在Windows Presentation Foundation(WPF)中创建自定义控件以及其他控件创作模型的需要的功能。
本主题还演示如何创建新控件。
AD:Windows Presentation Foundation(WPF)控件模型的扩展性极大减少了创建新控件的需要。
但在某些情况下,仍可能需要创建自定义控件。
本主题讨论可最大限度减少在Windows Presentation Foundation(WPF)中创建自定义控件以及其他控件创作模型的需要的功能。
本主题还演示如何创建新控件。
编写新控件的替代方法以前,如果要通过现有控件获取自定义体验,您只能更改控件的标准属性,例如背景色、边框宽度和字号。
如果希望在这些预定义参数的基础之上扩展控件的外观或行为,则需要创建新的控件,通常的方法是继承现有控件并重写负责绘制该控件的方法。
虽然这仍是一种可选方法,但也可以利用WPF丰富内容模型、样式、模板和触发器来自定义现有的控件。
下面的列表提供了一些示例,演示如何在不创建新控件的情况下使用这些功能来实现统一的自定义体验。
丰富内容。
很多标准WPF控件支持丰富内容。
例如,Button的内容属性为Object类型,因此从理论上讲,任何内容都可以显示在Button上。
若要让按钮显示图像和文本,可以将图像和TextBlock添加到StackPanel中,然后将StackPanel分配给Content属性。
由于这些控件可以显示WPF可视化元素和任意数据,因此,减少了创建新控件或修改现有控件来支持复杂可视化效果的需要。
样式。
Style是表示控件属性的值的集合。
使用样式可创建所需控件外观和行为的可重用表示形式,而无需编写新控件。
wpf⾃定义控件(包含依赖属性以及事件)创建了这个依赖属性,就可以直接在对应的控件中使⽤了,就像是button中⼀开始就内置的width等属性⼀样,这个在设计⾃定义控件的时候⽤的尤其多下⾯讲的是⾃定义分页控件代码:<UserControl x:Class="WPFDataGridPaging.Pager"xmlns="/winfx/2006/xaml/presentation"xmlns:x="/winfx/2006/xaml"xmlns:mc="/markup-compatibility/2006"xmlns:d="/expression/blend/2008"xmlns:local="clr-namespace:WPFDataGridPaging"mc:Ignorable="d"d:DesignHeight="30" d:DesignWidth="220"><UserControl.Resources><Style TargetType="{x:Type Button}"><Setter Property="Width" Value="22"/><Setter Property="Height" Value="22"/></Style></UserControl.Resources><Grid><StackPanel Orientation="Horizontal"><Button x:Name="FirstPageButton" Margin="5,0" Click="FirstPageButton_Click"><Path Width="7" Height="10" Data="M0,0L0,10 M0,5L6,2 6,8 0,5" Stroke="Black" StrokeThickness="1"Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/></Button><Button x:Name="PreviousPageButton" Margin="0,0,5,0" Click="PreviousPageButton_Click"><Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"/></Button><TextBlock VerticalAlignment="Center"><Run Text="第"/><Run x:Name="rCurrent" Text="0"/><Run Text="页"/></TextBlock><Button Margin="5,0" x:Name="NextPageButton" Click="NextPageButton_Click"><Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"><Path.RenderTransform><RotateTransform Angle="180" CenterX="4" CenterY="4"/></Path.RenderTransform></Path></Button><Button Margin="0,0,5,0" x:Name="LastPageButton" Click="LastPageButton_Click"><Path x:Name="MainPath" Width="7" Height="10" Data="M0,0L0,10 M0,5 L6,2 6,8 0,5"Stroke="Black" StrokeThickness="1" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"><Path.RenderTransform><RotateTransform Angle="180" CenterX="3" CenterY="5"/></Path.RenderTransform></Path></Button><TextBlock VerticalAlignment="Center"><Run Text="共"/><Run x:Name="rTotal" Text="0"/><Run Text="页"/></TextBlock></StackPanel></Grid></UserControl>界⾯:后台代码:public partial class Pager : UserControl{#region声明事件和依赖属性public static RoutedEvent FirstPageEvent;public static RoutedEvent PreviousPageEvent;public static RoutedEvent NextPageEvent;public static RoutedEvent LastPageEvent;public static readonly DependencyProperty CurrentPageProperty;public static readonly DependencyProperty TotalPageProperty;#endregionpublic string CurrentPage{get { return (string)GetValue(CurrentPageProperty); }set { SetValue(CurrentPageProperty, value); }}public string TotalPage{get { return (string)GetValue(TotalPageProperty); }set { SetValue(TotalPageProperty, value); }}public Pager(){InitializeComponent();}static Pager(){#region注册事件以及依赖属性//注册FirstPageEvent事件,事件的拥有者是Pager,路由事件的名称是FirstPage,这是唯⼀的FirstPageEvent = EventManager.RegisterRoutedEvent("FirstPage", RoutingStrategy.Direct,typeof(RoutedEventHandler), typeof(Pager));PreviousPageEvent = EventManager.RegisterRoutedEvent("PreviousPage", RoutingStrategy.Direct,typeof(RoutedEventHandler), typeof(Pager));NextPageEvent = EventManager.RegisterRoutedEvent("NextPage", RoutingStrategy.Direct,typeof(RoutedEventHandler), typeof(Pager));LastPageEvent = EventManager.RegisterRoutedEvent("LastPage", RoutingStrategy.Direct,typeof(RoutedEventHandler), typeof(Pager));//注册⾃定义的依赖属性CurrentPageProperty = DependencyProperty.Register("CurrentPage",typeof(string), typeof(Pager), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnCurrentPageChanged))); TotalPageProperty = DependencyProperty.Register("TotalPage",typeof(string), typeof(Pager), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnTotalPageChanged)));#endregion}public event RoutedEventHandler FirstPage{add { AddHandler(FirstPageEvent, value); }remove { RemoveHandler(FirstPageEvent, value); }}public event RoutedEventHandler PreviousPage{add { AddHandler(PreviousPageEvent, value); }remove { RemoveHandler(PreviousPageEvent, value); }}public event RoutedEventHandler NextPage{add { AddHandler(NextPageEvent, value); }remove { RemoveHandler(NextPageEvent, value); }}public event RoutedEventHandler LastPage{add { AddHandler(LastPageEvent, value); }remove { RemoveHandler(LastPageEvent, value); }}///<summary>///依赖属性回调⽅法///</summary>///<param name="d"></param>///<param name="e"></param>public static void OnTotalPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){Pager p = d as Pager;if (p != null){Run rTotal = (Run)p.FindName("rTotal");rTotal.Text = (string)e.NewValue;}}private static void OnCurrentPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){Pager p = d as Pager;if (p != null){Run rCurrrent = (Run)p.FindName("rCurrent");rCurrrent.Text = (string)e.NewValue;}}private void FirstPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(FirstPageEvent, this));}private void PreviousPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(PreviousPageEvent, this));}private void NextPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(NextPageEvent, this));}private void LastPageButton_Click(object sender, RoutedEventArgs e){RaiseEvent(new RoutedEventArgs(LastPageEvent, this));}}上⾯就是⾃定义的⼀个分页控件,如果我们想要使⽤这个控件,如下:<Window x:Class="WPFDataGridPaging.MainWindow"xmlns="/winfx/2006/xaml/presentation"xmlns:x="/winfx/2006/xaml"xmlns:d="/expression/blend/2008"xmlns:mc="/markup-compatibility/2006"xmlns:i="/expression/2010/interactivity"xmlns:local="clr-namespace:WPFDataGridPaging"mc:Ignorable="d"Title="MainWindow" Height="350" Width="525"><Grid><Grid.RowDefinitions><RowDefinition Height="*"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><DataGrid Grid.Row="0" ItemsSource="{Binding FakeSource}" AutoGenerateColumns="False" CanUserAddRows="False"> <DataGrid.Columns><DataGridTextColumn Header="Item Id" Binding="{Binding Id}" Width="80"/><DataGridTextColumn Header="Item Name" Binding="{Binding ItemName}" Width="180"/></DataGrid.Columns></DataGrid><!-- TotalPage 和CurrentPage就是在Pager中⾃定义的依赖属性,可以在这⾥直接来⽤--><local:Pager TotalPage="{Binding TotalPage}"CurrentPage="{Binding CurrentPage, Mode=TwoWay}"HorizontalAlignment="Center"Grid.Row="1"><i:Interaction.Triggers><!--EventName="FirstPage" 这⾥FirstPage就是前⾯注册事件的时候默认的事件名称,必须要唯⼀ --><i:EventTrigger EventName="FirstPage"><i:InvokeCommandAction Command="{Binding FirstPageCommand}"/></i:EventTrigger><i:EventTrigger EventName="PreviousPage"><i:InvokeCommandAction Command="{Binding PreviousPageCommand}"/></i:EventTrigger><i:EventTrigger EventName="NextPage"><i:InvokeCommandAction Command="{Binding NextPageCommand}"/></i:EventTrigger><i:EventTrigger EventName="LastPage"><i:InvokeCommandAction Command="{Binding LastPageCommand}"/></i:EventTrigger></i:Interaction.Triggers></local:Pager></Grid></Window>界⾯:后台代码:///<summary>/// Interaction logic for MainWindow.xaml///</summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();//这⾥⼀定要注意,⼀定要将模型加到上下⽂中,要不然依赖属性和事件都不会触发,在实际开发中是不可能⼀打开 //界⾯就开始加载出来数据的,所以可以通过ObservableCollection形式绑定表格数据,//⽽需要绑定事件和依赖属性的需要将其绑定到上下⽂中DataContext = new MainViewModel();}}MainViewModel:public class MainViewModel : ViewModel{private ICommand _firstPageCommand;public ICommand FirstPageCommand{get{return _firstPageCommand;}set{_firstPageCommand = value;}}private ICommand _previousPageCommand;public ICommand PreviousPageCommand{get{return _previousPageCommand;}set{_previousPageCommand = value;}}private ICommand _nextPageCommand;public ICommand NextPageCommand{get{return _nextPageCommand;}set{_nextPageCommand = value;}}private ICommand _lastPageCommand;public ICommand LastPageCommand{get{return _lastPageCommand;}set{_lastPageCommand = value;}}private int _pageSize;public int PageSize{get{return _pageSize;}set{if(_pageSize != value){_pageSize = value;OnPropertyChanged("PageSize"); }}}private int _currentPage;public int CurrentPage{get{return _currentPage;}set{if(_currentPage != value){_currentPage = value;OnPropertyChanged("CurrentPage"); }}}private int _totalPage;public int TotalPage{get{return _totalPage;}set{if(_totalPage != value){_totalPage = value;OnPropertyChanged("TotalPage"); }}}///<summary>/// ObservableCollection表⽰⼀个动态数据集合,它可在添加、删除项⽬或刷新整个列表时提供通知。
VBA中的用户界面设计和自定义控件随着计算机技术的不断发展,用户界面设计在软件开发中扮演着越来越重要的角色。
VBA(Visual Basic for Applications)作为一种强大的编程语言,提供了丰富的工具和功能,使得用户界面设计和自定义控件变得更加灵活和易于实现。
本文旨在介绍VBA中的用户界面设计和自定义控件的相关内容。
在VBA中,用户界面设计往往基于表单(Form)。
通过表单,可以创建交互性强、用户友好的应用程序。
VBA提供了丰富的控件类型,如文本框、标签、按钮、列表框等,可以用来构建界面元素。
用户可以通过拖拽的方式将这些控件添加到表单上,并进行相应的属性设置和事件编写,实现丰富的用户界面交互效果。
在进行用户界面设计时,设计原则和技巧是非常重要的。
首先,界面整洁简明,避免过多的控件和复杂的布局,以免用户感到困扰。
其次,界面要符合用户的直观操作习惯,提供清晰明了的导航和操作指引。
此外,界面的美观性和色彩搭配也是需要考虑的因素,可以根据应用程序的定位和目标用户来选择适合的主题和风格。
除了基本的表单控件外,VBA还支持自定义控件的创建和使用。
自定义控件可以满足特定业务需求,并且可以根据个人偏好进行灵活的定制。
VBA中的自定义控件可以通过编程方式创建,也可以通过ActiveX控件或Windows API实现。
编程方式创建自定义控件需要使用VBA提供的控件对象模型。
通过创建类模块和控件模块,可以定义新的控件类型,并在需要的地方使用。
自定义控件具有更高的灵活性和扩展性,可以根据实际需求设置不同的属性和事件,实现个性化的用户界面。
通过ActiveX控件,开发者可以使用第三方控件库,如Microsoft Office裡的常用控件,以扩展VBA的功能。
ActiveX控件是可重用的二进制组件,可以在VBA开发环境中进行使用。
这些控件具有更丰富的功能和更好的性能,可以提升用户界面的体验和效果。
另外,使用Windows API可以调用操作系统提供的功能和控件,实现更高级的用户界面效果。
WPF---控件模板(⼀)⼀、控件模板概述控件的外观通过⼀个ControlTemplate类型的对象确定,该对象指定了组成⼀个控件的显⽰的各种视觉元素。
当WPF创建⼀个控件时,会创建⼀个控件类(模板⽗)的实例,然后实例化通过它的ControlTemplate设定的这个控件的外观树(组成这个控件的内部UI元素)。
⼆、开发⾃定义的简单控件模板为了简单起见,我们开发⼀个简单的Button控件模板。
步骤参见以下:1)在Window的Resources中定义⼀个名字为myButtonTemplate的控件模板2)在使⽤StaticResource标记扩展为Button的Template属性赋值⾄此,⼀个简单的Button的ControlTemplate就算开发好了,但是仔细看图,我们会发现⼀个问题,我们按钮实际显⽰的⽂本信息与我们设定的⽂本信息是不⼀致的,这不是我们的预期,就连背景⾊和Border的颜⾊也不是我们的预设值,⽽是使⽤了模板的默认值,那么我们该如何修改控件模板来达到我们的预期呢?三、控件模板之TemplateBinding为了达到上述预期的效果,我们可以使⽤TemplateBinding将控件模板中的属性绑定到控件本⾝(模板⽗)。
参见以下代码:从图中可以看出,现在已经达到了预期的效果。
为了达到上述同样显⽰⽂本的效果,我们也可以使⽤ContentPresenter。
四、ContentPresenter对象1)ContentPresenter作为⼀个占位符,⽤来在模板中指定Content应该放置的位置;2)默认情况下,ContentPresenter从模板⽗(应⽤控件模板的控件本⾝)获取实际的内容,然后绑定到⾃⼰的Content属性;3)为了使⽤ContentPresenter,我们需要设置ControlTemplate的TargetType属性为模板⽗的类型。
使⽤了ContentPresenter的ControlTemplate参见以下:五、触发器1)Trigger必须在ControlTemplate.Triggers的节点下;2)Triggers集合中可以包含任意数量的Trigger;3)⼀个Trigger可以有任意数量的Setter;4)每个Setter中指定三个属性,分别是TargetName、Property和Value。
[WPF ⾃定义控件]简单的表单布局控件1. WPF布局⼀个表单在WPF 中布局表单⼀直都很传统,例如使⽤上⾯的XAML ,它通过Grid 布局⼀个表单。
这样出来的结果整整齐齐,看上去没什么问题,但当系统⾥有⼏⼗个表单页以后需要统⼀将标签改为上对齐,或者标签和控件中加⼀个:号等需求都会难倒开发⼈员。
⼀个好的做法是使⽤某些控件库提供的表单控件;如果不想引⼊⼀个这么“重”的东西,可以⾃⼰定义⼀个简单的表单控件。
这篇⽂章介绍⼀个简单的⽤于布局表单的Form 控件,虽然是⼀个很⽼的⽅案,但我很喜欢这个控件,不仅因为它简单实⽤,⽽且是⼀个很好的结合了ItemsControl 、ContentControl 、附加属性的教学例⼦。
Form 是⼀个⾃定义的ItemsControl ,部分代码可以参考这篇⽂章。
2. ⼀个古⽼的⽅法即使抛开验证信息、确认取消这些更⾼级的需求(表单的其它功能真的很多很多,但这篇⽂章只谈论布局),表单布局仍是个⼗分复杂的⼯作。
幸好⼗年前ScottGu 分享过⼀个,很有参考价值:Karl Shifflett has another great WPF blog post that covers a cool way to perform flexible form layout for LOB scenarios.<Grid Width="400" HorizontalAlignment="Center" VerticalAlignment="Center"><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions><TextBlock Text="⽤户名" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="4" /><TextBox Grid.Column="1" Margin="4" /><TextBlock Text="密码" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="4" Grid.Row="1" /><PasswordBox Grid.Row="1" Grid.Column="1" Margin="4" /><TextBlock Grid.Row="2" Text="确认密码" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="4" /><PasswordBox Grid.Column="1" Grid.Row="2" Margin="4" /></Grid>使⽤代码和截图如上所⽰。
简单易学图文并茂创作控件自己创作控件,分三种主要的形式:复合控件,扩展控件,和自定义控件。
复合控件,顾名思义就是把现有的进行组合,让它们协作形成功能强大的新控件;扩展控件,是以某一现有控件为基础,让它具有新的功能;自定义控件,则是由作者完全操刀,建立一个全新的控件。
可以用一个比喻来理解这三种形式的区别:复合控件,就是你买好各个电脑配件,组装成一台电脑;扩展控件,就是把显卡上的零件更换几个,让它能力比标准产品更强大;自定义控件,就是自己制作一个名为“生人勿近”的硬件,他可以通过PCI插槽,安装到电脑上,一旦生人走近,它能识别并发出狗叫……综上,三种形式中,复合控件相对来说是最简单的;扩展控件在其次;自定义控件最难。
通常,我们使用前两种技术,就能创作出很复杂的控件了。
范例1:Excel的单元格Cell,当它没有焦点的时候,就是一个TextBlock,当它获得焦点,可以编辑的时候,就是一个TextBox框。
这样一个控件,将是我们今后制作表格控件的基础。
范例1中,我们会用到两种技术,复合控件和扩展控件。
在VS中,要进行如下的工作(推荐使用VS2010)1.新建一个Solution,名为Cell;2.添加一个名为“TestAPP”的WFP项目。
我们用他来测试成果;3.添加一个名为“Ctrl_Cell”的WFP用户控件项目。
然后,我们需要一个TextBlock,和一个TextBox控件,这是我们的演员。
考虑一下它们应该怎样演出,才能达到我们需要的效果:●平时这个控件,应该表现出TextBlock的外观;●当我们点击这个Label时,隐藏的TextBox控件跑到TextBlock的前面,并且它显示的值和TextBlock一样。
同时,这个值是可以编辑的;●编辑完TextBox的内容,按下Enter,或者点击屏幕上的其他控件,让TextBox失去焦点,TextBox消失。
TextBlock跑到前面来,并且显示编辑后的内容。
接着,需要考虑一下这个控件的属性和事件。
1.它应该有一个Value属性,Label显示这个Value;同时Text也显示这个Value;我们编辑的时候,也是针对这个Value。
2.点击TextBlock时,会发生一系列的变化。
所以我们要关注TextBlock的MouseDown事件。
3.编辑TextBox,按下Enter后,或者TextBox失去焦点,会发生一系列的变化。
所以我们要关注TextBox接受了Enter键这个输入,同时也要关注它的LostFocus事件。
关于“TextBox控件接受到一个Enter输入”的问题。
基础的TextBox控件是没有这个功能的,而我们今后要用到的地方很多。
所以我考虑扩展一下TextBox的功能,制作一个Ex_TextBox。
新的控件在用户按下Enter的时候,产生一个getEnterKey的事件,这样使用者就能处理这条消息了。
扩展现有控件,直接在原有的TextBox上继承,把一个判断键盘输入值的程序afterGetEnter绑定到Keydown事件下。
在Ctrol_Cell项目下,添加一个新的类,名为Ex_TextBox。
*******************代码********************Public Class Ex_TextBoxInherits TextBox'这个控件扩展了现有TextBox的功能。
'当用户输入Enter的时候,引发一个getEnterKey事件。
'这样,控件的使用者,就能在输入Enter的时候,得到一个信息。
'扩展控件功能,属于创作控件的第二种技术。
Public Event getEnterKey As EventHandlerPrivate Sub afterGetEnter(ByVal sender As Object, ByVal e As KeyEventArgs) Handles MyBase.KeyDownIf e.Key = Key.Enter ThenRaiseEvent getEnterKey(sender, e)End IfEnd SubEnd Class*******************代码********************如此,用户按下Enter后,Ex_TextBox就发出一个getEnterKey事件。
使用者今后编写响应这个事件的代码就可以了。
最后,我们在Cell的UI上,添加一个TextBlock和一个Ex_TextBox。
其UI代码如下:*******************代码********************<UserControl x:Class="Ctrl_Cell"xmlns="/winfx/2006/xaml/presentation"xmlns:x="/winfx/2006/xaml"xmlns:mc="/markup-compatibility/2006"xmlns:d="/expression/blend/2008"mc:Ignorable="d"d:DesignHeight="300" d:DesignWidth="182" Height="23" xmlns:my="clr-namespace:Ctrl_Label_Text"><Grid><TextBlock Height="23" HorizontalAlignment="Stretch" Margin="0" Name="TextBlock1" Text="TextBlock" VerticalAlignment="Top" Background="#FF8DD66D" Padding="1" /><my:Ex_TextBox Height="23" HorizontalAlignment="Stretch" Margin="0" x:Name="Ex_TextBox1" VerticalAlignment="Stretch" Width="Auto" Visibility="Hidden" VerticalScrollBarVisibility="Hidden" Background="#FF8DD66D" BorderThickness="0" /> </Grid></UserControl>*******************代码********************控件的外观如下:要添加Value属性,并描述控件的行为,还需要添加一些代码:*******************代码********************Public Class Ctrl_CellPrivate p_value As String '这是Cell的Value属性Public Property Value As StringGetReturn Me.p_valueEnd GetSet(ByVal value As String)Me.p_value = valueMe.TextBlock1.Text = valueEnd SetEnd PropertyPrivate Sub ShowExTextBox(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBlock1.MouseDown'把显示Ex_TextBox的动作,和点击TextBlock事件绑定起来Me.Ex_TextBox1.Visibility = Windows.Visibility.VisibleMe.TextBlock1.Visibility = Windows.Visibility.HiddenMe.Ex_TextBox1.Focus()End SubPrivate Sub MyInit()'把显示TextBlock的动作,和Ex_Textbox得到Enter,以及失去焦点这两个事件绑定起来AddHandler Ex_TextBox1.getEnterKey, AddressOf Me.ShowTextBlockAddHandler Ex_TextBox1.LostFocus, AddressOf Me.ShowTextBlockEnd SubPrivate Sub ShowTextBlock(ByVal sender As Object, ByVal e As System.EventArgs) '这是从Ex_TextBox切换到TextBlock的动作Me.TextBlock1.Visibility = Windows.Visibility.VisibleMe.Value = Me.Ex_TextBox1.TextMe.Ex_TextBox1.Visibility = Windows.Visibility.HiddenEnd SubPublic Sub New()' 此调用是设计器所必需的。
InitializeComponent()' 在InitializeComponent() 调用之后添加任何初始化。
Me.MyInit() '调用自己的初始化代码End SubEnd Class*******************代码********************这样,Cell的设计就完成了。
在TestAPP中测试一下:在UI上放一个Cell控件。
并添加一个按钮:按钮查看Cell的Value,代码如下:*******************代码********************Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.ClickMsgBox(Me.Cell1.Value)End Sub*******************代码********************当Cell没有点击的时候,它是一个TextBlock;点击它,变成一个TextBox,可以接受用户的输入;修改内容并按下Enter后,切换回TextBlock,内容也修改了;修改内容,直接点击旁边的按钮,也能切换回TextBlock;按钮显示的是Cell的值。