介绍

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 = ;
public byte Red
{
get
{
return _red;
}
set
{
if(_red != value)
{
_red = value;
RaisePropertyChanged("Red");
RaiseColorChanged();
}
}
} private byte _green = ;
public byte Green
{
get
{
return _green;
}
set
{
if(_green != value)
{
_green = value;
RaisePropertyChanged("Green");
RaiseColorChanged();
}
}
} private byte _blue = ;
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;
}
}

使用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 = ; if(int.TryParse(this.Text, out input))
{
if (operation == "+")
{
this.Text = (input + ).ToString();
}
else
{
this.Text = (input - ).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. UserControl和CustomControl基础【PluraSight】

    UserControl UserControl实际上就是ContentControl,xaml里<UserControl></UserControl>tag之间包含的实际就是后 ...

  2. WPF UserControl响应窗体的PreviewKeyDown事件

    目的 在UserControl页面实现通过快捷键打开新建窗口 实现过程 监听Window窗体的PreviewKeyDown 其实,使用KeyDown事件也是可以的 页面代码 <Window x: ...

  3. WPF UserControl 的绑定事件、属性、附加属性

    原文:WPF UserControl 的绑定事件.属性.附加属性 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Vblegend_2013/arti ...

  4. WPF之路——用户控件对比自定义控件UserControl VS CustomControl)

    将多个现有的控件组合成一个可重用的“组”. 由一个XAML文件和一个后台代码文件. 不能使用样式和模板. 继承自UserControl类. 自定义控件(扩展) 在现有的控件上进行扩展,增加一些新的属性 ...

  5. WPF中用户控件对比自定义控件(UserControl VS CustomControl)

    接着这篇文章(http://www.cnblogs.com/shiyue/archive/2013/02/02/2889907.html)写: 用户控件(组合) 用于在一个项目中使用多次 自定义控件( ...

  6. UserControl和CustomControl两者区别

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

  7. Wpf usercontrol dispose

    窗口关闭时组件"析构": public UserControl()        {            InitializeComponent();               ...

  8. [WPF]UserControl的MouseWheel事件触发

    用户控件: <UserControl> <Grid> <TextBox x:Name="textBlock" HorizontalAlignment= ...

  9. WPF usercontrol 自定义依赖属性

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

随机推荐

  1. jquery html5 file 上传图片显示图片

    jquery js 的代码:不同浏览器下的路径 //建立一個可存取到該file的url function getObjectURL(file) {     var url = null ;     i ...

  2. super 与 this 同时使用问题

    大家都知道this 和 super 调用构造函数时都必须放在第一句,今天同学问我的一个问题有点意思. 那么:我怎么在子类中 显式的用 super 初始化父类同时用 this 初始化子类? ------ ...

  3. Python初识(PyMysql实例)

    为什么学习python呢,好吧,其实我也不知道,反正就是想学习了. 资料什么的全都low了,传值博客免费的就够.不要问我为什么,我基本上都是找的免费的视频.然后传值博客的最多,我真的不是打广告. py ...

  4. 浅谈Vue不同场景下组件间的数据交流

    浅谈Vue不同场景下组件间的数据“交流”   Vue的官方文档可以说是很详细了.在我看来,它和react等其他框架文档一样,讲述的方式的更多的是“方法论”,而不是“场景论”,这也就导致了:我们在阅读完 ...

  5. LoadRunner性能测试-loadrunner事务

    事务(Transaction): 简单来说就是用来模拟用户的一个相对完整的业务过程.添加事务,是用来衡量响应时间的重要方法.我们可以通过事务计时来对不同压力负载下的性能指标进行对比. 插入事务的方法: ...

  6. 分布式web架构中对session同步的常用处理方法以及优缺点

    写在前面 最近在读一本来自淘宝技术团队大牛的书,名字叫<大型网站系统与Java中间件实践>.开篇的章节详细地介绍了一个网站架构由小变大不断演进的过程,其中从单机架构升级到集群架构的过程中着 ...

  7. 数据结构随笔-php实现栈

    栈(Stack)满足后进先出(LIFO)的原则: 下面利用php实现栈的相关操作: 本实例栈的基本操作: 入栈(push):向栈内压入一个元素,栈顶指针指向栈顶元素 出栈(pop): 从栈顶去除元素, ...

  8. LAP+mysql-主从+redis

    Redis是一个开源的,内存中的数据结构存储系统,他可以用作数据库,缓存和消息中间介.支持多种类型数据库结构,如字符串(strings),散列(hashes),列表(lists),集合(sets),有 ...

  9. JVM学习笔记五:虚拟机类加载机制

    类加载生命周期 类加载生命周期:加载.验证.准备.解析.初始化.使用.卸载 类加载或初始化过程什么时候开始? 遇到new.getstatic.putstatic或invokestatic这4条字节码指 ...

  10. C互质个数

    C互质个数 Time Limit:1000MS  Memory Limit:65536K Total Submit:55 Accepted:27 Description 贝贝.妞妞和康康都长大了,如今 ...