数据绑定-WPF:如何实现在所有GUI控件中可用的通用属性



是否可以实现可以在每个GUI控件(即FrameworkElement)上指定的属性?我想象的是像Tag这样的财产,然而,我宁愿不使用Tag,而是使用我自己的财产。

编辑:由于Felice和CodeNaked的回复,我再次尝试了我的第一个附加依赖属性实验。尽管对所有内容都进行了双重检查,但我的附加属性(SetAdsName())的setter永远不会被调用,尽管附加属性的注册成功,没有任何错误。与WPF一样,没有错误消息。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ads="clr-namespace:WAL.UI.Lib.Ads.Binding;assembly=WAL.UI.Lib"
        Title="Demo Page" Height="350" Width="525"
>
    <Grid>
        <Label ads:AdsNameRegistry.AdsName="SpecialLabelName" Content="Some Button Caption" />
    </Grid>
</Window>

public class AdsNameRegistry : DependencyObject
{
    public static readonly DependencyProperty AdsNameProperty = DependencyProperty.RegisterAttached( "AdsName", typeof(String), typeof(AdsNameRegistry), new FrameworkPropertyMetadata( "", FrameworkPropertyMetadataOptions.AffectsRender ) );
    public static void SetAdsName( UIElement element, String value )
    {
        try
        {
            MessageBox.Show( "SetAdsName(value=" + value + ")" );
            element.SetValue( AdsNameProperty, value );
        }
        catch (Exception ex)
        {
            Debug.Assert( false, "Exception in SetAdsName(): " + ex.Message + "nn" + ex );
            throw;
        }
    }
    public static String GetAdsName( UIElement element )
    {
        try
        {
            return (String) element.GetValue( AdsNameProperty );
        }
        catch (Exception ex)
        {
            Debug.Assert( false, "Exception in GetAdsName(): " + ex.Message + "nn" + ex );
            throw;
        }
    }
}

}

我的第一个猜测是,SetAdsName()永远不会被调用,因为XAML编码中没有元素作为父元素。但这似乎是一个错误的结论。

谨致问候,七个

首先,是的,您想要一个附加的属性。但是您没有正确地实现模式。

永远不要在GetXxxx()或SetXxxx(()方法中放入任何逻辑。GetXxxx和SetXxxx应分别只包含对GetValue和SetValue的调用:

public static String GetAdsName(UIElement element)
{
    return (string) element.GetValue(AdsNameProperty);
}
public static void SetAdsName(UIElement element, String value)
{
    element.SetValue(AdsNameProperty, value);
}

为什么它们不应该包含任何其他逻辑?因为在加载XAML时,不会调用您的SetXxxx方法。WPF团队有一个选择:他们可以让XAML加载程序使用Reflection来找到你的SetXxxx方法,并在运行时动态调用它,这样你的方法就可以调用SetValue;或者他们可以去掉中间人,直接调用SetValue。他们选择了后者,因为它更简单、更高效。

如果希望在设置属性时产生副作用,则需要在构造PropertyMetadata时指定propertyChangedCallback。在您的情况下:

public static readonly DependencyProperty AdsNameProperty =
    DependencyProperty.RegisterAttached("AdsName",
        typeof(String), typeof(AdsNameRegistry),
        new FrameworkPropertyMetadata("",
            FrameworkPropertyMetadataOptions.AffectsRender, OnAdsNameChanged));
private static void OnAdsNameChanged(DependencyObject sender,
    DependencyPropertyChangedEventArgs e)
{
    // do something with the new value
}

这可以通过使用附加属性来完成。当属性被附加时,您可以通过以下示例中的注册得到通知:

public static readonly DependencyProperty XYZProperty =
            DependencyProperty.RegisterAttached(
                "XYZ",
                typeof(object),
                typeof(TargetClass),
                new PropertyMetadata(OnXYZChanged)
                );

并实现OnXYZChanged:

private static void OnXYZChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ...     
}

d将是您要附加到的对象,在e.NewValue中,您将找到属性的新值。

您可以使用附加的属性来添加您想要的任何自定义属性。示例包括Canvas.Left属性。

最新更新