繁体   English   中英

从Label:派生的WPF控件是自定义属性(使用DP)不使用setter?

[英]WPF control derived from Label: are custom properties (with DP) not using the setter?

到目前为止,我的所有绑定都运行良好,只要它们完成了现有的控件属性,比如Button,Label等。 出于一个目的,我需要一个带有一个附加属性的自定义画布(继承自Canvas)。 然而,绑定似乎并不适用于那里。 然后,我使用自定义标签创建了一个更简单的示例,可以重现我的问题。 自定义标签在代码中定义如下:

namespace CustomCanvasTest
{
  class CustomLabel : Label
  {
    public string Str
    {
      get { return GetValue(StrProperty) as string; }
      set
      {
        SetValue(StrProperty, value);
      }
    }

    public static readonly DependencyProperty StrProperty =
      DependencyProperty.Register("Str", typeof(string), typeof(CustomLabel));
  }
}

主窗口的XAML:

<Window x:Class="CustomCanvasTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CustomCanvasTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel/>
    </Window.DataContext>
    <Grid>
        <Button Content="Button" HorizontalAlignment="Left" Margin="313,10,0,0" VerticalAlignment="Top" Width="75" Command="{Binding ButtonClickCmd}"/>
        <local:CustomLabel Content="{Binding SomeString}" Str="{Binding SomeString}" HorizontalAlignment="Left" Height="25" Margin="291,288,0,0" VerticalAlignment="Top" Width="176"/>
    </Grid>
</Window>

ViewModel具有以下代码( MainWindow.xaml.cs未受影响):

using System.ComponentModel;
using System.Windows.Input;
using WpfHelperClasses;

namespace CustomCanvasTest
{
  class ViewModel : INotifyPropertyChanged
  {
    public ViewModel()
    {
      SomeString = "init";
    }

    private string someString;
    public string SomeString
    {
      get { return someString; }
      set
      {
        someString = value;
        RaisePropertyChanged("SomeString");
      }
    }

    #region INPC

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string name)
    {
      var handler = PropertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(name));
      }
    }

    #endregion

    public ICommand ButtonClickCmd
    {
      get
      {
        return new DelegateCommand(param =>
        {
          SomeString = "blub";
        });
      }
    }
  }
}

当我单击按钮时,标签内容会明显改变,但是我在setter中为Str设置的断点永远不会到达。 我肯定会在这里犯一些新手的错误,但即使在这里找到关于类似问题的其他答案,我也不能完全理解它。 在此先感谢您的帮助!

从MSDN上的XAML加载和依赖属性文章:

出于实现原因,将属性标识为依赖项属性并访问属性系统SetValue方法来设置它,而不是使用属性包装器及其setter,计算成本更低。 这是因为XAML处理器必须仅基于知道标记结构和各种字符串所指示的类型和成员关系来推断支持代码的整个对象模型。

...

由于属性设置的XAML处理器行为的当前WPF实现完全绕过包装器,因此不应将任何其他逻辑放入自定义依赖项属性的包装器的集定义中。 如果将这样的逻辑放在set定义中,那么当在XAML中而不是在代码中设置属性时,将不会执行逻辑。

所以你的问题的答案是:不,不一定要设置setter。


为了获得有关依赖项属性的值更改的通知,您必须通过依赖项属性元数据注册PropertyChangedCallback

public static readonly DependencyProperty StrProperty =
    DependencyProperty.Register(
        "Str", typeof(string), typeof(CustomLabel),
        new PropertyMetadata(StrPropertyChanged));

private static void StrPropertyChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var label = obj as CustomLabel;
    var str = e.NewValue as string;
    ...
}

使用UIPropertyMetadata获取分配给Dependency属性的值:

为在核心级别具有呈现/用户界面影响的非框架属性提供属性元数据。

例:

public class CustomLabel : Label
{
    public static readonly DependencyProperty StrProperty = 
                           DependencyProperty.Register("Str",
                                                       typeof(string),
                                                       typeof(CustomLabel), 
                                                       new UIPropertyMetadata(String.Empty, IsStrTurn));

    public string Str
    {
        get
        {
            return GetValue(StrProperty) as string; 
        }

        set
        {
            SetValue(StrProperty, value);
        }
    }

    private static void IsStrTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {    
        string strOld = e.OldValue as string;
        string strNew = e.NewValue as string;

        System.Diagnostics.Debug.WriteLine("The old value is " + strOld); // The old value is "init"
        System.Diagnostics.Debug.WriteLine("The new value is " + strNew); // The new value is "blub"
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM