WPF基础教程之属性系统

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF基础教程之属性系统相关的知识,希望对你有一定的参考价值。

参考技术A Windows Presentation Foundation (WPF) 提供了一组服务 这些服务可用于扩展公共语言运行库 (CLR) 属性的功能 这些服务通常统称为 WPF 属性系统 由 WPF 属性系统支持的属性称为依赖项属性 本概述介绍 WPF 属性系统以及依赖项属性的功能 这包括如何在可扩展应用程序标记语言 (XAML) 中和代码中使用现有的依赖项属性 本概述还介绍了依赖项属性所特有的方面(如依赖项属性元数据) 并说明了如何在自定义类中创建自己的依赖项属性

  先决条件   本主题假设您在 CLR 和面向对象的编程方面有一些基础知识 若要采用本主题中的示例 还应当了解 XAML 并知道如何编写 WPF 应用程序

  依赖项属性和 CLR 属性   在 WPF 中 属性通常公开为公共语言运行库 (CLR) 属性 在基本级别 您可以在根本不知道这些属性实现为依赖项属性的情况下直接与它们交互 但是 您应当熟悉 WPF 属性系统的部分或全部功能 才能利用这些功能

  依赖项属性的用途在于提供一种方法来基于其他输入的值计算属性值 这些其他输入可以包括系统属性(如主题和用户首选项) 实时属性确定机制(如数据绑定和动画/演示图板) 重用模板(如资源和样式)或者通过与元素树中其他元素的父子关系来公开的值 另外 可以通过实现依赖项属性来提供独立验证 默认值 监视其他属性的更改的回调以及可以基于可能的运行时信息来强制指定属性值的系统 派生类还可以通过重写依赖项属性元数据(而不是重写现有属性的实际实现或者创建新属性)来更改现有属性的某些具体特征

  在 SDK 参考中 可以根据某个属性的托管引用页上是否存在 依赖项属性信息 部分来确定该属性是否为依赖项属性 依赖项属性信息 部分包括一个指向该依赖项属性的 DependencyProperty 标识符字段的链接 还包括一个为该属性设置的元数据选项的列表 每个类的重写信息以及其他详细信息

  依赖项属性支持 CLR 属性   依赖项属性和 WPF 属性系统通过提供一个支持属性的类型来扩展属性功能 这是使用私有字段支持该属性的标准模式的替代实现方法 该类型的名称是 DependencyProperty 定义 WPF 属性系统的另一个重要类型是 DependencyObject DependencyObject 定义可以注册和拥有依赖项属性的基类

  下面汇集了在本软件开发工具包 (SDK) 文档中 在讨论依赖项属性时所使用的术语

  依赖项属性 一个由 DependencyProperty 支持的属性

  依赖项属性标识符 一个 DependencyProperty 实例 在注册依赖项属性时作为返回值获得 之后将存储为一个类成员 在与 WPF 属性系统交互的许多 API 中 此标识符用作一个参数

  CLR 包装 属性的实际 get 和 set 实现 这些实现通过在 GetValue 和 SetValue 调用中使用依赖项属性标识符来合并此标识符 从而使用 WPF 属性系统为属性提供支持

  下面的示例定义 IsSpinning 依赖项属性 并说明 DependencyProperty 标识符与它所支持的属性之间的关系

WPF入门教程系列九——布局之DockPanel与ViewBox

七. DockPanel

DockPanel定义一个区域,在此区域中,您可以使子元素通过描点的形式排列,这些对象位于 Children 属性中。停靠面板其实就是在WinForm类似于Dock属性的元 素。DockPanel会对每个子元素进行排序,并停靠在面板的一侧,多个停靠在同侧的元素则按顺序排序。 

   如果将 LastChildFill 属性设置为 true(默认设置),那么无论对 DockPanel 的最后一个子元素设置的其他任何停靠值如何,该子元素都将始终填满剩余的空间。若要将子元素停靠在另一个方向,必须将 LastChildFill 属性设置为 false,还必须为最后一个子元素指定显式停靠方向。

默认情况下,面板元素并不接收焦点。要强制使面板元素接收焦点,请将 Focusable 属性设置为 true。

   注意:屏幕上 DockPanel 的子元素的位置由相关子元素的 Dock 属性以及这些子元素在 DockPanel 下的相对顺序确定。因此,具有相同 Dock 属性值的一组子元素在屏幕上的位置可能不同,具体取决于这些子元素在 DockPanel 下的顺序。子元素的顺序会影响定位,因为 DockPanel 会按顺序迭代其子元素,并根据剩余空间来设置每个子元素的位置。      

 

使用XAML代码实现如下图效果。图如下。

 

 

复制代码
<Window x:Class="WpfApp1.WindowDock"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="WindowDock" Height="300" Width="400">

    <Grid>

        <DockPanel Width="Auto" Height="Auto">

            <Button DockPanel.Dock="Left" Content="1" />

            <Button DockPanel.Dock="Top" Content="2" />

            <Button DockPanel.Dock="Right" Content="3" />

            <Button DockPanel.Dock="Bottom" Content="4" />

        

            <Button  HorizontalAlignment="Left"  Name="btnAddByCode" Height="22" Width="65" DockPanel.Dock=" Left "  Click="btnAddByCode_Click" >后台代码添加</Button>

 

        </DockPanel>

 

    </Grid>

</Window>
复制代码

 

 使用C#代码实现如下图效果。图如下。

复制代码
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

 

namespace WpfApp1

{

    /// <summary>

    /// WindowDock.xaml 的交互逻辑

    /// </summary>

    public partial class WindowDock : Window

    {

        public WindowDock()

        {

            InitializeComponent();

        }

 

        private void btnAddByCode_Click(object sender, RoutedEventArgs e)

        {

            DockPanel dp = new DockPanel();

          //  dp.LastChildFill = true;

            dp.Width = Double.NaN;    //相当于在XAML中设置Width="Auto"

            dp.Height = Double.NaN;   //相当于在XAML中设置Height="Auto"

            //把dp添加为窗体的子控件

            this.Content = dp;

            //添加Rectangles

            Rectangle rTop = new Rectangle();

            rTop.Fill = new SolidColorBrush(Colors.BlanchedAlmond);

            rTop.Stroke = new SolidColorBrush(Colors.BlanchedAlmond);

            rTop.Height = 30;

            dp.Children.Add(rTop);

            rTop.SetValue(DockPanel.DockProperty, Dock.Top);

      

            Rectangle rLeft = new Rectangle();

            rLeft.Fill = new SolidColorBrush(Colors.Gray);

            rLeft.Stroke = new SolidColorBrush(Colors.Gray);

            rLeft.HorizontalAlignment = HorizontalAlignment.Left;

            rLeft.Height = 30;

            rLeft.Width = 30;

            dp.Children.Add(rLeft);

            rLeft.SetValue(DockPanel.DockProperty, Dock.Left);

            Rectangle rBottom = new Rectangle();

            rBottom.Fill = new SolidColorBrush(Colors.Red);

            rBottom.VerticalAlignment = VerticalAlignment.Bottom;

            rBottom.Height = 30;

            dp.Children.Add(rBottom);

            rBottom.SetValue(DockPanel.DockProperty, Dock.Bottom);

        }

    }

}
复制代码

 

 

八. ViewBox

ViewBox这个控件通常和其他控件结合起来使用,是WPF中非常有用的控件。定义一个内容容器。ViewBox组件的作用是拉伸或延展位于其中的组件,以填满可用空间,使之有更好的布局及视觉效果。

一个 Viewbox中只能放一个控件。如果多添加了一个控件就会报错。如下图。

 

组件常用属性:

Child:获取或设置一个ViewBox元素的单一子元素。

Stretch:获取或设置拉伸模式以决定该组件中的内容以怎样的形式填充该组件的已有空间。具体设置值如下:

成员名称

说明

None

内容保持其原始大小。

Fill

调整内容的大小以填充目标尺寸。 不保留纵横比。

Uniform

在保留内容原有纵横比的同时调整内容的大小,以适合目标尺寸。

UniformToFill

在保留内容原有纵横比的同时调整内容的大小,以填充目标尺寸。 如果目标矩形的纵横比不同于源矩形的纵横比,则对源内容进行剪裁以适合目标尺寸。

 

 

StretchDirection:获取或设置该组件的拉伸方向以决定该组件中的内容将以何种形式被延展。具体的设置值如下。

成员名称

说明

UpOnly

仅当内容小于父项时,它才会放大。 如果内容大于父项,不会执行任何缩小操作。

DownOnly

仅当内容大于父项时,它才会缩小。 如果内容小于父项,不会执行任何放大操作。

Both

内容根据 Stretch 属性进行拉伸以适合父项的大小。

 

 

接下来我们做个示例,你可以通过选择下拉框中的不同设置值,来查看不同的效果。效果如下图。

 

XAML代码实现:

复制代码
<Window x:Class="WpfApp1.WindowViewBox"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        Title="WindowViewBox" Height="400" Width="500" Loaded="Window_Loaded">

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="250"/>

            <RowDefinition Height="auto"/>

            <RowDefinition Height="73*"/>

        </Grid.RowDefinitions>

        <Viewbox Stretch="Fill" Grid.Row="0" Name="viewBoxTest">

            <TextBox Text="通过调查发现,被阿里打假驱逐的30家售假商家中,竟有12家转战到了京东上。" />

        </Viewbox>

        <WrapPanel  Grid.Row="2">

        <StackPanel>

 

                <TextBlock Height="16" HorizontalAlignment="Left"  VerticalAlignment="Bottom" Width="66" Text="拉伸模式:" TextWrapping="Wrap"/>

                <ComboBox x:Name="cbStretch" Height="21" HorizontalAlignment="Left" VerticalAlignment="Bottom" Width="139" SelectionChanged="cbStretch_SelectionChanged"/>

 

            </StackPanel>

            <StackPanel>

                <TextBlock Height="16" HorizontalAlignment="Right"  VerticalAlignment="Bottom" Width="56" Text="拉伸方向:" TextWrapping="Wrap"/>

 

                <ComboBox x:Name="cbStretchDirection" Height="21" HorizontalAlignment="Right"  VerticalAlignment="Bottom" Width="139" SelectionChanged="cbStretchDirection_SelectionChanged"/>

 

            </StackPanel>

        </WrapPanel>

    </Grid>

</Window>

 
复制代码

 

 c#代码实现:

复制代码
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

 

namespace WpfApp1

{

 

    /// <summary>

    /// WindowViewBox.xaml 的交互逻辑

    /// </summary>

    public partial class WindowViewBox : Window

    {

        //定义cbStretch与cbStretchDirection的数据源 

List<StretchHelper> cbStretchList = new List<StretchHelper>(); 

List<StretchDirectionHelper> cbStretchDirectionList = new List<StretchDirectionHelper>(); 

 

        public WindowViewBox()

        {

            InitializeComponent();

        }

        private void BindDrp()

        { //填充各ComboBox内容 

            cbStretchList.Add(new StretchHelper() { StretchModeName = "Fill", theStretchMode = Stretch.Fill });

            cbStretchList.Add(new StretchHelper() { StretchModeName = "None", theStretchMode = Stretch.None });

            cbStretchList.Add(new StretchHelper() { StretchModeName = "Uniform", theStretchMode = Stretch.Uniform });

            cbStretchList.Add(new StretchHelper() { StretchModeName = "UniformToFill", theStretchMode = Stretch.UniformToFill });

            cbStretch.ItemsSource = cbStretchList;

            cbStretch.DisplayMemberPath = "StretchModeName";

            cbStretchDirectionList.Add(new StretchDirectionHelper() { StretchDirectionName = "DownOnly", theStretchDirection = StretchDirection.DownOnly });

            cbStretchDirectionList.Add(new StretchDirectionHelper() { StretchDirectionName = "UpOnly", theStretchDirection = StretchDirection.UpOnly });

            cbStretchDirectionList.Add(new StretchDirectionHelper() { StretchDirectionName = "Both", theStretchDirection = StretchDirection.Both });

            cbStretchDirection.ItemsSource = cbStretchDirectionList;

            cbStretchDirection.DisplayMemberPath = "StretchDirectionName";

        }

 

        private void cbStretchDirection_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            if (cbStretchDirection.SelectedItem != null)

            {

                viewBoxTest.StretchDirection = (cbStretchDirection.SelectedItem as StretchDirectionHelper).theStretchDirection;

            } 

        }

 

        private void cbStretch_SelectionChanged(object sender, SelectionChangedEventArgs e)

        {

            if (cbStretch.SelectedItem != null)

            {

                viewBoxTest.Stretch = (cbStretch.SelectedItem as StretchHelper).theStretchMode;

            } 

        }

 

        private void Window_Loaded(object sender, RoutedEventArgs e)

        {

            BindDrp();

        }

    }

    //辅助类StretchHelper 

    public class StretchHelper

    {

        public string StretchModeName { get; set; }

        public Stretch theStretchMode { get; set; }

    }

    //辅助类StretchDirectionHelper 

    public class StretchDirectionHelper

    {

        public string StretchDirectionName { get; set; }

        public StretchDirection theStretchDirection { get; set; }

    } 

}

 
复制代码

以上是关于WPF基础教程之属性系统的主要内容,如果未能解决你的问题,请参考以下文章

二WPF入门教程——Bingding学习

WPF教程一:基础

WPF教程一:基础

WPF入门教程---基础

WPF入门教程系列一——基础

WPF开始教程[译]