在實際工作中,WPF提供的控件並不能完全滿足不同的設計需求。這時,需要我們設計自定義控件。
這里LZ總結一些自己的思路,特性如下:
- Coupling
- UITemplate
- Behaviour
- Function Package
下面舉例說說在項目中我們經常用到調音台音量條,寫一個自定義控件模擬調音台音量條。
自定義控件SingnalLight,實現功能
- 接收來自外部的范圍0~100的數值
- 實時顯示接收數值
- 數值范圍0~50顯示綠色,50~85顯示黃色,85~100顯示紅色,沒有數值顯示褐色
- 可在父控件上拖拽該控件
public class SingnalLight : ContentControl { public int ValueA { get { return (int)GetValue(ValueAProperty); } set { SetValue(ValueAProperty, value); } } public SingnalLight() { this.AllowDrop = true; } static SingnalLight() { DefaultStyleKeyProperty.OverrideMetadata(typeof(SingnalLight), new FrameworkPropertyMetadata(typeof(SingnalLight))); } }
ValueA為接受外部數值的屬性
2.復寫控件UITemplate
1 <Style TargetType="{x:Type control:SingnalLight}">
2 <Setter Property="RenderTransform">
3 <Setter.Value>
4 <TranslateTransform X="{Binding Path=X,RelativeSource={RelativeSource AncestorType={x:Type control:SingnalLight}}}"
5 Y="{Binding Path=Y,RelativeSource={RelativeSource AncestorType={x:Type control:SingnalLight}}}"/>
6 </Setter.Value>
7 </Setter>
8 <Setter Property="Template">
9 <Setter.Value>
10 <ControlTemplate>
11 <ControlTemplate.Resources>
12 <control:SingnalLightStatusConverter x:Key="colorconverter"></control:SingnalLightStatusConverter>
13 <control:SingnalLightValueConverter x:Key="valueconverter"></control:SingnalLightValueConverter>
14 </ControlTemplate.Resources>
15 <StackPanel>
16 <TextBlock Text="{Binding Path=ValueA,RelativeSource={RelativeSource AncestorType={x:Type control:SingnalLight}}}"></TextBlock>
17 <TextBlock Text="100"></TextBlock>
18 <Border
19 x:Name="bd1"
20 Height="{Binding Path=LightHeight,RelativeSource={RelativeSource AncestorType={x:Type control:SingnalLight}}}"
21 SnapsToDevicePixels="True"
22 BorderBrush="Black" BorderThickness="1" Background="Transparent">
23 <Rectangle Fill="{Binding Path=ValueA,
24 RelativeSource={RelativeSource AncestorType={x:Type control:SingnalLight}},
25 Converter={StaticResource ResourceKey=colorconverter}}"
26 VerticalAlignment="Bottom">
27 <Rectangle.Height>
28 <MultiBinding Converter="{StaticResource ResourceKey=valueconverter}">
29 <Binding Path="ValueA" RelativeSource="{RelativeSource AncestorType={x:Type control:SingnalLight}}"></Binding>
30 <Binding Path="Height" ElementName="bd1"></Binding>
31 </MultiBinding>
32 </Rectangle.Height>
33 </Rectangle>
34 </Border>
35 <TextBlock Text="0"></TextBlock>
36 </StackPanel>
37 </ControlTemplate>
38 </Setter.Value>
39 </Setter>
40 </Style>
3.接受值判斷,SingnalLight通過實現IValueConverter和Override Arrange & Measure Methods,實現了UI呈現的綁定,
1 public class SingnalLightStatusConverter : IValueConverter {
2 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
3 SolidColorBrush result = Brushes.Transparent;
4 if (value.GetType() == typeof(int)) {
5 var color = System.Convert.ToInt32(value);
6 if (color < 50) result = Brushes.Green;
7 else if (color < 85 && color >= 50) result = Brushes.Yellow;
8 else if (color <= 100 && color >= 85) result = Brushes.Red;
9 else result = Brushes.Gray;
10 }
11 return result;
12 }
13
14 public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
15 throw new NotImplementedException();
16 }
17 }
18
19 public class SingnalLightValueConverter : IMultiValueConverter {
20 public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
21 double result = 0;
22 if (values[0].GetType() == typeof(int) && values[1].GetType() == typeof(double)) {
23 result = (double)values[1] / 100 * System.Convert.ToDouble(values[0]);
24 }
25 return result;
26 }
27
28 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) {
29 throw new NotImplementedException();
30 }
31 }
1 protected override Size MeasureOverride(Size constraint) {
2 if (ActualHeight > 0) LightHeight = ActualHeight * .7;
3 return base.MeasureOverride(constraint);
4 }
5
6 protected override Size ArrangeOverride(Size arrangeBounds) {
7 return base.ArrangeOverride(arrangeBounds);
8 }
4.控件支持拖拽,覆寫MouseDown,MouseMove,MouseUp方法。這樣寫的好處是,如果在父控件的事件中實現Drag,父控件如果有多個對象,這樣邏輯會十分混亂。
1 protected override void OnMouseMove(MouseEventArgs e) {
2 base.OnMouseMove(e);
3 if (e.LeftButton == MouseButtonState.Pressed) {
4 _currentPoint = e.GetPosition(this);
5 X += _currentPoint.X - _startPoint.X;
6 Y += _currentPoint.Y - _startPoint.Y;
7 }
8 }
9
10 protected override void OnMouseDown(MouseButtonEventArgs e) {
11 base.OnMouseDown(e);
12 _startPoint = e.GetPosition(this);
13 this.CaptureMouse();
14 }
15
16 protected override void OnMouseUp(MouseButtonEventArgs e) {
17 base.OnMouseUp(e);
18 this.ReleaseMouseCapture();
19 }
自定義控件系列博文鏈接:
WPF自定義控件(一)の控件分類
WPF自定義控件(二)の重寫原生控件樣式模板
WPF自定義控件(三)の擴展控件
WPF自定義控件(四)の自定義控件
WPF自定義控件(五)の用戶控件
