WPF自定义控件开发实例 - ColorPicker

开发环境:Win10 + VS2017 + .Net4.5

这个 ColorPicker 是<<WPF编程宝典:使用C#2012和.NET4.5>>这本书中的例子.这里我记录一下,主要是为了加深印象,防止以后要开发自定义控件的时候忘记一些基本的步骤,可以随时来查一下.
调到博文的最后可以先查看一下效果图.

  1. 建立ColorPicker类继承自 Control

    为什么继承自 Control,Control类继承自UIElement -> FrameworkElement -> ColorPicker,同时 Control 类提供了 Template 功能.

  2. 通知WPF,将为控件提供新的样式.
    方法是在静态构造函数中调用 OverrideMetadata()方法.

    static ColorPicker()
     {
         DefaultStyleKeyProperty.OverrideMetadata(
             typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
     }
    
  3. 编写控件逻辑,添加一些必要的属性|事件|方法 ...

  4. 重写 OnApplyTemplate 方法,为模板中的元素添加数据绑定或者关联事件处理程序

  5. ColorPicker类的完整代码:

    using System;
     using System.Windows;
     using System.Windows.Controls;
     using System.Windows.Controls.Primitives;
     using System.Windows.Data;
     using System.Windows.Media;
    
     namespace Demo.DIYControl.Controls.DeepInDIY
     {
         [TemplatePart(Name = RedSliderName,Type = typeof(RangeBase))]
         [TemplatePart(Name = GreenSliderName, Type = typeof(RangeBase))]
         [TemplatePart(Name = BlueSliderName, Type = typeof(RangeBase))]
         [TemplatePart(Name = PreviewBrushName, Type = typeof(SolidColorBrush))]
         public class ColorPicker:Control
         {
             private const string RedSliderName = "PART_RedSlider";
             private const string GreenSliderName = "PART_GreenSlider";
             private const string BlueSliderName = "PART_BlueSlider";
             private const string PreviewBrushName = "PART_PreviewBrush";
    
             private Brush _initializeBorderBrush;
             
    
             public const byte RGBMaxValue = 255;
    
             public byte Red
             {
                 get { return (byte)GetValue(RedProperty); }
                 set { SetValue(RedProperty, value); }
             }
             // Using a DependencyProperty as the backing store for Red.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty RedProperty =
                 DependencyProperty.Register(
                     nameof(Red), typeof(byte), typeof(ColorPicker), 
                     new FrameworkPropertyMetadata(OnColorRGBChanged));
    
             public byte Green
             {
                 get { return (byte)GetValue(GreenProperty); }
                 set { SetValue(GreenProperty, value); }
             }
             // Using a DependencyProperty as the backing store for Green.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty GreenProperty =
                 DependencyProperty.Register(
                     nameof(Green), typeof(byte), typeof(ColorPicker), 
                     new FrameworkPropertyMetadata(OnColorRGBChanged));
    
             public byte Blue
             {
                 get { return (byte)GetValue(BlueProperty); }
                 set { SetValue(BlueProperty, value); }
             }
             // Using a DependencyProperty as the backing store for Blue.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty BlueProperty =
                 DependencyProperty.Register(
                     nameof(Blue), typeof(byte), typeof(ColorPicker), 
                     new FrameworkPropertyMetadata(OnColorRGBChanged));
    
             public Color Color
             {
                 get { return (Color)GetValue(ColorProperty); }
                 set { SetValue(ColorProperty, value); }
             }
             // Using a DependencyProperty as the backing store for Color.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty ColorProperty =
                 DependencyProperty.Register(nameof(Color), typeof(Color), 
                     typeof(ColorPicker), new FrameworkPropertyMetadata(Colors.Black,OnColorChanged));
    
             public CornerRadius CornerRadius
             {
                 get { return (CornerRadius)GetValue(CornerRadiusProperty); }
                 set { SetValue(CornerRadiusProperty, value); }
             }
             // Using a DependencyProperty as the backing store for CornerRadius.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty CornerRadiusProperty =
                 DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(ColorPicker), 
                     new FrameworkPropertyMetadata(default(CornerRadius)));
    
             public bool UseDynamicBorder
             {
                 get { return (bool)GetValue(UseDynamicBorderProperty); }
                 set { SetValue(UseDynamicBorderProperty, value); }
             }
             // Using a DependencyProperty as the backing store for UseDynamicBorder.  This enables animation, styling, binding, etc...
             public static readonly DependencyProperty UseDynamicBorderProperty =
                 DependencyProperty.Register(
                     "UseDynamicBorder", typeof(bool), typeof(ColorPicker), 
                     new FrameworkPropertyMetadata(true, OnUseDynamicBorderChanged));
    
    
             public static readonly RoutedEvent ColorChangedEvent = EventManager.RegisterRoutedEvent(
                 "ColorChangedEvent", RoutingStrategy.Bubble,
                 typeof(RoutedPropertyChangedEventHandler<Color>), typeof(ColorPicker));
             public event RoutedPropertyChangedEventHandler<Color> ColorChanged
             {
                 add { AddHandler(ColorChangedEvent, value); }
                 remove { RemoveHandler(ColorChangedEvent, value); }
             }
    
             static ColorPicker()
             {
                 DefaultStyleKeyProperty.OverrideMetadata(
                     typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
             }
    
             public ColorPicker()
             {
                 Loaded += (sender, args) =>
                 {
                     _initializeBorderBrush = BorderBrush;   //save initial borderbrush
                     BorderBrush = UseDynamicBorder? new SolidColorBrush(Color) : BorderBrush;
                 };
             }
    
    
             private static void OnColorRGBChanged(DependencyObject sender,
                 DependencyPropertyChangedEventArgs args)
             {
                 ColorPicker colorPicker = sender as ColorPicker;
                 colorPicker = colorPicker ?? throw new ArgumentException();
    
                 Color color = colorPicker.Color;
                 if (args.Property == RedProperty)
                     color.R = (byte)args.NewValue;
                 else if (args.Property == GreenProperty)
                     color.G = (byte)args.NewValue;
                 else if (args.Property == BlueProperty)
                     color.B = (byte)args.NewValue;
    
                 colorPicker.Color = color;
             }
    
             private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
             {
                 ColorPicker colorPicker = d as ColorPicker;
                 d = d ?? throw new ArgumentException();
                 colorPicker.Red = colorPicker.Color.R;
                 colorPicker.Green = colorPicker.Color.G;
                 colorPicker.Blue = colorPicker.Color.B;
    
                 //set border color
                 if (colorPicker.UseDynamicBorder)
                     colorPicker.BorderBrush = new SolidColorBrush(colorPicker.Color);
    
                 colorPicker.RaiseEvent(
                     new RoutedEventArgs(ColorChangedEvent, e.NewValue));
             }
    
             private static void OnUseDynamicBorderChanged(
                 DependencyObject d, DependencyPropertyChangedEventArgs args)
             {
                 ColorPicker colorPicker = d as ColorPicker;
                 colorPicker = colorPicker ?? throw new ArgumentException();
    
                 colorPicker.BorderBrush = (bool)args.NewValue ? new SolidColorBrush(colorPicker.Color) : colorPicker._initializeBorderBrush;
             }
    
             public override void OnApplyTemplate()
             {
                 base.OnApplyTemplate();
    
                 RangeBase slider = GetTemplateChild("PART_RedSlider") as RangeBase;
                 if (slider != null)
                 {
                     Binding binding = new Binding()
                     {
                         Path = new PropertyPath("Red"),
                         Source = this,
                         Mode = BindingMode.TwoWay
                     };
                     slider.SetBinding(RangeBase.ValueProperty, binding);
                     slider.Maximum = RGBMaxValue;
                 }
    
                 slider = GetTemplateChild("PART_GreenSlider") as RangeBase;
                 if (slider != null)
                 {
                     Binding binding = new Binding()
                     {
                         Path = new PropertyPath(nameof(Green)),
                         Source = this,
                         Mode = BindingMode.TwoWay
                     };
                     slider.SetBinding(RangeBase.ValueProperty, binding);
                     slider.Maximum = RGBMaxValue;
                 }
    
                 slider = GetTemplateChild("PART_BlueSlider") as RangeBase;
                 if (slider != null)
                 {
                     Binding binding = new Binding()
                     {
                         Path = new PropertyPath(nameof(Blue)),
                         Source = this,
                         Mode = BindingMode.TwoWay
                     };
                     slider.SetBinding(RangeBase.ValueProperty, binding);
                     slider.Maximum = RGBMaxValue;
                 }
    
                 SolidColorBrush brush = GetTemplateChild("PART_PreviewBrush") as SolidColorBrush;
                 if (brush != null)
                 {
                     Binding bd = new Binding
                     {
                         Path = new PropertyPath(nameof(brush.Color)),
                         Source = brush,
                         Mode = BindingMode.OneWayToSource
                     };
                     SetBinding(ColorPicker.ColorProperty, bd);
                 }
             }
    
         }
     }
    
    
  6. 差不多就是这样一个简单的ColorPicker就出来了.另外增加一个UseDynamicBorder,来控制控件边框的颜色是否动态改变.
    看一下效果图

转载于:https://www.cnblogs.com/Laggage/p/10706376.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WPF(Windows Presentation Foundation)是一种用于创建功能丰富的用户界面的技术,它提供了许多预定义的控件,但也支持自定义控件来满足更特定的需求。 在WPF中,我们可以通过扩展现有的控件或创建全新的控件来自定义控件。具体步骤如下: 1. 创建一个新的类,继承自WPF中的控件类(如Button、TextBox等),这个新类将成为我们自定义控件的基类。 2. 在新类中添加需要的属性、方法和事件,以满足我们的特定需求。我们可以根据需要自定义控件的外观、行为和逻辑。 3. 使用WPF的外观系统来定义自定义控件的视觉效果。可以使用XAML来定义控件的样式、模板和触发器,也可以通过代码动态创建控件。 4. 在控件的构造函数中初始化控件的默认属性和事件。 5. 可选地,可以实现控件的依赖属性,这样就可以通过绑定的方式将数据与控件关联起来。 6. 在需要使用自定义控件的地方,将控件添加到XAML布局或通过代码创建并添加到视觉树中。 通过自定义控件,我们可以实现更灵活、更具个性化的用户界面,同时提供更好的用户体验。自定义控件可以适应各种复杂的场景和需求,从而提供更具创意和创新性的用户界面设计。 总结来说,使用WPF自定义控件的过程包括创建扩展自控件基类、添加属性和事件、定义外观效果、初始化属性和事件、实现依赖属性等步骤。自定义控件能够满足特定需求,提供更灵活、个性化的用户界面。 ### 回答2: WPF(Windows Presentation Foundation)是微软推出的一种优秀的用户界面开发技术,允许开发者创建高度可定制的界面。而自定义控件则是WPF中的一种重要功能,它允许开发者根据自己的需求创建全新的用户界面元素。 自定义控件实例如下: 我们假设要创建一个自定义按钮控件,该按钮有独特的外观和交互行为。首先,我们需要在WPF应用程序中定义一个新的自定义控件类,该类继承自Button类。然后,我们可以在控件类中添加新的依赖属性以实现更多的定制化选项。 在控件类中,我们可以重写OnApplyTemplate方法以定义在控件模板中使用的可视化元素。比如,我们可以定义一个Grid作为按钮的视觉部分,并在Grid中添加一个Border作为按钮的背景。还可以添加鼠标事件处理程序以响应用户的交互动作。 接下来,我们需要在XAML文件中使用我们自定义的按钮控件。我们可以在Window或者其他容器中引用自定义按钮,并设置其属性和事件处理程序。比如,我们可以设置按钮的背景颜色为蓝色,文本为“点击我”,并为按钮的Click事件添加一个处理方法。 通过这种方式,我们可以实现一个具有独特外观和交互行为的自定义按钮控件。开发者可以根据自己的需求定义更多的自定义控件,从而为用户提供更灵活和丰富的界面体验。 总而言之,WPF中的自定义控件是一种强大的功能,它允许开发者创建全新的用户界面元素,实现更高度的定制化和交互行为。通过合理地使用自定义控件开发者可以为用户提供更好的用户界面体验。 ### 回答3: WPF(Windows Presentation Foundation)是一个用于创建 Windows 桌面应用程序的开发框架,它提供了丰富的图形化用户界面(GUI)设计工具和功能。在 WPF 中,我们可以创建自定义控件来满足特定的需求。 自定义控件是指在原有的 WPF 控件基础上进行扩展或重写,以满足特定场景的需求。通过自定义控件,我们可以实现更加灵活的界面设计和交互方式。 创建自定义控件的过程包括以下几个步骤: 1. 继承现有的 WPF 控件:可以选择一个现有的 WPF 控件作为基类,然后通过扩展或重写其功能来实现自定义控件。例如,我们可以继承 Button 控件,并添加一些额外的属性和事件来实现一个特定的按钮效果。 2. 添加依赖属性:依赖属性是 WPF 中一种特殊的属性,它可以提供数据的绑定和通知机制。通过添加依赖属性,我们可以在自定义控件中定义可以被外部代码修改和引用的属性。 3. 创建控件模板:控件模板定义了控件的外观和布局方式。可以通过 XAML 或代码方式创建控件模板,并将其应用到自定义控件中。 4. 添加样式和模板绑定:可以为自定义控件添加样式,定义其在不同状态下的外观效果。同时,可以通过模板绑定将控件属性和模板中的元素进行关联。 创建完成后,我们可以在 XAML 中使用自定义控件,就像使用任何其他的 WPF 控件一样。可以设置自定义控件的属性、订阅事件,并将其嵌入到应用程序的界面中。 总的来说,WPF自定义控件功能可以帮助开发者实现更加灵活和个性化的用户界面设计。通过继承和扩展现有的控件,添加依赖属性和控件模板,我们可以创建出符合特定需求的自定义控件,并在应用程序中灵活使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值