原文:[WPF] UserControl vs CustomControl

介绍

WPF中有两种控件:UserControl和CustomControl,但是这两者有什么区别呢?这篇博客中将介绍两者之间的区别,这样可以在项目中合理的使用它们。

UserControl

  • 将多个WPF控件(例如:TextBox,TextBlock,Button)进行组合成一个可复用的控件组;
  • 由XAML和Code Behind代码组成;
  • 不支持样式/模板重写;
  • 继承自UserControl;

下面创建的一个RGBControl由3个TextBlock,3个TextBox,1个Rectangle组成。我们可以在WPF的任意窗体/Page上面复用该UserControl。

XAML Code:

<Grid Background="LightGray"><Grid.RowDefinitions><RowDefinition /><RowDefinition /><RowDefinition /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="*" /><ColumnDefinition Width="2*" /></Grid.ColumnDefinitions><TextBlock Text="Red" /><TextBlock Text="Green" Grid.Row="1" /><TextBlock Text="Blue" Grid.Row="2" /><TextBox Text="{Binding Red, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Grid.Column="1" Height="25" Width="80" Margin="0,5" /><TextBox Text="{Binding Green, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Grid.Row="1" Grid.Column="1" Height="25" Width="80" Margin="0,5" /><TextBox Text="{Binding Blue, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Grid.Row="2" Grid.Column="1" Height="25" Width="80" Margin="0,5" /><Rectangle Fill="{Binding Color, Converter={StaticResource ColorToSolidBrushConverter}}" Grid.Column="2" Grid.RowSpan="3" Margin="10, 5" Width="100" Height="100"/>
</Grid>

C# Code

public partial class RGBControl : UserControl
{public RGBControl(){InitializeComponent();this.DataContext = new RGBViewModel();}
}public class RGBViewModel : ObservableObject
{private byte _red = 0;public byte Red{get{return _red;}set{if(_red != value){_red = value;RaisePropertyChanged("Red");RaiseColorChanged();}}}private byte _green = 0;public byte Green{get{return _green;}set{if(_green != value){_green = value;RaisePropertyChanged("Green");RaiseColorChanged();}}}private byte _blue = 0;public byte Blue{get{return _blue;}set{if(_blue != value){_blue = value;RaisePropertyChanged("Blue");RaiseColorChanged();}}}private Color _color;public Color Color{get{return _color;}set{RaiseColorChanged();}}private void RaiseColorChanged(){_color = Color.FromRgb(Red, Green, Blue);RaisePropertyChanged("Color");}
}public class ObservableObject : INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;protected virtual void RaisePropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}public class ColorToSolidBrushConverter : IValueConverter
{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){Color color = (Color)value;return new SolidColorBrush(color);}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return null;}
}

View Code

使用RGBControl:

<Grid><local:RGBControl Width="320" Height="120"/>
</Grid>

CustomControl

  • 自定义控件,扩展自一个已经存在的控件,并添加新的功能/特性;
  • 由C#/VB.NET Code和样式文件组成(Themes/Generic.xaml);
  • 支持样式/模板重写;
  • 如果项目中自定义控件较多,建议创建一个WPF自定义控件库(WPF Control Library)

怎样创建一个WPF CustomControl呢?

选择合适的控件基类,或者说选择合适的控件进行功能扩展

UIElement 最轻量级的基类,支持Layout, Input, Focus, Event

FrameworkElement 继承自UIElement,支持styling,tooltips,context menus,data binding,resouce look up

Control 最基础的控件,支持template, 并增加了一些额外属性,例如Foreground, Background, FontSize等

ContentControl 在Control的基础上增加了Content属性,常见的控件有,布局控件,Button等

HeaderedContentControl 在ContentControl基础增加了一个Header属性,常见的控件有:Expander,TabControl,GroupBox等

ItemsControl 一个具有Items集合的控件,用来展示数据,但是不包含 Selection 特性

Selector 是一个ItemsControl,增加了Indexed,Selected特性,典型的控件有: ListBox, ComboBox, ListView, TabControl等

RangeBase 典型的控件有Sliders, ProgressBars. 增加了Value,Minimum和Maximum属性

WPF的控件行为和表现是分离的。行为在Code中定义,Template在XAML中定义。

重写Default Style

static NumericTextBox()
{DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata(typeof(NumericTextBox)));
}

重写默认样式文件

<Style TargetType="{x:Type local:NumericTextBox}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:NumericTextBox}">...</ControlTemplate></Setter.Value></Setter>
</Style>

以一个Numeric up/down控件为例:控件如下:

很直观的可以看到,Numeric up/down TextBox可以通过扩展WPF的TextBox控件实现,在WPF TextBox的基础上添加两个Button,然后重写这个自定义控件样式。

C# Code:

[TemplatePart(Name = UpButtonKey, Type = typeof(Button))]
[TemplatePart(Name = DownButtonKey, Type = typeof(Button))]
public class NumericTextBox : TextBox
{private const string UpButtonKey = "PART_UpButton";private const string DownButtonKey = "PART_DownButton";private Button _btnUp = null;private Button _btnDown = null;static NumericTextBox(){DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata(typeof(NumericTextBox)));}public override void OnApplyTemplate(){base.OnApplyTemplate();_btnUp = Template.FindName(UpButtonKey, this) as Button;_btnDown = Template.FindName(DownButtonKey, this) as Button;_btnUp.Click += delegate { Operate("+"); };_btnDown.Click += delegate { Operate("-"); };}private void Operate(string operation){int input = 0;if(int.TryParse(this.Text, out input)){if (operation == "+"){this.Text = (input + 1).ToString();}else{this.Text = (input - 1).ToString();}}}
}

Style Code:

<Style TargetType="{x:Type local:NumericTextBox}"><Setter Property="SnapsToDevicePixels" Value="True" /><Setter Property="FontSize" Value="12" /><Setter Property="Height" Value="40" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:NumericTextBox}"><Border x:Name="OuterBorder" BorderBrush="LightGray" BorderThickness="1"><Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="*" /><ColumnDefinition Width="30" /></Grid.ColumnDefinitions><Border Grid.ColumnSpan="2" Grid.RowSpan="2" Background="White"><ScrollViewer x:Name="PART_ContentHost" Margin="5,0" VerticalAlignment="Center" FontSize="12" /></Border><Button x:Name="PART_UpButton" Grid.Column="1" Content="+" VerticalContentAlignment="Center" /><Button x:Name="PART_DownButton" Grid.Row="1" Grid.Column="1" Content="-" VerticalContentAlignment="Center" /></Grid></Border></ControlTemplate></Setter.Value></Setter>
</Style>

使用:

<StackPanel><custom:NumericTextBox Width="200" Text="1" />
</StackPanel>

感谢您的阅读~

参考文章:

https://wpftutorial.net/CustomVsUserControl.html

https://wpftutorial.net/HowToCreateACustomControl.html

[WPF] UserControl vs CustomControl相关推荐

  1. 【WPF】用CustomControl打造WPF版的Marquee

    控件代码已经更新,支持上下左右四个方向.VS2010工程 /Files/RMay/WPF_Marquee/WpfMarquee.zip 我们知道在html中有一个marquee标签,可以很方便的实现文 ...

  2. WPF usercontrol 自定义依赖属性

    1.依赖属性不同意一般属性,一般属性主要定义在对象中,而依赖属性是存在一个特殊的依赖属性表中. 2.当我们触发改变值时,需要通过SetValue这种方式进行触发. UserControl1.xaml: ...

  3. WPF UserControl响应PreviewKeyDown事件方法

    之前在一个项目中,Window窗口嵌入UserControl页面,在UserControl控件页面中添加PreviewKeyDown或者KeyDown事件,软件均不触发事件:在Window窗口可以响应 ...

  4. 【转】在WPF中自定义控件

    周银辉的开发博客(WPF) 在WPF中自定义控件(1) 一, 不一定需要自定义控件 在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费 ...

  5. 在Silverlight 和WPF中使用预编译指令 if..else..endif (译)

    下面的是中文翻译,有些扯淡的话就略过了,想看原文,请到这里 对于预编译指令,作者分成了几篇文章来讲解的.鉴于翻译后的文字较少,我把作者的几篇合为了一篇.下面进入正题. 一.总揽: 想要编写特定平台的代 ...

  6. how to reference the parent form from the WPF control(Control in ElementHost)

    Winform 中放置 ElementHost 控件加载 wpf 的 UserControl 在 WPF UserControl 中获取 winform 的方法 public partial clas ...

  7. [WPF]如何实现设置弹出窗口的Owner属性功能?

    普通WPF窗口从一个Window1(Show方式)打开另一个Window2,只要设置Window2.Owner= Window1即可.这样Window2的显示和隐藏可由Window1自动控制. 但使用 ...

  8. WPF 控件样式之TextBox 输入框

    TextBox 输入框 基础用法 <TextBox></TextBox> <TextBox lib:Assists.PlaceHolder="自定义水印内容和颜 ...

  9. Silverlight 用DependencyProperty 自定义ImageButton控件 定义属性

    为ImageButton自定义IconSource和Contents属性 xaml代码 <UserControl x:Class="SilverlightCreate.Silverli ...

最新文章

  1. 新的小游戏发布啦。Pop Jungle
  2. 手机app 有没有window.location.href_热议小程序使用场景越来越多,未来有没有可能替代手机APP?...
  3. bat 域 本机管理员密码_Windows域中特殊的用户-计算机对象攻防
  4. 我的世界 文件保存位置
  5. 计算机在外语专业中有哪些应用,CALL(3):计算机在外语教学中的应用
  6. C++中的抽象类以及接口的区别联系
  7. canvas 圆角矩形填充_一篇文章让你学会你最“害怕”的Canvas,太有意思了
  8. FFmpeg--命令详解
  9. 如何在ngRepeat中使用Bootstrap Span元素
  10. blogic-io.xml文件中的出力属性和output.javabean文件中的属性需要一一对应
  11. 关于datetimepicker和vue v-model指令双向数据绑定失败的问题
  12. 如何用DOM4J编程使用xml schema
  13. 【Linux】VMware虚拟机中如何配置静态IP
  14. php list() ecah(),PHP each()与list()函数
  15. python代码变成手机软件_使用Python代码的程序员也浪漫
  16. java中重命名文件夹名,【Java】对文件或文件夹进行重命名
  17. 记win10安装cupy的cuda版本成功踩得坑!!!血泪教训!!
  18. win10在哪找计算机配置,电脑教程:windows10的设置在哪
  19. 多线程处理容器ExecutorCompletionService使用
  20. 【DFS】马蹄印(Horseshoes)

热门文章

  1. Windows客户端C/C++编程规范“建议”——风格
  2. Dlib库中实现正脸人脸关键点(landmark)检测的测试代码
  3. java 读取数据库结构_JAVA从SQLITE数据库中读取省份地市构造一棵树
  4. C语言常用算法 脚本之家,C/C++常用算法手册 秦姣华 中文pdf扫描版 22.5MB
  5. 测试方案_何小伟:ABTest测试方案
  6. oracle字段重复新增错误,oracle在已有重复数据的列上创建唯一约束
  7. python代码画皮卡丘_Python气象绘图实例我们一起画台风(代码+数据)
  8. 【windows】cmd中的help无法使用的解决方法
  9. JackJson 使用记录
  10. runaway深度递归函数测试及相关汇编指令