WPF之创建无外观控件

发布于:2024-05-06 ⋅ 阅读:(28) ⋅ 点赞:(0)

1,定义无外观控件。

  •     定义默认样式,在其静态构造函数中调用DefaultStyleKeyProperty.OverrideMetadata()。
//设置默认样式
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
  •  在项目中创建Themes文件夹, 在Themes文件夹中创建资源字典:generic.xaml。/Themes/generic.xaml 此格式路径为规定格式不得修改,此路径字典中的样式将被自动识别为自定义控件的默认样式。
  • 样式必须指定适用的对象类型:TargetType
<Style TargetType="local:ColorPicker"> <!--必须指定类型-->
  • 在generic.xaml中合并位于themes/colorpicker.xaml的字典时,需要使用包含程序集的路径(assemblyName;component/themes/colorpicker.xaml),如果只是使用/themes/colorpicker.xaml虽然在运行时可以正常运行,但是在编辑状态下无法预览效果。

2,使用Vs生成无外观控件框架。

  • 选择自定义控件

  • 自动生成包含静态样式重写的静态构造函数 。
 public class ColorPicker : Control
    {
        
        static ColorPicker()
        {
            //设置默认样式
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
          
        }
    }
  • 自动创建Themes文件,以及Themes文件下的generic.xaml资源字典。

3,定义资源字典:colorpicker.xaml。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:无外观控件">
    <Style TargetType="local:ColorPicker"> <!--必须指定类型-->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ColorPicker">
                    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                        <Grid Margin="{TemplateBinding Padding}">
                            <Grid.RowDefinitions>
                                <RowDefinition ></RowDefinition>
                                <RowDefinition ></RowDefinition>
                                <RowDefinition ></RowDefinition>
                                <RowDefinition ></RowDefinition>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="auto"></ColumnDefinition>
                                <ColumnDefinition Width="3*"></ColumnDefinition>
                                <ColumnDefinition Width="2*"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Grid.Resources>
                                <Style TargetType="TextBlock">
                                    <Setter Property="VerticalAlignment" Value="Center"></Setter>
                                    <Setter Property="Margin" Value="5,0,0,0"></Setter>
                                </Style>
                                <Style TargetType="Slider">
                                    <Setter Property="VerticalAlignment" Value="Center"></Setter>
                                    <Setter Property="Margin" Value="0,5,5,5"></Setter>
                                    <Setter Property="Maximum" Value="255"></Setter>
                                    <Setter Property="Minimum" Value="0"></Setter>
                                    <Setter Property="SmallChange" Value="1"></Setter>
                                </Style>
                            </Grid.Resources>
                            <TextBlock Text="Alpha:"></TextBlock>
                            <Slider x:Name="PART_AlphaSlider" Grid.Column="1"></Slider>
                            <TextBlock Text="Red:" Grid.Row="1"></TextBlock>
                            <Slider x:Name="PART_RedSlider" Grid.Row="1" Grid.Column="1"></Slider>
                            <TextBlock Text="Green:" Grid.Row="2"></TextBlock>
                            <Slider x:Name="PART_GreenSlider" Grid.Row="2" Grid.Column="1"></Slider>
                            <TextBlock Text="Blue:" Grid.Row="3"></TextBlock>
                            <Slider x:Name="PART_BlueSlider" Grid.Row="3" Grid.Column="1"></Slider>
                            <Rectangle  Grid.Column="2" Grid.RowSpan="4">
                                <Rectangle.Fill>
                                    <SolidColorBrush x:Name="PART_RecBrush"></SolidColorBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

4,在generic.xaml中添加资源字典colorpicker.xaml。

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="无外观控件;component/Themes/colorpicker.xaml">
        </ResourceDictionary>
        <ResourceDictionary Source="无外观控件;component/Themes/FlipPanel.xaml"></ResourceDictionary>
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

5,编写代码

[TemplatePart(Name = "PART_AlphaSlider", Type = typeof(RangeBase))]//此特性无特殊意义,只是用于标识提示
    [TemplatePart(Name = "PART_RedSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_GreenSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_BlueSlider", Type = typeof(RangeBase))]
    [TemplatePart(Name = "PART_RecBrush", Type = typeof(SolidColorBrush))]
    public class ColorPicker : Control
    {
        //注册依赖属性
        public static readonly DependencyProperty AlphaProperty;
        public static readonly DependencyProperty RedColorProperty;
        public static readonly DependencyProperty GreenColorProperty;
        public static readonly DependencyProperty BlueColorProperty;
        public static readonly DependencyProperty ColorProperty;
        public static readonly RoutedEvent ColorChangedEvent;
        static ColorPicker()
        {
            //设置默认样式
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
            AlphaProperty = DependencyProperty.Register("Alpha", typeof(Byte), typeof(ColorPicker), new PropertyMetadata((byte)0, RedGreenBlueChangedCallBack));
            RedColorProperty = DependencyProperty.Register("Red", typeof(Byte), typeof(ColorPicker), new PropertyMetadata((byte)0, RedGreenBlueChangedCallBack));
            GreenColorProperty = DependencyProperty.Register("Green", typeof(Byte), typeof(ColorPicker), new PropertyMetadata((byte)0, RedGreenBlueChangedCallBack));
            BlueColorProperty = DependencyProperty.Register("Blue", typeof(Byte), typeof(ColorPicker), new PropertyMetadata((byte)0, RedGreenBlueChangedCallBack));
            ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(ColorPicker), new PropertyMetadata(Colors.Yellow, ColorPropertyChanged));
            ColorChangedEvent = EventManager.RegisterRoutedEvent("ColorChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<Color>), typeof(ColorPicker));
        }

        public override void OnApplyTemplate()
        {
            
            //进行绑定设置

            RangeBase alpha = GetTemplateChild("PART_AlphaSlider") as RangeBase;
            RangeBase red = GetTemplateChild("PART_RedSlider") as RangeBase;
            RangeBase green = GetTemplateChild("PART_GreenSlider") as RangeBase;
            RangeBase blue = GetTemplateChild("PART_BlueSlider") as RangeBase;
            SolidColorBrush brush = GetTemplateChild("PART_RecBrush") as SolidColorBrush;
            alpha?.SetBinding(Slider.ValueProperty, new Binding(nameof(Alpha)) { Source = this });
            red?.SetBinding(Slider.ValueProperty, new Binding(nameof(Red)) { Source = this });
            green?.SetBinding(Slider.ValueProperty, new Binding(nameof(Green)) { Source = this });
            blue?.SetBinding(Slider.ValueProperty, new Binding(nameof(Blue)) { Source = this });
          //  this.SetBinding(ColorProperty, new Binding("Color") { Source = brush });
            BindingOperations.SetBinding(brush, SolidColorBrush.ColorProperty, new Binding(nameof(Color)) { Source = this });
            base.OnApplyTemplate();
        }

        private static void ColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Color curColor = (Color)e.NewValue;
            ColorPicker picker = d as ColorPicker;
            picker.Alpha = curColor.A;
            picker.Red = curColor.R;
            picker.Green = curColor.G;
            picker.Blue = curColor.B;
            RoutedPropertyChangedEventArgs<Color> args = new RoutedPropertyChangedEventArgs<Color>((Color)e.OldValue, (Color)e.NewValue);
            args.RoutedEvent = ColorChangedEvent;
            picker.RaiseEvent(args);
        }

        private static void RedGreenBlueChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorPicker picker = d as ColorPicker;
            Color curColor = picker.Color;
            byte val = (byte)e.NewValue;
            switch (e.Property.Name)
            {
                case "Alpha":
                    curColor.A = val;
                    break;
                case "Red":
                    curColor.R = val;
                    break;
                case "Green":
                    curColor.G = val;
                    break;
                case "Blue":
                    curColor.B = val;
                    break;
                default:
                    break;
            }
            picker.Color = curColor;
        }

        /// <summary>
        /// 设置颜色的Alpha值
        /// </summary>
        ///  [System.ComponentModel.Bindable(true)]
        [System.ComponentModel.Browsable(true)]
        [Category("颜色设置")]
        public byte Alpha
        {
            get
            {
                return (byte)this.GetValue(AlphaProperty);
            }
            set
            {
                this.SetValue(AlphaProperty, value);
            }
        }

        /// <summary>
        /// 设置颜色的Red值
        /// </summary>
        [Bindable(true), Browsable(true), Category("颜色设置")]
        public byte Red
        {
            get
            {
                return (byte)GetValue(RedColorProperty);
            }
            set
            {
                SetValue(RedColorProperty, value);
            }
        }
        /// <summary>
        /// 设置颜色的Green值
        /// </summary>
        [Bindable(true), Browsable(true), Category("颜色设置")]

        public byte Green
        {
            get
            {
                return (byte)GetValue(GreenColorProperty);
            }
            set
            {
                SetValue(GreenColorProperty, value);
            }
        }

        /// <summary>
        /// 设置颜色的Blue值
        /// </summary>
        [Bindable(true), Browsable(true), Category("颜色设置")]
        public byte Blue
        {
            get
            {
                return (byte)GetValue(BlueColorProperty);
            }
            set
            {
                SetValue(BlueColorProperty, value);
            }
        }

        /// <summary>
        /// 设置颜色值
        /// </summary>
        [Bindable(true), Browsable(true), Category("颜色设置")]
        public Color Color
        {
            get
            {
                return (Color)GetValue(ColorProperty);
            }
            set
            {
                SetValue(ColorProperty, value);
            }
        }
        //对事件进行包装
        /// <summary>
        /// 颜色变化完成事件
        /// </summary>
        public event RoutedPropertyChangedEventHandler<Color> ColorChanged
        {
            add
            {
                this.AddHandler(ColorChangedEvent, value);
            }
            remove
            {
                this.RemoveHandler(ColorChangedEvent, value);
            }
        }
    }

6,在UI中添加此控件。

  • 默认情况:
<local:ColorPicker Color="SkyBlue" Padding="5" BorderBrush="Black" BorderThickness="2"></local:ColorPicker>

  • 二次自定义控件模板:
<Window.Resources>
        <ControlTemplate x:Key="FancyColorPickerTemplate">
                <Border Background="LightGoldenrodYellow"
                BorderBrush="Black"
                BorderThickness="1">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition Height="Auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <Grid.Resources>
                            <Style TargetType="{x:Type Slider}">
                                <Setter Property="Orientation" Value="Vertical"></Setter>
                                <Setter Property="TickPlacement" Value="TopLeft"></Setter>
                                <Setter Property="TickFrequency" Value="10"></Setter>
                                <Setter Property="Minimum" Value="0"></Setter>
                                <Setter Property="Maximum" Value="255"></Setter>
                                <Setter Property="Margin" Value="5"></Setter>
                            </Style>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="Margin" Value="3"></Setter>
                                <Setter Property="FontSize" Value="10"></Setter>
                            </Style>
                        </Grid.Resources>

                        <Ellipse Grid.Column="0" Grid.RowSpan="2" 
                       Margin="10" Height="120" Stroke="LightGray" StrokeThickness="5">
                            <Ellipse.Fill>
                            <SolidColorBrush x:Name="PART_RecBrush"></SolidColorBrush>
                            </Ellipse.Fill>
                        </Ellipse>


                    <Slider Name="PART_RedSlider" Grid.Column="1"></Slider>
                        <TextBlock Grid.Row="1" Grid.Column="1">RED</TextBlock>
                    <Slider Name="PART_GreenSlider" Grid.Column="2"></Slider>
                        <TextBlock Grid.Row="1" Grid.Column="2">GREEN</TextBlock>
                    <Slider Name="PART_BlueSlider" Grid.Column="3"></Slider>
                        <TextBlock Grid.Row="1" Grid.Column="3">BLUE</TextBlock>


                    </Grid>

                </Border>
            </ControlTemplate>
        </Window.Resources>
  •  引用对象资源
<local:ColorPicker Template="{StaticResource FancyColorPickerTemplate}" Padding="5" Grid.Column="1" Margin="5" BorderBrush="BurlyWood" BorderThickness="2" Color="Red">

7,Demo链接

https://download.csdn.net/download/lingxiao16888/89253829?spm=1001.2014.3001.5501