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>
感謝您的閱讀~
參考文章: