wpf 创建无外观应用程序并应用默认控件模板

1 新建wpf应用程序

2 新建wpf UserControl类库,并新建类,继承Control,这里的代码基本都是从有外观的UserControl里面拷贝过来的,只是在静态构造函数中添加了覆盖默认样式的代码

 DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace CustomControl
{
    public class ColorPicker : Control
    {
        public Color Color
        {
            get { return (Color)GetValue(ColorProperty); }
            set { SetValue(ColorProperty, value); }
        }

        public byte Red
        {
            get { return (byte)GetValue(RedProperty); }
            set { SetValue(RedProperty, value); }
        }
        public byte Green
        {
            get { return (byte)GetValue(GreenProperty); }
            set { SetValue(GreenProperty, value); }
        }

        public byte Blue
        {
            get { return (byte)GetValue(BlueProperty); }
            set { SetValue(BlueProperty, value); }
        }

        public static readonly DependencyProperty ColorProperty =
            DependencyProperty.Register("Color", typeof(Color), typeof(ColorPicker), new PropertyMetadata(Colors.Black, OnColorChanged));

        public static readonly DependencyProperty RedProperty =
            DependencyProperty.Register("Red", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

        public static readonly DependencyProperty GreenProperty =
            DependencyProperty.Register("Green", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

        public static readonly DependencyProperty BlueProperty =
            DependencyProperty.Register("Blue", typeof(byte), typeof(ColorPicker), new PropertyMetadata(OnColorRGBChanged));

        private static void OnColorRGBChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorPicker uc = (ColorPicker)d;
            Color color = uc.Color;
            if (e.Property == RedProperty)
            {
                color.R = (byte)e.NewValue;
            }
            else if (e.Property == GreenProperty)
            {
                color.G = (byte)e.NewValue;
            }
            else if (e.Property == BlueProperty)
            {
                color.B = (byte)e.NewValue;
            }
            uc.Color = color;
        }

        private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ColorPicker uc = (ColorPicker)d;
            Color color = (Color)e.NewValue;
            uc.Red = color.R;
            uc.Green = color.G;
            uc.Blue = color.B;

            Color oldColor = (Color)e.OldValue;
            uc.PreviousColor = oldColor;

            RoutedPropertyChangedEventArgs<Color> args = new RoutedPropertyChangedEventArgs<Color>(oldColor, color);
            args.RoutedEvent = ColorChangedEvent;
            uc.RaiseEvent(args);

        }


        public static readonly RoutedEvent ColorChangedEvent = EventManager.RegisterRoutedEvent("ColorChanged", RoutingStrategy.Bubble,
            typeof(RoutedPropertyChangedEventHandler<Color>), typeof(ColorPickerUserControl));

        public event RoutedPropertyChangedEventHandler<Color> ColorChanged
        {
            add { AddHandler(ColorChangedEvent, value); }
            remove { RemoveHandler(ColorChangedEvent, value); }
        }


        Color? PreviousColor;


        public ColorPicker()
        {
            CommandBinding binding = new CommandBinding(ApplicationCommands.Undo,
              UndoCommand_Executed, UndoCommand_CanExecute);

            this.CommandBindings.Add(binding);
        }

        private void UndoCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = PreviousColor.HasValue;
        }

        private void UndoCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.Color = (Color)PreviousColor;
        }

        static ColorPicker()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorPicker), new FrameworkPropertyMetadata(typeof(ColorPicker)));
        }
    }
}

3 新建Themes文件夹,并新建generic.xaml资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:CustomControl.Themes">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/CustomControl;component/Themes/ColorPicker.xaml" />
    </ResourceDictionary.MergedDictionaries>
    
</ResourceDictionary>

同时在Themes下面新建ColorPicker.xaml资源字典,该字典定义了默认的样式,注意需要将local的命名空间修改为 xmlns:local="clr-namespace:CustomControl",才能访问到ColorPicker类,另外注意,Slider的Value属性需要双向绑定,所以使用RelativeResource来绑定到父控件,而不能用TemplatedBinding,这个只是单向绑定

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:CustomControl">
    <Style TargetType="{x:Type local:ColorPicker}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ColorPicker}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="Auto"></RowDefinition>
                            <RowDefinition Height="Auto"></RowDefinition>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition Width="Auto"></ColumnDefinition>
                        </Grid.ColumnDefinitions>

                        <Slider Minimum="0" Maximum="255" Margin="{TemplateBinding Padding}" 
                                Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Red}" />

                        <Slider Grid.Row="1" Minimum="0" Maximum="255" Margin="{TemplateBinding Padding}" 
                                Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Green}" />

                        <Slider Grid.Row="2" Minimum="0" Maximum="255" Margin="{TemplateBinding Padding}" 
                                Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Blue}"></Slider>


                        <Rectangle Grid.Column="1" Grid.RowSpan="3" Margin="{TemplateBinding Padding}" Width="50" Stroke="Black" StrokeThickness="1">
                            <Rectangle.Fill>
                                <SolidColorBrush Color="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Color}"></SolidColorBrush>
                            </Rectangle.Fill>
                        </Rectangle>

                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
</ResourceDictionary>

4 主程序

<Window x:Class="CustomControlApp.ColorPickerTwoWays"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:CustomControlApp"
        xmlns:lib="clr-namespace:CustomControl;assembly=CustomControl"
        mc:Ignorable="d"
        Title="ColorPickerTwoWays" Height="450" Width="800">
    <StackPanel>
        <lib:ColorPicker
      Name="colorPicker1" Margin="2" Padding="3" Color="AliceBlue"></lib:ColorPicker>
       

    </StackPanel>
</Window>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值