是否可以实现可以在每个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属性。