[英]WPF Attached Property has no effect at design time (xaml editor)
I have a Attached Property that works great at runtime, and I would like to get it working at design time as well. 我有一个在运行时运行良好的附加属性,我也想在设计时使用它。 I've read a bit of the docs and followed some tutorials, but I they assume more familiarity than I have.
我已经阅读了一些文档并遵循了一些教程,但我认为他们比我更熟悉。
The purpose of this DP (from source blog post (microsoft.co.il) ) is: 这个DP的目的(来自博客文章(microsoft.co.il) )是:
How can I get this property to have the same effect in the designer as it does at runtime? 如何让这个属性在设计器中与在运行时具有相同的效果? It affects the layout, so I think its important to see what is going on there too.
它会影响布局,所以我认为重要的是看看那里发生了什么。
Simplified XAML : 简化的XAML:
<StackPanel Orientation="Horizontal" local:PanelItems.Margin="0,0,10,0">
<TextBox Width="120" Text="{Binding Email}"/>
<Button Content="Search" Command="{Binding SearchCommand}"/>
</StackPanel>
The current class (works fine at runtime). 当前类(在运行时工作正常)。
I've remove inheriting from DependencyObject
since that didn't help (I was following msdn examples) for this this case. 我已经删除了从
DependencyObject
继承,因为这对于这种情况没有帮助(我正在关注msdn示例)。 Those examples don't handle attached properties, I suppose. 我想这些例子不处理附加属性。
public static class PanelItems : DependencyObject
{
public static readonly DependencyProperty MarginProperty =
DependencyProperty.RegisterAttached(
"Margin", typeof(Thickness), typeof(PanelItems),
new UIPropertyMetadata(new Thickness(), MarginChangedCallback)
);
public static Thickness GetMargin(DependencyObject obj)
{
return (Thickness)obj.GetValue(MarginProperty);
}
public static void SetMargin(DependencyObject obj, Thickness value)
{
obj.SetValue(MarginProperty, value);
}
public static void MarginChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
{
// requires a panel control (e.g. a StackPanel)
var panel = sender as Panel;
if (panel == null) return;
panel.Loaded += new RoutedEventHandler(OnPanelLoaded);
}
static void OnPanelLoaded(object sender, RoutedEventArgs e)
{
var panel = sender as Panel;
foreach (var child in panel.Children.OfType<FrameworkElement>())
child.Margin = PanelItems.GetMargin(panel);
}
}
I added an extension method to check if the value has been set for a given object, which allows targeting only direct children. 我添加了一个扩展方法来检查是否已为给定对象设置了值,这允许仅定位直接子对象。 There is no other way that I can see, since there is no context back to the original change that caused the cascade.
没有其他方法可以看到,因为没有上下文回到导致级联的原始更改。
public static class DependencyExtensions
{
/// <summary>
/// Checks if a DependencObject has a value set for the Dependency Property.
/// Element is an object for conveninence purpose, and the return value is
/// always false if it is not a DependencyObject (e.g. a UI element)
/// </summary>
/// <param name="property">The DependencyProperty to check</param>
/// <param name="element">The element (a DependencyObject) to check against</param>
/// <returns></returns>
public static bool IsSetFor(this DependencyProperty property, object element)
{
if (element is DependencyObject d)
{
return d.ReadLocalValue(property) != DependencyProperty.UnsetValue;
}
return false;
}
}
After that I modified the event a little to check both. 之后,我稍微修改了一下这个事件。 Nested panels work fine as well;
嵌套面板也可以正常工作; the inner panel is according to the outer panels rule, and the inner children get the correct margin.
内部面板根据外部面板规则,内部儿童获得正确的边距。
if (sender is FrameworkElement el && MarginProperty.IsSetFor(el.Parent))
{
el.Margin = (Thickness)args.NewValue;
}
Note: Its also possible to call GetMargin(el as DependencyObject)
though the values are the same as NewValue
for children. 注意:虽然值与子项的
NewValue
相同,但也可以调用GetMargin(el as DependencyObject)
。
One final note: I had project code
switched off on the designer, so no matter what I did I never could see the changes there. 最后一点说明:我已经关闭了设计师的
project code
,所以无论我做了什么,我都看不到那里的变化。 Here is the tiny unlabeled button with huge effects: 这是一个微小的无标签按钮,具有巨大的效果:
Here's a quick draft of a Margin property with value inheritance, which is thus automatically applied to all child elements. 这是带有值继承的Margin属性的快速草图,因此自动应用于所有子元素。
Besides all child elements, a Margin is also applied to the Panel itself, which you may somehow try to avoid (perhaps by simply checking if the target element is a Panel). 除了所有子元素之外,边距也适用于面板本身,您可能会以某种方式避免(可能只是通过检查目标元素是否为Panel)。
public static class PanelItems
{
public static readonly DependencyProperty MarginProperty =
DependencyProperty.RegisterAttached(
"Margin", typeof(Thickness), typeof(PanelItems),
new FrameworkPropertyMetadata(new Thickness(),
FrameworkPropertyMetadataOptions.Inherits, MarginChangedCallback));
public static Thickness GetMargin(DependencyObject obj)
{
return (Thickness)obj.GetValue(MarginProperty);
}
public static void SetMargin(DependencyObject obj, Thickness value)
{
obj.SetValue(MarginProperty, value);
}
private static void MarginChangedCallback(
object sender, DependencyPropertyChangedEventArgs e)
{
var element = sender as FrameworkElement;
if (element != null && !(element is Panel))
{
element.Margin = (Thickness)e.NewValue;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.