zoukankan      html  css  js  c++  java
  • wpf之依赖属性

    什么是依赖附加属性

    依赖属性就是一种自己可以没有值,并且可以通过绑定从其他数据源获取值。依赖属性可支持WPF中的样式设置、数据绑定、继承、动画及默认值。

    如果要定义依赖属性,必须满足下面三个条件:

    1 所属对象必须是依赖对象(依赖对象就是说必须要继承自DependencyObject,在wpf中大部分)

    2 必须是静态+readonly

    3 不是通过new而是通过注册来完成定义的

    下面展示一个简单的依赖属性定义:

       public partial class MyDependency : UserControl
        {
            public MyDependency()
            {
                InitializeComponent();
            }
             
            public int MyProperty
            {
                get { return (int)GetValue(MyPropertyProperty); }
                set { SetValue(MyPropertyProperty, value); }
            }
    
            /// <summary>
            /// 定义一个依赖属性,不是通过new生成,而是通过n注册生成的,
            /// 注意第一个参数之所以是MyProperty是因为依赖属性默认后面是Property来结尾,是默认的一个约束,
            /// 
            /// </summary>
            public static readonly DependencyProperty MyPropertyProperty =
                DependencyProperty.Register("MyProperty", typeof(int), typeof(MyDependency), new PropertyMetadata(0));
             
    
        }

    至于依赖附加属性,看下面一个这个例子:

    <UserControl x:Class="MyWpf.MyGrid"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:MyWpf"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
            <Grid.RowDefinitions>
                <!--指定宽高,剩余的会自动占满-->
                <RowDefinition Height="90"></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <!--可以指定行列-->
            <Border Background="Red" Grid.Row="0"></Border>
            <Border Background="Blue" Grid.Row="1"></Border>
            <Border Background="SandyBrown" Grid.Column="1" Grid.Row="0"></Border>
            <Border Background="RosyBrown" Grid.Column="1" Grid.Row="1"></Border>
        </Grid> 
    </UserControl>

    <Border>标签这是没有Row这个属性的,但是通过Grid中的这个属性附加到了Border上,使得Border标签也有了Row属性。使用附加属性,属性定义在与其使用的类不同的类上。这通常用于布局。

    依赖附加属性关心的不是拥有者是不是依赖对象,关心的是被附加的对象。

    定义一个依赖附加属性:

    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.Navigation;
    using System.Windows.Shapes;
    
    namespace MyWpf
    {
        /// <summary>
        /// MyDependency.xaml 的交互逻辑
        /// </summary>
        public partial class MyDependency : UserControl
        {
            public MyDependency()
            {
                InitializeComponent();
            } 
    
            /// <summary>
            /// 定义一个依赖属性,不是通过new生成,而是通过n注册生成的,
            /// 注意第一个参数之所以是MyProperty是因为依赖属性默认后面是Property,
            /// 
            /// </summary>
            public static readonly DependencyProperty MyTestProperty =
                DependencyProperty.RegisterAttached("MyTest", typeof(int), typeof(MyDependency), new PropertyMetadata(0));
            /// <summary>
            /// 注意必须是Get+附加属性的名称,默认的后缀Property不用写在这里
            /// </summary>
            /// <param name="dependency"></param>
            /// <returns></returns>
            public string GetMyTest(DependencyObject dependency)
            {
                return (string)dependency.GetValue(MyTestProperty);
            }
    
            public void SetMyTest(DependencyObject dependency,string value)
            {
                dependency.SetValue(MyTestProperty,value);
            } 
        } 
    
    }

    依赖属性和依赖附加属性的区别

     1 承载对象的区别

    一个是需要拥有者必须是依赖对象,依赖附加属性则要求被附加对象是依赖对象

    2 定义方法的区别

    一个是Regist,一个是RegisterAttached

    3 包装(封装)

     依赖属性使用属性包装器,但是依赖附加属性使用的是方法包装

    依赖附加属性使用场景

     1 绑定中转

    我们以登录界面为例,其中PasswordBox控件,Password属性不是依赖对象,所以没法进行Binding绑定,所以需要创建依赖附加属性来解决。

     依赖附加属性关心的是被附加的对象是不是依赖对象,下面的PasswordBox是继承自依赖对象的,所以可以添加依赖附加属性。

     界面:

    <UserControl x:Class="MyWpf.DependencyAttachedProperty"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:MyWpf"
                 xmlns:c="clr-namespace:MyWpf.CommonService"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="60"></RowDefinition>
                <RowDefinition Height="60"></RowDefinition>
            </Grid.RowDefinitions>
            <Button Content="提交"  Grid.Row="1" Command="{Binding GetPasswordCommand}"></Button>
            <TextBox Text="{Binding UserName}" ></TextBox>
            <PasswordBox Password="" Grid.Row="0"  c:PaswwordHelper.Password="{Binding Password}"></PasswordBox>
             
            
        </Grid>
    </UserControl>

    后台:

    namespace MyWpf
    {
        /// <summary>
        /// DependencyAttachedProperty.xaml 的交互逻辑
        /// </summary>
        public partial class DependencyAttachedProperty : UserControl
        {
            public DependencyAttachedProperty()
            {
                InitializeComponent();
                this.DataContext = new Person();
            }
        }
    
        public class Person
        {
            public string UserName { get; set; }
            public string Password { get; set; }
            public Person()
            {
                UserName = "哈哈";
                Password = "123";
            }
    
            private CommandBase _getPasswordCommand;
    
            public CommandBase GetPasswordCommand
            {
                get
                {
                    if (_getPasswordCommand == null)
                    {
                        _getPasswordCommand = new CommandBase();
                        _getPasswordCommand.DoExecute = new Action<object>(
                            (o) => { MessageBox.Show(this.Password); }
                            );
                    }
    
                    return _getPasswordCommand;
    
                }
                set { _getPasswordCommand = value; }
            }
    
    
        }
    
        public class CommandBase : ICommand
        {
            public event EventHandler CanExecuteChanged;
    
            public bool CanExecute(object parameter)
            {
                return true;
            }
    
            public void Execute(object parameter)
            {
                DoExecute?.Invoke(parameter);
            }
    
            public Action<object> DoExecute { get; set; }
        }
    
    
    
    }

    帮助类:

    namespace MyWpf.CommonService
    {
        public class PaswwordHelper
        {
            /// <summary>
            /// 定义一个依赖属性,不是通过new生成,而是通过n注册生成的, 
            /// 注意第三个参数是typeof(PaswwordHelper),这个依赖附加属性是属于这个类的
            /// </summary>
            public static readonly DependencyProperty PasswordProperty =
                DependencyProperty.RegisterAttached("Password", typeof(string),  typeof(PaswwordHelper), 
    new PropertyMetadata(new PropertyChangedCallback(OnBindedPasswordChanged))); /// <summary> /// 注意必须是Get+附加属性的名称,默认的后缀Property不用写在这里 /// </summary> /// <param name="dependency"></param> /// <returns></returns> public static string GetPassword(DependencyObject dependency) { return (string)dependency.GetValue(PasswordProperty); } public static void SetPassword(DependencyObject dependency, string value) { dependency.SetValue(PasswordProperty, value); } /// <summary> /// 回调函数 /// </summary> /// <param name="obj"></param> /// <param name="e"></param> private static void OnBindedPasswordChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as System.Windows.Controls.PasswordBox; if (passwordBox != null) { //PasswordBox的Password属性赋值 passwordBox.Password = e.NewValue == null ? string.Empty : e.NewValue.ToString(); } } } }

     结果:

     可以看到,我们明显在界面上已经做过密码更改了,但是Password还是之前的旧密码,所以我们可以再建一个附加属性来联动更改:

    namespace MyWpf.CommonService
    {
        public class PaswwordHelper
        {
            /// <summary>
            /// 定义一个依赖属性,不是通过new生成,而是通过n注册生成的, 
            /// 注意第三个参数是typeof(PaswwordHelper),这个依赖附加属性是属于这个类的
            /// </summary>
            public static readonly DependencyProperty PasswordProperty =
                DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PaswwordHelper),
    new PropertyMetadata(new PropertyChangedCallback(OnBindedPasswordChanged))); /// <summary> /// 注意必须是Get+附加属性的名称,默认的后缀Property不用写在这里 /// </summary> /// <param name="dependency"></param> /// <returns></returns> public static string GetPassword(DependencyObject dependency) { return (string)dependency.GetValue(PasswordProperty); } public static void SetPassword(DependencyObject dependency, string value) { dependency.SetValue(PasswordProperty, value); } #region public static readonly DependencyProperty AttachedProperty = DependencyProperty.RegisterAttached("Attached", typeof(string), typeof(PaswwordHelper),

    new PropertyMetadata(new PropertyChangedCallback(OnAttachedChanged))); /// <summary> /// 注意必须是Get+附加属性的名称,默认的后缀Property不用写在这里 /// </summary> /// <param name="dependency"></param> /// <returns></returns> public static string GetAttached(DependencyObject dependency) { return (string)dependency.GetValue(AttachedProperty); } public static void SetAttached(DependencyObject dependency, string value) { dependency.SetValue(AttachedProperty, value); } #endregion /// <summary> /// 依赖附加属性值更改的时候的回调函数 /// </summary> /// <param name="obj"></param> /// <param name="e"></param> private static void OnBindedPasswordChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as System.Windows.Controls.PasswordBox; passwordBox.PasswordChanged -= Pb_PasswordChanged; if (!isUpdating ) { passwordBox.Password = e.NewValue == null ? string.Empty : e.NewValue.ToString(); } passwordBox.PasswordChanged += Pb_PasswordChanged; } private static void OnAttachedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { var passwordBox = obj as PasswordBox; if (passwordBox != null) { passwordBox.PasswordChanged += Pb_PasswordChanged; } } static bool isUpdating = false; private static void Pb_PasswordChanged(object sender, RoutedEventArgs e) { PasswordBox pb = sender as PasswordBox; isUpdating = true; SetPassword(pb, pb.Password); isUpdating = false; } } }

    界面:

    <UserControl x:Class="MyWpf.DependencyAttachedProperty"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:local="clr-namespace:MyWpf"
                 xmlns:c="clr-namespace:MyWpf.CommonService"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="60"></RowDefinition>
                <RowDefinition Height="60"></RowDefinition>
            </Grid.RowDefinitions>
            <Button Content="提交"  Grid.Row="1" Command="{Binding GetPasswordCommand}"></Button>
            <TextBox Text="{Binding UserName}" ></TextBox>
            <!-- c:PaswwordHelper.Attached="true"    没什么特别的意思,主要是给个值能够触发这个依赖属性就行,
            主要是为了绑定上密码更改的事件PasswordChanged
           UpdateSourceTrigger=PropertyChanged 意味着当目标控件值发生变化时,源数据立马更新,不是失去焦点之后才更新-->
            <PasswordBox Password="" Grid.Row="0"  
                         c:PaswwordHelper.Password="{Binding Password,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
           c:PaswwordHelper.Attached="true"    ></PasswordBox>
    
        </Grid>
    </UserControl>

     

  • 相关阅读:
    sql server delete语句
    sql server 通配符
    sql server join联结
    windows下如何使用两个版本的nodejs
    PHP的Trait 特性
    PHP错误与异常处理try和catch
    laravel belongsTo()&hasOne()用法详解
    Laravel Model 的 fillable (白名单)与 guarded (黑名单)
    js原生,缓动动画封装
    js原生轮播图
  • 原文地址:https://www.cnblogs.com/anjingdian/p/15483750.html
Copyright © 2011-2022 走看看