WPF 定义自己的控件

最近在研究怎么制作自己的控件,制作好了之后给别人用,别人只需要修改控件的相关属性就可以适应他的需求,而无需去修改控件的模板。先上图再解释。 
以下是我自己制作的控件截图: 
温度计: 
这里写图片描述
模拟微信文章后面的摆球: 
这里写图片描述 
这里写图片描述 
由于是摆动的,截图看效果不明显,下载源码看 
以下是我借鉴别人的加以改进的控件 
进度条: 
这里写图片描述 
win8转圈等待控件: 
这里写图片描述 
这里写图片描述 
以下是纯别人写的 
油表: 
这里写图片描述 
转圈等待:(这个控件是Winform的,也可以用到WPF) 
这里写图片描述 
最后再晒一张将控件用在项目中的图片的效果: 
这里写图片描述
本文所有控件打包下载地址

自定义控件的过程: 
1.新建一个WPF custom control library: 
这里写图片描述
2.新建成功后,会自动生成一个类(.cs)文件和一个资源字典(Generic.xaml)文件,其中Generic.xaml在项目的Themes文件夹下: 
这里写图片描述 
接着就在类中定义我们的属性、依赖属性以及方法、依赖属性变化的回调方法。

经验总结: 
1.注册属性和普通属性的区别?什么时候定义普通属性,什么时候定义注册属性并与依赖属性关联? 
普通属性:

private int successRate = 100;
        public int SuccessRate
        {
            get
            {
                return successRate;
            }
            set
            {
                if (value != successRate)
                {
                    successRate = value;
                    OnPropertyChanged("SuccessRate");
                }
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

注册属性:(与依赖属性关联)

 public static readonly DependencyProperty MeterHeightProperty =
         DependencyProperty.Register("MeterHeight", typeof(double), typeof(TemperatureGuageControl),new PropertyMetadata((double)100, new PropertyChangedCallback(TemperatureGuageControl.OnAllChanged)));

 [Description("设置进度条的高度"), Category(TemperatureGuageControl.meterInfo)]
 public double MeterHeight
 {
     get { return (double)GetValue(MeterHeightProperty); }
     set { SetValue(MeterHeightProperty, value); }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

当这两种类型的属性与空间模板的元素属性绑定时: 
普通属性绑定方法:(与MVVM模式一样) 
1.在构造函数中:this.DataContext=this 
2.绑定时:(在Generic.xaml中)

<ProgressBar Minimum="0" Maximum="100" Value="{Binding SuccessRate, Mode=OneWay}">
  • 1

注册属性绑定方法:(在Generic.xaml中)

<Canvas x:Name="rootCanvas" Background="Gray" Height="{Binding MeterHeight, RelativeSource={RelativeSource TemplatedParent}}" Width="{Binding MeterWidth, RelativeSource={RelativeSource TemplatedParent}}" Margin="{Binding MeterMargin,RelativeSource={RelativeSource TemplatedParent}}">
  • 1

而当注册属性值发生变化通知的方法可在注册时的回调方法中处理。 
使用场景: 
当属性变化要执行一段动画或者要动态加载、生成或布局模板中的子控件时,使用注册属性,其他情况,可以使用普通属性,也可以使用注册属性,一般使用普通属性,这样简便一些。 
例如温度计的主刻度个数属性,当主刻度个数变化时,要重新计算并动态生成其他刻度,此时必须使用注册属性。 
2.使用注册属性时,默认值第一次加载控件没有应用上,在类中重写OnApplyTemplate方法,使用GetTemplateChild获得的控件为空的解决方法: 
出现的原因为控件第一次还没有完全把子控件加载完就调用了OnApplyTemplate方法,所以要在控件加载完之后再调用OnApplyTemplate方法:

 static  TemperatureGuageControl()
       {
           DefaultStyleKeyProperty.OverrideMetadata(typeof(TemperatureGuageControl), new FrameworkPropertyMetadata(typeof(TemperatureGuageControl)));
       }
       public TemperatureGuageControl()
       {
           this.Loaded += TemperatureGuageControl_Loaded;
       }

       void TemperatureGuageControl_Loaded(object sender, RoutedEventArgs e)
       {
           this.OnApplyTemplate();
           CurrentValueChanged(new DependencyPropertyChangedEventArgs(TemperatureGuageControl.CurrentValueProperty, 0, 0));
       }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

以上两点是个人经验,如果有错误之处,请指正。 
本文所有控件打包资源下载

猜你喜欢

转载自blog.csdn.net/bruce135lee/article/details/81111061