WPF 八( UserControl 与 CustomControl区别总结)
UserControl vs CustomControl区别
UserControl
将多个WPF控件(例如:TextBox,TextBlock,Button)进行组合成一个可复用的控件组;
由XAML和Code Behind代码组成;
不支持样式/模板重写,其不支持重写是自己本页面不支持重写,但是页面内可以嵌套自定义控件;
由一个xaml和对应的后台组合而成
继承自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);
支持样式/模板重写;
包括一个自定义的控件类和默认的自定义主题样式文件
继承于要实现的相关控件基类;
自定义控件与当前页面进行实现数据传输需要进行创建依赖属性,达到复用原则;
以下是基于 TextBox实现的自定义控件
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>