• 重新想象 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
    [源码下载]

  • 相关阅读:
    使用 Eclipse 调试 Java 程序的 10 个技巧
    oracle9i,10g再谈优化模式参数问题.
    oracle 索引
    解决IE不能在新窗口中向父窗口的下拉框添加项的问题
    获取文档的尺寸:利用Math.max的另一种方式
    揭开constructor属性的神秘面纱
    测试杂感:Windows8也许需要Account Hub
    探索式测试:探索是为了学习
    一次有教益的程序崩溃调试 (下)
    软件测试读书列表 (2013.8)
  • 原文地址:https://www.cnblogs.com/webabcd/p/2992689.html
Copyright © 2020-2023  润新知