【问题标题】:How do dependency properties work in WPF?依赖属性如何在 WPF 中工作?
【发布时间】:2020-05-06 13:07:34
【问题描述】:

我正在尝试了解依赖属性并学习如何使用它。我正在浏览文章,在这篇文章中https://www.c-sharpcorner.com/UploadFile/6d590d/wpf-dependency-property/ 有这个例子:

MainWindow.xaml:

<Window x:Class="WpfApplication1.DependencyPropertyDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="DependencyPropertyDemo" Height="350" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <local:CarDependencyClass x:Key="carDependencyClass"></local:CarDependencyClass>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Label Content="Enter Car:" Grid.Row="0" VerticalAlignment="Center" />
        <TextBox Text="{Binding Path=MyCar, Source={StaticResource carDependencyClass }}" Name="MyTextCar" Height="25" Width="150" />
        <Button Name="MyButton" Content="Click Me!" Height="25" Click="MyButton_Click" Width="150" Grid.Row="1" />
    </Grid>
</Window>

MainWindow.xaml.cs:

using System.Windows;


namespace WpfApplication1 {
    /// <summary>  
    /// Interaction logic for DependencyPropertyDemo.xaml  
    /// </summary>  
    public partial class DependencyPropertyDemo : Window {
        public DependencyPropertyDemo() {
            InitializeComponent();
        }
        private void MyButton_Click(object sender, RoutedEventArgs e) {
            CarDependencyClass dpSample = TryFindResource("carDependencyClass") as CarDependencyClass;
            MessageBox.Show(dpSample.MyCar);
        }
    }
    public class CarDependencyClass : DependencyObject {
        //Register Dependency Property  
        public static readonly DependencyProperty CarDependencyProperty = DependencyProperty.Register("MyProperty", typeof(string), typeof(CarDependencyClass));
        public string MyCar {
            get {
                return (string)GetValue(CarDependencyProperty);
            }
            set {
                SetValue(CarDependencyProperty, value);
            }
        }
    }
}

它有效。我注意到他们注册了名为“MyProperty”的依赖属性,并且在程序的任何地方都没有使用它。 xaml 中只使用普通的 CLR 属性 MyCar。

但是还有另一篇文章https://www.c-sharpcorner.com/article/simplest-wpf-dependency-property-for-beginners-on-background-color/。他们还提供了其他示例:

MainWindow.xaml:

<Window x:Class="DependencyPropertyTutorial.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:views="clr-namespace:DependencyPropertyTutorial" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:DependencyPropertyTutorial" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <SolidColorBrush x:Key="BG" Color="Green" />
    </Window.Resources>
    <Grid>
        <views:CustomButtonControl SetBackground="{DynamicResource BG}"></views:CustomButtonControl>
    </Grid>
</Window>

CustomButtonControl.xaml:

<UserControl x:Class="DependencyPropertyTutorial.CustomButtonControl"
             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:DependencyPropertyTutorial"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Button x:Name="btnCustom" Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Height="52" Click="btnCustom_Click" />
    </Grid>
</UserControl>

CustomButtonControl.xaml.cs:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;


namespace DependencyPropertyTutorial {
    /// <summary>  
    /// Interaction logic for CustomButtonControl.xaml  
    /// </summary>  
    public partial class CustomButtonControl : UserControl {
        public CustomButtonControl() {
            InitializeComponent();
        }
        public static readonly DependencyProperty btnDependencyProperty = DependencyProperty.Register("SetBackground", typeof(SolidColorBrush), typeof(CustomButtonControl), new PropertyMetadata(new SolidColorBrush(Colors.HotPink), new PropertyChangedCallback(OnSetColorChanged)));
        public SolidColorBrush SetBackground {
            set {
                SetValue(btnDependencyProperty, value);
            }
            get {
                return (SolidColorBrush)GetValue(btnDependencyProperty);
            }
        }
        private void btnCustom_Click(object sender, RoutedEventArgs e) {
            this.SetBackground = new SolidColorBrush(Colors.IndianRed);
        }
        private static void OnSetColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            CustomButtonControl mycontrol = d as CustomButtonControl;
            mycontrol.callmyInstanceMethod(e);
        }
        private void callmyInstanceMethod(DependencyPropertyChangedEventArgs e) {
            btnCustom.Background = (SolidColorBrush)e.NewValue;
        }
    }
}

在这里,他们注册依赖属性的名称为“SetBackground”,这与 CLR 属性的名称 - SetBackground 完全相同。如果我将依赖属性(我使用 Register 方法注册的那个)“SetBackground”更改为其他属性,例如“SetBackgroundDependencyProperty”,那么在尝试运行应用程序时会出现 XAML 异常。但是“SetBackground”依赖属性甚至没有在任何地方的 xaml 中引用。 XAML 中仅在行中引用了 CLR 属性 SetBackground

&lt;views:CustomButtonControl SetBackground="{DynamicResource BG}"&gt;&lt;/views:CustomButtonControl&gt;

我在 Visual Studio 中也遇到了这个例子的错误:

但是当我尝试构建和运行应用程序时,它可以工作。

所以我的问题是:为什么在第一个示例中他们不必将注册的依赖属性命名为与 CLR 属性相同,但在第二个示例中,我必须将注册的依赖属性命名为与 CLR 属性相同。有没有办法将注册的依赖属性命名为与第二个示例中的 CLR 属性不同的名称?考虑到 xaml 仅引用 CLR 属性,为什么以及如何使用依赖属性?我检查了它,根据 VS IntelliSense,在这两个项目中,只有 CLR 属性是从 XAML 中引用的。为什么我必须注册与 CLR 属性同名的依赖属性 - “SetBackground”当在 xaml 中仅引用 CLR 属性并且它从依赖属性返回 SolidColorBrush,无论如何:

return (SolidColorBrush)GetValue(btnDependencyProperty);

以下是两个示例的解决方案: https://github.com/KulaGGin/DependencyProperty

【问题讨论】:

    标签: wpf


    【解决方案1】:

    第一个例子有点脏,我不会这样编码。有一个很好的约定可以避免混淆 - 将 DP 命名为 CLR 属性 + 'Property'(但这不是强制性的!)并将其注册为 CLR 属性的名称(如果您想在 XAML 中将其用作 DP)。
    先回答你的问题:

    • 第一个示例确实有效,因为无处不在,在使用属性 MyCar 的地方,它被用作 CLR 属性。如果您尝试绑定到MyCar,它将失败,因为没有这样的依赖属性。要实现此示例中的功能,只需声明一个 CLR 属性即可:
      public string MyCar { get; set; }
      而不是所有这些与依赖属性的混淆。
    • 在第二个示例中,定义了 CLR 属性以及依赖属性 SetBackground(该字段的名称 btnDependencyProperty 不方便,但可以)。您的误解是 XAML 中使用的内容。
      如果您在 XAML 中使用 BindingDynamicResource,则依赖属性和 CLR 属性都是必需的!因此它们需要具有相同的名称。如果没有,那么您将收到错误消息。
      如果将属性设置为 StaticResource 或直接设置为值,甚至不在 XAML 中使用它,那么您将能够运行应用程序。

    【讨论】:

      【解决方案2】:

      DependencyProperty 的实现有点奇怪。

      XAML 编译器依赖 CLR 属性包装器进行编译,但在运行时绑定完全忽略它,只在 DP 上调用 GetValue/SetValue。因此名称应该匹配。

      【讨论】:

        【解决方案3】:

        第一个示例中有错字。注册的依赖属性名称需要与 CLR-backing 属性相同。

        声明一个 DependencyProperty 是一个两阶段的过程:

        1. 注册属性,以便 WPF DependencyProperty 系统可以对其进行跟踪,并在属性更改时通知等。
        2. 设置一个 CLR 属性,为开发人员提供一个 API 来获取和设置值。

        我希望这会有所帮助。

        【讨论】:

          猜你喜欢
          • 2011-07-22
          • 2014-05-23
          • 2013-10-09
          • 2012-11-27
          • 1970-01-01
          • 1970-01-01
          • 2013-01-27
          相关资源
          最近更新 更多