原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

[源码下载]

重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

作者:webabcd

介绍
重新想象 Windows 8 Store Apps 之 控件基础

  • DependencyProperty - 依赖属性
  • AttachedProperty - 附加属性
  • 控件的继承关系
  • 路由事件和命中测试

示例
1、开发一个具有 DependencyProperty 和 AttachedProperty 的自定义控件
MyControls/themes/generic.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyControls"> <!--
自定义控件的样式在本文件(themes/generic.xaml)中定义 整合外部 ResourceDictionary
-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///MyControls/themes/MyControl.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary>

MyControls/themes/MyControl.xaml

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyControls">
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:MyControl">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<!--绑定自定义依赖属性-->
<TextBlock Text="{TemplateBinding Title}" Foreground="White" FontSize="26.667" /> <!--绑定自定义附加属性-->
<TextBlock Text="{TemplateBinding local:MyAttachedProperty.SubTitle}" Foreground="White" FontSize="14.667" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

MyControls/MyControl.cs

/*
* 开发一个自定义控件,用于演示依赖属性(Dependency Property)和附加属性(Attached Property)
*
* 依赖属性:可以用于样式, 模板, 绑定, 动画
* 附加属性:全局可用的依赖属性
*/ using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml; namespace MyControls
{
/// <summary>
/// 用于依赖属性的演示
/// </summary>
public class MyControl : Control
{
public MyControl()
{
// 指定默认样式为 typeof(MyControl),即对应:<Style xmlns:local="using:MyControls" TargetType="local:MyControl" />
this.DefaultStyleKey = typeof(MyControl);
} // 通过 DependencyObject.GetValue() 和 DependencyObject.SetValue() 访问依赖属性,这里由 Title 属性封装一下,以方便对依赖属性的访问
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
} // 注册一个依赖属性
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register(
"Title", // 依赖属性的名称
typeof(string), // 依赖属性的数据类型
typeof(MyControl), // 依赖属性所属的类
new PropertyMetadata("", PropertyMetadataCallback)); // 指定依赖属性的默认值,以及值发生改变时所调用的方法 private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
object newValue = args.NewValue; // 发生改变之后的值
object oldValue = args.OldValue; // 发生改变之前的值
}
} /// <summary>
/// 用于附加属性的演示
/// </summary>
public class MyAttachedProperty
{
// 获取附加属性
public static string GetSubTitle(DependencyObject obj)
{
return (string)obj.GetValue(SubTitleProperty);
} // 设置附加属性
public static void SetSubTitle(DependencyObject obj, string value)
{
obj.SetValue(SubTitleProperty, value);
} // 注册一个附加属性
public static readonly DependencyProperty SubTitleProperty =
DependencyProperty.RegisterAttached(
"SubTitle", // 附加属性的名称
typeof(string), // 附加属性的数据类型
typeof(MyAttachedProperty), // 附加属性所属的类
new PropertyMetadata("", PropertyMetadataCallback)); // 指定附加属性的默认值,以及值发生改变时所调用的方法 private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
object newValue = args.NewValue; // 发生改变之后的值
object oldValue = args.OldValue; // 发生改变之前的值
}
}
}

2、演示依赖属性的使用
Controls/Basic/DependencyPropertyDemo.xaml

<Page
x:Class="XamlDemo.Controls.Basic.DependencyPropertyDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Controls.Basic"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:myControls="using:MyControls"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <!--
演示如何开发和使用自定义依赖属性(本例所用到的自定义控件请参看:MyControls/MyControl.cs)
-->
<myControls:MyControl Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="100" HorizontalAlignment="Left"
Title="{Binding Value, ElementName=slider}" /> <Slider Name="slider" Width="100" Minimum="0" Maximum="200" IsThumbToolTipEnabled="False" HorizontalAlignment="Left" /> </StackPanel>
</Grid>
</Page>

3、演示附加属性的使用
Controls/Basic/AttachedPropertyDemo.xaml

<Page
x:Class="XamlDemo.Controls.Basic.AttachedPropertyDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Controls.Basic"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:myControls="using:MyControls"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <!--
演示如何开发和使用自定义附加属性(本例所用到的自定义控件请参看:MyControls/MyControl.cs)
-->
<myControls:MyControl Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="100" HorizontalAlignment="Left"
Title="{Binding Value, ElementName=slider}" myControls:MyAttachedProperty.SubTitle="{Binding Value, ElementName=slider}" /> <Slider Name="slider" Width="100" Minimum="0" Maximum="200" IsThumbToolTipEnabled="False" HorizontalAlignment="Left" /> </StackPanel>
</Grid>
</Page>

4、控件的继承关系的概述
Controls/Basic/Inherit.xaml

<Page
x:Class="XamlDemo.Controls.Basic.Inherit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Controls.Basic"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" LineHeight="25">
<Run>继承关系: FrameworkElement -> UIElement -> DependencyObject</Run>
<LineBreak />
<Run>DependencyObject - 提供对依赖属性的访问,以及获取此对象关联的 CoreDispatcher</Run>
<LineBreak />
<Run>UIElement - 可视元素,键盘和鼠标输入等</Run>
<LineBreak />
<Run>FrameworkElement - 框架元素,数据绑定,一些公共 API 等。例:Control, TextBlock, WebView 等继承自 FrameworkElement</Run>
<LineBreak />
<Run>ContentControl - 其内包含有一个内容,继承自 Control。例:ScrollViewer, AppBar 等继承自 ContentControl</Run>
<LineBreak />
<Run>ButtonBase - 按钮的基本功能,继承自 ContentControl。例:Button, RepeatButton 等继承自 ButtonBase</Run>
<LineBreak />
<Run>ToggleButton - 可切换状态的按钮,继承自 ButtonBase。例:RadioButton, CheckBox 等继承自 ToggleButton</Run>
<LineBreak />
<Run>RangeBase - 值在某一范围内,继承自 ButtonBase。例:ProgressBar, Slider, ScrollBar 等继承自 RangeBase</Run>
<LineBreak />
<Run>ItemsControl - 用于呈现集合,继承自 Control</Run>
<LineBreak />
<Run>Selector - 可选择集合中的某一项,继承自 ItemsControl。例:ComboBox, ListBox, FlipView, ListViewBase 等继承自 Selector</Run>
<LineBreak />
<Run>ListViewBase - 继承自 ListViewBase 的控件有 GridView 和 ListView</Run>
<LineBreak />
<Run>Panel - 一个容器,继承自 FrameworkElement。例:Grid, StackPanel, Canvas 等继承自 Panel</Run>
<LineBreak />
<Run>如 ScrollBar, Thumb, RangeBase, ButtonBase, Selector, Popup 等这类基元控件在 Windows.UI.Xaml.Controls.Primitives 命名空间下</Run>
</TextBlock> </StackPanel>
</Grid>
</Page>

5、路由事件和命中测试
Controls/Basic/RoutedEventDemo.xaml

<Page
x:Class="XamlDemo.Controls.Basic.RoutedEventDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Controls.Basic"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<!--
演示事件冒泡:儿子传递事件给爸爸,爸爸传递事件给爷爷,这就是事件冒泡
-->
<Border Name="borderRed" Background="Red" Width="300" Height="300">
<Border Name="borderGreen" Background="Green" Width="250" Height="250" Tapped="borderGreen_Tapped_1">
<Border Name="borderBlue" Background="Blue" Width="200" Height="200" Tapped="borderBlue_Tapped_1">
<Border Name="borderOrange" Background="Orange" Width="150" Height="150" Tapped="borderOrange_Tapped_1">
<!--命中测试不可见,也就是说 borderPurple 和 borderYellow 均命中测试不可见-->
<Border Name="borderPurple" Background="Purple" Width="100" Height="100" Tapped="borderPurple_Tapped_1" IsHitTestVisible="False">
<Border Name="borderYellow" Background="Yellow" Width="50" Height="50" Tapped="borderYellow_Tapped_1" />
</Border>
</Border>
</Border>
</Border>
</Border> <!--
像这样排列元素,是没有事件冒泡的,而只是前面的元素响应事件,后面的元素不会响应事件,也就是说同辈间没有事件冒泡的概念
IsHitTestVisible - 是否对命中测试可见
<Rectangle Name="rectangle1" Width="800" Height="400" Fill="Red" />
<Rectangle Name="rectangle2" Width="700" Height="350" Fill="Green" />
<Rectangle Name="rectangle3" Width="600" Height="300" Fill="Blue" />
<Rectangle Name="rectangle4" Width="500" Height="250" Fill="Orange" />
<Rectangle Name="rectangle5" Width="400" Height="200" Fill="Purple" />
-->
</Grid> <TextBlock Name="lblMsg" FontSize="14.667" Margin="0 10 0 0" /> </StackPanel>
</Grid>
</Page>

Controls/Basic/RoutedEventDemo.xaml.cs

/*
* 演示路由事件的冒泡和命中测试的可见性
*
* TappedRoutedEventArgs
* OriginalSource - 引发此路由事件的对象
* Handled - 是否将路由事件标记为已处理
* true - 不再冒泡
* false - 继续冒泡
*
* UIElement
* IsHitTestVisible - 是否对命中测试可见
*/ using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input; namespace XamlDemo.Controls.Basic
{
public sealed partial class RoutedEventDemo : Page
{
public RoutedEventDemo()
{
this.InitializeComponent(); // AddHandler() - 注册一个路由事件,注意最后一个参数:true 代表即使子辈 TappedRoutedEventArgs.Handled = true 也不会影响此元素事件的触发
// RemoveHandler() - 移除指定的路由事件
borderRed.AddHandler(UIElement.TappedEvent, new TappedEventHandler(borderRed_Tapped_1), true);
} private void borderRed_Tapped_1(object sender, TappedRoutedEventArgs e)
{
lblMsg.Text += "borderRed tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine;
} private void borderGreen_Tapped_1(object sender, TappedRoutedEventArgs e)
{
lblMsg.Text += "borderGreen tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine;
} private void borderBlue_Tapped_1(object sender, TappedRoutedEventArgs e)
{
lblMsg.Text += "borderBlue tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine; // 不会再冒泡,也就是说 borderGreen 无法响应 Tapped 事件,但是 borderRed 注册 Tapped 事件时 handledEventsToo = true,所以 borderRed 会响应 Tapped 事件
e.Handled = true;
} private void borderOrange_Tapped_1(object sender, TappedRoutedEventArgs e)
{
lblMsg.Text += "borderOrange tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine;
} private void borderPurple_Tapped_1(object sender, TappedRoutedEventArgs e)
{
// 不会响应此事件,因为 borderPurple 的 IsHitTestVisible = false
lblMsg.Text += "borderPurple tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine;
} private void borderYellow_Tapped_1(object sender, TappedRoutedEventArgs e)
{
// 不会响应此事件,因为 borderYellow 的爸爸 borderPurple 的 IsHitTestVisible = false
lblMsg.Text += "borderYellow tapped, originalSource: " + (e.OriginalSource as FrameworkElement).Name;
lblMsg.Text += Environment.NewLine;
}
}
}

OK
[源码下载]

重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试的更多相关文章

  1. 重新想象 Windows 8 Store Apps 系列文章索引

    [源码下载][重新想象 Windows 8.1 Store Apps 系列文章] 重新想象 Windows 8 Store Apps 系列文章索引 作者:webabcd 1.重新想象 Windows ...

  2. 重新想象 Windows 8 Store Apps (6) - 控件之媒体控件: Image, MediaElement

    原文:重新想象 Windows 8 Store Apps (6) - 控件之媒体控件: Image, MediaElement [源码下载] 重新想象 Windows 8 Store Apps (6) ...

  3. 重新想象 Windows 8 Store Apps (1) - 控件之文本控件: TextBlock, TextBox, PasswordBox, RichEditBox, RichTextBlock, RichTextBlockOverflow

    原文:重新想象 Windows 8 Store Apps (1) - 控件之文本控件: TextBlock, TextBox, PasswordBox, RichEditBox, RichTextBl ...

  4. 重新想象 Windows 8 Store Apps (17) - 控件基础: Measure, Arrange, GeneralTransform, VisualTree

    原文:重新想象 Windows 8 Store Apps (17) - 控件基础: Measure, Arrange, GeneralTransform, VisualTree [源码下载] 重新想象 ...

  5. 重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState, VisualStateManager

    原文:重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState ...

  6. 重新想象 Windows 8 Store Apps (14) - 控件 UI: RenderTransform, Projection, Clip, UseLayoutRounding

    原文:重新想象 Windows 8 Store Apps (14) - 控件 UI: RenderTransform, Projection, Clip, UseLayoutRounding [源码下 ...

  7. 重新想象 Windows 8 Store Apps (13) - 控件之 SemanticZoom

    原文:重新想象 Windows 8 Store Apps (13) - 控件之 SemanticZoom [源码下载] 重新想象 Windows 8 Store Apps (13) - 控件之 Sem ...

  8. 重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示

    原文:重新想象 Windows 8 Store Apps (12) - 控件之 GridView 特性: 拖动项, 项尺寸可变, 分组显示 [源码下载] 重新想象 Windows 8 Store Ap ...

  9. 重新想象 Windows 8 Store Apps (11) - 控件之 ListView 和 GridView

    原文:重新想象 Windows 8 Store Apps (11) - 控件之 ListView 和 GridView [源码下载] 重新想象 Windows 8 Store Apps (11) - ...

随机推荐

  1. ThinkPhp学习06

    原文:ThinkPhp学习06 一.简单学习修改用户信息模块 1.编写UserAction.class.php <?php class UserAction extends Action{ pu ...

  2. 对struts2的OGNL的理解

    OGNL:Object-Graph Navigation Language.对象图形化导航语言 OGNL是集成进struts2框架中比較强大的技术有助于传输数据和类型转换,OGNL由表达式语言和类型装 ...

  3. 8张图理解Java(转)

    一图胜千言,下面图解均来自Program Creek 网站的Java教程,目前它们拥有最多的票选.如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟. 1.字符串不变性 下面这张图展示了这段代码做 ...

  4. 让qt应用程序支持触摸

    一.设备驱动 我的触摸屏是usb接口的 可以参考下这2篇文件 http://blog.csdn.net/paomadi/article/details/8754783 usb触摸屏 http://bl ...

  5. ADO.NET之1-数据库连接---ShinePans

    ADO.NET技术主要包含Connection,Command,DataReader,DataAdapter,DateSet,DataTable等六种对象 1).Connection 对象的主要功能是 ...

  6. 微信 SDK 不能 分享

    说多了都是泪水,真的. 前段时间,做好了微信的分享功能,测试通过的,最近我又跑了一遍用例,发现不能启动微信客户端了,怎么都启动不了,日志如下:ignore wechat app signature v ...

  7. Accord.Net中决策树

    Accord.Net中决策树 决策树介绍 决策树是一类机器学习算法,可以实现对数据集的分类.预测等.具体请阅读我另一篇博客(http://www.cnblogs.com/twocold/p/54245 ...

  8. Cocos2dx3.4 VS2013无法打开包括文件extensions/ExtensionExport.h解决的方法

    本来打算看白鹭引擎的.可是又被叫回来研究新引擎呢,不搞不知道,一搞发现cocos2dx新版本号3.4又有了一些变化. 我查了网上的资源,都没有解决的方法.我如今应该是第一个出这个问题的解决的方法哦.. ...

  9. HTML学习笔记——各种居中对齐

    0.前言     水平居中基本方法--指定块的宽度并设定块的左右外边距为auto,上下外边距可取0,那么该块能够在父元素中水平居中. 样式例如以下: 1:margin:0px auto 2:margi ...

  10. poj3280(区间dp)

    题目连接:http://poj.org/problem?id=3280 题意:给定一个长度为m(m<=2000)的小写字母字符串,在给定组成该字符串的n(n<=26)个字符的添加和删除费用 ...