原文:wpf控件开发基础(5) -依赖属性实践

知识回顾

接上篇,回顾这三篇讲了什么东西

首先说明了属性的现存问题,然后介绍了依赖属性的基本用法及其解决方案,由于依赖属性以静态属性的方式存在,进而又介绍了可重写的属性元数据的使用.这是以上三篇所说明的问题.当然依赖属性的特性依然没有说完整.这两天也一直在想依赖属性,然后就是头疼,呵呵.由于WPF的依赖属性系统与整体功能都有关联,所以接下来等讲到某个特性的时候然后再来讲依赖属性.这篇我们来个简单的实践,增加点乐趣.

定义RadioButtonList和CheckBoxList

WPF内置没有这两个控件,但实际开发时,用到的会比较多.下面我们一起来创建这两个控件.

  1. 明确控件需求
  2. 定义依赖属性
  3. 重写默认样式属性元数据
  4. 用xaml定义控件样式

一.明确控件需求

控件功能如下:

  1. 可以垂直,水平排列
  2. 可以分行,列
  3. 为子项设置Margin

二.定义依赖属性

为避免重复定义属性,为两个控件定义公共类ListControl,从ListBox继承

然后定义依赖属性

namespace WPF.Controls
{
/// <summary>
/// this is a base class for CheckBoxList and RadioButtonList
/// this class define some common property
/// </summary>
public abstract class ListControl : ListBox
{ #region Orientation /// <summary>
/// Gets or sets a value that indicates the dimension by which child elements are stacked.
/// This is a dependency property.
/// </summary>
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
} public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ListControl),
new UIPropertyMetadata(Orientation.Vertical, new PropertyChangedCallback(OrientationChangedCallback))); public static void OrientationChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListControl control = d as ListControl;
if (control.Orientation == Orientation.Horizontal)
{
control.Columns = 0;
control.Rows = 1;
}
else if (control.Orientation == Orientation.Vertical)
{
control.Rows = 0;
control.Columns = 1;
}
} #endregion #region Columns /// <summary>
/// Get or set a value that indicates which Columns list item should appear in.
/// This is a dependency property.
/// </summary>
public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
} public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register("Columns", typeof(int), typeof(ListControl), new UIPropertyMetadata(1)); #endregion #region Rows /// <summary>
/// Get or set a value that indicates which Rows list item should appear in.
/// This is a dependency property.
/// </summary>
public int Rows
{
get { return (int)GetValue(RowsProperty); }
set { SetValue(RowsProperty, value); }
} public static readonly DependencyProperty RowsProperty =
DependencyProperty.Register("Rows", typeof(int), typeof(ListControl), new UIPropertyMetadata(0)); #endregion public Thickness SubMargin
{
get { return (Thickness)GetValue(SubMarginProperty); }
set { SetValue(SubMarginProperty, value); }
} public static readonly DependencyProperty SubMarginProperty =
DependencyProperty.Register("SubMargin", typeof(Thickness), typeof(ListControl),
new UIPropertyMetadata(new Thickness(2,2,2,0))); }
}

以上依赖属性定义的非常简单,之所以定义成依赖属性是因为可以进行属性绑定操作.

三.重写默认样式属性元数据

/// <summary>
/// Represents a control that a user can choose one from list options in a group radiobutton
/// </summary>
public class RadioButtonList : ListControl
{
static RadioButtonList()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(RadioButtonList)
, new FrameworkPropertyMetadata(typeof(RadioButtonList)));
}
} /// <summary>
/// Contains a list of selectable CheckBox items
/// Represents a control that a user can choose from a list options in a group of CheckBox
/// </summary>
public class CheckBoxList : ListControl
{
static CheckBoxList()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CheckBoxList)
, new FrameworkPropertyMetadata(typeof(CheckBoxList)));
}
}

四.用xaml定义控件样式

默认项目中会有一个Generic.xaml文件,我们要把样式定义在此文件中

控件样式定义

(1)ListControl

<Style TargetType="{x:Type local:ListControl}" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid HorizontalAlignment="Left" VerticalAlignment="Top"
Rows="{Binding Path=Rows,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:ListControl}}}"
Columns="{Binding Path=Columns,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:ListControl}}}"></UniformGrid>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
</Style>

(2)RadioButtonList

<Style TargetType="{x:Type local:RadioButtonList}" BasedOn="{StaticResource {x:Type local:ListControl}}">
<Style.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="2, 2, 2, 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<RadioButton
Margin="{Binding Path=SubMargin,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:RadioButtonList}}}"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}">
<RadioButton.Content>
<ContentPresenter/>
</RadioButton.Content>
</RadioButton>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>

(3)CheckBoxList

<Style TargetType="{x:Type local:CheckBoxList}" BasedOn="{StaticResource {x:Type local:ListControl}}">
<Setter Property="SelectionMode" Value="Multiple"></Setter>
<Style.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="2, 2, 2, 0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<CheckBox
Margin="{Binding Path=SubMargin,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type local:RadioButtonList}}}"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}">
<CheckBox.Content>
<ContentPresenter/>
</CheckBox.Content>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>

OK,到这里就完事了.我们发现我们并不需要写多少代码,就可以实现一个控件.而且RadioButtonList和CheckBoxList几乎没有代码,仅仅只是重写了样式而已,这也是WPF定义控件的基本概念,一些变的都是如此简单.

Demo下载

最新文章

  1. css单位:em,rem解释
  2. python 之 推导式
  3. IT公司100题-17-第一个只出现一次的字符
  4. 操作笔记:tomcat在正式环境
  5. java RuntimeException
  6. Hadoop 的子项目
  7. sqlite命令
  8. (6)Xamarin.android google map v2
  9. [2015-11-23]分享一个批处理脚本,创建iis站点及程序池
  10. SpringBoot中使用JNnit4(一)之Mockito的使用
  11. ubuntu server 16.04 安装过程中提示无法安装busybox-initramfs
  12. [CERC2017] Intrinsic Interval
  13. 20, CSS 定义选择器
  14. Java并发(二)—— 并发编程的挑战 与 并发机制的底层原理
  15. repo 获取各个库的tag代码或者分支代码
  16. Java 猜字谜游戏
  17. R语言学习笔记(五)绘图(1)
  18. Odoo中连接mysql数据库
  19. H5添加禁止缩放功能
  20. 【Python】使用torrentParser1.02对单文件torrent的分析结果

热门文章

  1. Redis笔记---set
  2. HDU 2147kiki&#39;s game
  3. get_mysql_conn_info.py
  4. POJ 2546 Circular Area 几何
  5. DOCKER学习心得
  6. opencv播放不了AVI视频的问题
  7. POJ 3132 &amp;amp; ZOJ 2822 Sum of Different Primes(dp)
  8. HDU1248 寒冰王座 【数学题】or【全然背包】
  9. crontab经验 分类: B3_LINUX 2015-03-06 11:17 282人阅读 评论(0) 收藏
  10. TensorFlow on Windows: “Couldn't open CUDA library cudnn64_5.dll”