介绍

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. [分享] 自动化测试与持续集成方案-- UI 检查

    对于自动化测试中,UI 自动化测试估计是最有争议的,让人又爱又恨. UI 自动化做回归测试,可以省下很多人力.如果版本一直不稳定,投入跟产出不成比例的. 时机 一般是要版本稳定,界面改动不大.如果迭代 ...

  2. Linux基本命令整理_sheng

    Linux版本 Linux系统是一个多用户.多任务的分时操作系统. Linux版本分为内核版本和发行版本. 常见的Linux发行版有: RedHat(分为用于企业的Red Hat Enterprise ...

  3. 52. leetcode 96. Unique Binary Search Trees

    96. Unique Binary Search Trees Given n, how many structurally unique BST's (binary search trees) tha ...

  4. python中的类属性和实例属性

    属性就是属于一个对象的数据或者函数,我们可以通过句点(.)来访问属性,同时 Python 还支持在运作中添加和修改属性. 我们先来看看类里面的普通字段: class Test(object): nam ...

  5. git分支管理之Feature分支

    软件开发中,总有无穷无尽的新的功能要不断添加进来. 添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合 ...

  6. 开源蜘蛛集合(转自haizhiguang博客,链接:http://blog.csdn.net/haizhiguang/article/details/20209573)

    各种蜘蛛: Heritrix   点击次数:1458 Heritrix是一个开源,可扩展的web爬虫项目.Heritrix设计成严格按照robots.txt文件的排除指示和META robots标签. ...

  7. Ubuntu 虚拟机支持与windows机器复制粘贴

    实现虚拟机VMware上Ubuntu与主机windows之间互相复制与粘贴 实现VMware中Ubuntu与主机Windows系统之间的相互复制与粘贴(公用粘贴板): 1.在虚拟机VMware的菜单栏 ...

  8. C#语言入门详解(002)

    c# 所編寫的不同應用程序 Console.WriteLine("Hello World!"); ///console textBoxShowHellow.Text = " ...

  9. [Scoi2014]方伯伯的玉米田 二维树状数组+动态规划

    考试最后半个小时才做这道题.十分钟写了个暴力还写挂了..最后默默输出n.菜鸡一只. 这道题比较好看出来是动规.首先我们要明确一点.因为能拔高长度任意的一段区域,所以如果从i开始拔高,那么一直拔高到n比 ...

  10. Linux IP_FORWARD说明

    --Linux IP_FORWARD说明 -----------------------------2014/03/01 ip地址分公有地址和私有地址,public address是由INIC(int ...