背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性

原文:背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性

[源码下载]

作者:webabcd

介绍
背水一战 Windows 10 之 控件(自定义控件)

  • 自定义控件的基础知识,依赖属性和附加属性

示例
演示自定义控件的基础知识,依赖属性和附加属性
1、自定义控件的示例
/MyControls/themes/generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <!--
        在 themes/generic.xaml 中定义自定义控件的默认样式
    -->
    <ResourceDictionary.MergedDictionaries>
        <!--
            注意:
            此处在指定 xaml 路径时,要以“项目名”为根路径(因为这个自定控件的项目是要被别的项目引用的)
            这个是对的 ms-appx:///MyControls/themes/MyControl1.xaml
            这个是错的 ms-appx:///themes/MyControl1.xaml(编译时不会报错,运行时会报错 Failed to assign to property ‘Windows.UI.Xaml.ResourceDictionary.Source‘ because the type ‘Windows.Foundation.String‘ cannot be assigned to the type ‘Windows.Foundation.Uri‘)
        -->
        <ResourceDictionary Source="ms-appx:///MyControls/themes/MyControl1.xaml"/>
        <ResourceDictionary Source="ms-appx:///MyControls/themes/MyControl3.xaml"/>
    </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

/MyControls/themes/MyControl1.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:MyControl1">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyControl1">
                    <!--
                        绑定基类中定义的依赖属性
                    -->
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                        <StackPanel>

                            <!--
                                绑定自定义依赖属性
                            -->
                            <TextBlock Text="{TemplateBinding Title}" Foreground="White" FontSize="24" />

                            <!--
                                绑定自定义附加属性
                            -->
                            <TextBlock Text="{TemplateBinding local:MyAttachedProperty.SubTitle}" Foreground="Orange" FontSize="24" />

                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

/MyControls/MyAttachedProperty.cs

/*
 * 定义一个附加属性(Attached Property)
 *
 * 依赖属性:可以用于样式, 模板, 绑定, 动画
 * 附加属性:全局可用的依赖属性
 */

using Windows.UI.Xaml;

namespace MyControls
{
    /// <summary>
    /// 定义一个附加属性(Attached Property)
    /// </summary>
    public sealed 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);
        }

        // 注册一个附加属性(winrc 中不支持 public 类型的 field,如果是 dll 项目则无此限制)
        private static readonly DependencyProperty SubTitlePropertyField =
            DependencyProperty.RegisterAttached(
                "SubTitle", // 附加属性的名称
                typeof(string), // 附加属性的数据类型
                typeof(MyAttachedProperty), // 附加属性所属的类
                new PropertyMetadata("", PropertyMetadataCallback)); // 指定附加属性的默认值,以及值发生改变时所调用的方法

        // 用属性的方式封装一下 SubTitlePropertyField
        public static DependencyProperty SubTitleProperty
        {
            get
            {
                return SubTitlePropertyField;
            }
        }

        private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            object newValue = args.NewValue; // 发生改变之后的值
            object oldValue = args.OldValue; // 发生改变之前的值
        }
    }
}

/MyControls/MyControl1.cs

/*
 * 开发一个自定义控件,并定义一个依赖属性(Dependency Property)
 *
 * 依赖属性:可以用于样式, 模板, 绑定, 动画
 * 附加属性:全局可用的依赖属性
 */

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;

namespace MyControls
{
    /// <summary>
    /// 开发一个自定义控件,并定义一个依赖属性(Dependency Property)
    /// </summary>
    // 注意:
    // 在 winrc 中用 c# 写的类必须是 sealed 的(否则编译时会报错 Exporting unsealed types is not supported.Please mark type ‘MyControls.MyControl1‘ as sealed)
    // 如果是 dll 项目则无此限制
    public sealed class MyControl1 : Control
    {
        public MyControl1()
        {
            // 指定默认样式为 typeof(MyControl1),即使用 TargetType 为 MyControl1 的样式,即 <Style xmlns:local="using:MyControls" TargetType="local:MyControl1" />
            // 如果不指 DefaultStyleKey 的话,则默认使用基类即 Control 的样式
            this.DefaultStyleKey = typeof(MyControl1);
        }

        // 通过 DependencyObject.GetValue() 和 DependencyObject.SetValue() 访问依赖属性,这里由 Title 属性封装一下,以方便对依赖属性的访问
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        // 注册一个依赖属性
        // 注意:
        // 在 winrc 中不支持 public 类型的 field(在 dll 项目无此限制),所以这里改为 private 的,之后再用 public 属性的方式封装一下即可
        // 如果使用了 public 类型的 field 的话,编译时会报错 Type ‘MyControls.MyControl1‘ contains externally visible field ‘Windows.UI.Xaml.DependencyProperty MyControls.MyControl1.TitlePropertyField‘.  Fields can be exposed only by structures
        private static readonly DependencyProperty TitlePropertyField =
            DependencyProperty.Register(
                "Title", // 依赖属性的名称
                typeof(string),  // 依赖属性的数据类型
                typeof(MyControl1),  // 依赖属性所属的类
                new PropertyMetadata("", PropertyMetadataCallback)); // 指定依赖属性的默认值,以及值发生改变时所调用的方法

        // 用属性的方式封装一下 TitlePropertyField
        public static DependencyProperty TitleProperty
        {
            get
            {
                return TitlePropertyField;
            }
        }

        private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            object newValue = args.NewValue; // 发生改变之后的值
            object oldValue = args.OldValue; // 发生改变之前的值
        }
    }
}

2、调用自定义控件的示例
Controls/CustomControl/Demo1.xaml

<Page
    x:Class="Windows10.Controls.CustomControl.Demo1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.Controls.CustomControl"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"

    xmlns:myControls="using:MyControls">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <!--
                演示自定义控件的基础知识,依赖属性和附加属性
                本例所用到的自定义控件请参看:MyControls/MyControl1.cs
            -->

            <!--
                依赖属性和附加属性可以用于绑定
            -->
            <myControls:MyControl1 x:Name="control1" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5"
                                   Title="{Binding Value, ElementName=slider}"
                                   myControls:MyAttachedProperty.SubTitle="{Binding Value, ElementName=slider}">
            </myControls:MyControl1>
            <Slider Name="slider" Width="200" Minimum="0" Maximum="200" IsThumbToolTipEnabled="False" HorizontalAlignment="Left" Margin="5" Foreground="Orange" Background="White" Style="{StaticResource MySliderStyle}" />

            <!--
                依赖属性和附加属性可以用于 Storyboard 动画
                但是无法通过 Storyboard 对自定义附加属性做动画,在文档中找到了这样一句话“However, an existing limitation of the Windows Runtime XAML implementation is that you cannot animate a custom attached property.”
            -->
            <myControls:MyControl1 x:Name="control2" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5">
                <myControls:MyControl1.Resources>
                    <BeginStoryboard x:Name="storyboard1">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="control2" Storyboard.TargetProperty="Title" Duration="0:0:10" RepeatBehavior="Forever">
                                <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="w" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:2" Value="we" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:3" Value="web" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:4" Value="weba" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:5" Value="webab" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:6" Value="webabc" />
                                <DiscreteObjectKeyFrame KeyTime="0:0:7" Value="webabcd" />
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </myControls:MyControl1.Resources>
            </myControls:MyControl1>

            <!--
                在 code-behind 中设置依赖属性和附加属性
            -->
            <myControls:MyControl1 x:Name="control3" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5" />

        </StackPanel>
    </Grid>
</Page>

Controls/CustomControl/Demo1.xaml.cs

/*
 * 本例用于演示自定义控件的基础知识,依赖属性和附加属性
 */

using MyControls;
using Windows.UI.Xaml.Controls;

namespace Windows10.Controls.CustomControl
{
    public sealed partial class Demo1 : Page
    {
        public Demo1()
        {
            this.InitializeComponent();

            this.Loaded += Demo1_Loaded;
        }

        private void Demo1_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            // 设置依赖属性
            control3.Title = "我是依赖属性";

            // 设置附加属性
            control3.SetValue(MyAttachedProperty.SubTitleProperty, "我是附加属性");
        }
    }
}

OK
[源码下载]

原文地址:https://www.cnblogs.com/lonelyxmas/p/8527046.html

时间: 2024-10-03 17:52:12

背水一战 Windows 10 (78) - 自定义控件: 基础知识, 依赖属性, 附加属性的相关文章

背水一战 Windows 10 (87) - 文件系统: 获取文件的属性, 修改文件的属性, 获取文件的缩略图

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 文件系统 获取文件的属性 修改文件的属性 获取文件的缩略图 示例1.演示如何获取文件的属性,修改文件的属性FileSystem/FileProperties.xaml <Page x:Class="Windows10.FileSystem.FileProperties" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentatio

背水一战 Windows 10 (56) - 控件(集合类): ListViewBase - 基础知识, 拖动项

原文:背水一战 Windows 10 (56) - 控件(集合类): ListViewBase - 基础知识, 拖动项 [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(集合类 - ListViewBase) 基础知识 拖动项 示例1.ListViewBase 的基础知识Controls/CollectionControl/ListViewBaseDemo/ListViewBaseDemo1.xaml <Page x:Class="Windows10.Con

背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, ListViewItemPresenter

原文:背水一战 Windows 10 (50) - 控件(集合类): ItemsControl - 基础知识, 数据绑定, ItemsPresenter, GridViewItemPresenter, ListViewItemPresenter [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(集合类 - ItemsControl) 基础知识 数据绑定 ItemsPresenter GridViewItemPresenter ListViewItemPresent

背水一战 Windows 10 (46) - 控件(ScrollViewer 基础): ScrollViewer, ScrollBar, ScrollContentPresenter

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(ScrollViewer 基础) ScrollViewer ScrollBar ScrollContentPresenter 示例1.ScrollViewer 的基本应用Controls/ScrollViewerDemo/ScrollViewerDemo.xaml <Page x:Class="Windows10.Controls.ScrollViewerDemo.ScrollViewerDemo"

背水一战 Windows 10 (26) - XAML: x:DeferLoadStrategy, x:Null

原文:背水一战 Windows 10 (26) - XAML: x:DeferLoadStrategy, x:Null [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 XAML x:DeferLoadStrategy="Lazy" - 用于指定一个 UIElement 为一个延迟加载元素 x:Null - null 示例1.x:DeferLoadStrategy 通过 FindName 加载Xaml/DeferLoadStrategy/Demo1.xaml

背水一战 Windows 10 (60) - 控件(媒体类): Pointer 涂鸦板, InkCanvas 涂鸦板

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(媒体类) 通过处理 Pointer 相关事件实现一个简单的涂鸦板 InkCanvas 基础知识 示例1.演示如何通过 Pointer 相关事件的处理,来实现一个简单的涂鸦板Controls/MediaControl/InkSimple.xaml <Page x:Class="Windows10.Controls.MediaControl.InkSimple" xmlns="http://s

背水一战 Windows 10 (77) - 控件(控件基类): ContentControl, UserControl, Page

原文:背水一战 Windows 10 (77) - 控件(控件基类): ContentControl, UserControl, Page [源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(控件基类 - ContentControl, UserControl, Page) ContentPresenter ContentControl UserControl Page 示例1.演示 ContentPresenter 的基础知识Controls/BaseContro

背水一战 Windows 10 (102) - 应用间通信: 剪切板

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 应用间通信 剪切板 - 基础, 复制/粘贴 text 内容 剪切板 - 复制/粘贴 html 内容 剪切板 - 复制/粘贴 bitmap 内容,延迟复制 剪切板 - 复制/粘贴文件 示例1.演示剪切板的基础知识,以及如何复制 text 数据到剪切板,以及如何从剪切板中获取 text 数据 App2AppCommunication/Clipboard.xaml <Page x:Class="Windows10.App

背水一战 Windows 10 (58) - 控件(集合类): ListViewBase - ListView, GridView

[源码下载] 作者:webabcd 介绍背水一战 Windows 10 之 控件(集合类 - ListViewBase) ListView GridView 示例1.ListView 的示例Controls/CollectionControl/ListViewBaseDemo/ListViewDemo.xaml <Page x:Class="Windows10.Controls.CollectionControl.ListViewDemo" xmlns="http://