WPF自定义控件(四)の自定义控件

在实际工作中,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自定义控件(五)の用户控件

posted @   卖雨伞的小男孩  阅读(4636)  评论(1编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示