WPF中有两种控件:UserControl和CustomControl,可是这二者有什么区别呢?这篇博客中将介绍二者之间的区别,这样能够在项目中合理的使用它们。html
下面建立的一个RGBControl由3个TextBlock,3个TextBox,1个Rectangle组成。咱们能够在WPF的任意窗体/Page上面复用该UserControl。ide
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# Codethis
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; } }
使用RGBControl:spa
<Grid> <local:RGBControl Width="320" Height="120"/> </Grid>
UIElement 最轻量级的基类,支持Layout, Input, Focus, Event.net
FrameworkElement 继承自UIElement,支持styling,tooltips,context menus,data binding,resouce look upcode
Control 最基础的控件,支持template, 并增长了一些额外属性,例如Foreground, Background, FontSize等htm
ContentControl 在Control的基础上增长了Content属性,常见的控件有,布局控件,Button等blog
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中定义。
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>
感谢您的阅读~
参考文章: