开发者

How can an AttachedProperty have multiple values?

How can an AttachedProperty which 开发者_高级运维is a single property defined by an owning parent element, be set with multiple values through several child elements of that parent?

For example:

If I have:

<DockPanel>
  <CheckBox DockPanel.Dock="Top">Hello</CheckBox>
  <CheckBox DockPanel.Dock="Bottom">World</CheckBox>
</DockPanel>

Here we have a single DockPanel element and it has a single Dock property. How can it be set to "Top" and then "Bottom" simultaneously?


It will end up in a method looking like this

public class DockPanel : Panel
{
    public static readonly DependencyProperty DockProperty;
    // ...
    public static void SetDock(UIElement element, Dock dock)
    {
        element.SetValue(DockProperty, value);
    }
}

As you can see, it's actually not set on the parent, but the CheckBox itself, through the static method SetDock on DockPanel and not the parent instance. Doing it in code behind makes this a little clearer, notice how we never use an instance of a DockPanel.

DockPanel.SetDock(checkBox1, Dock.Top);
DockPanel.SetDock(checkBox2, Dock.Bottom);

Hopefully this was clear, unless your question was how this works "under the hood". In that case, see this question.

Quote from link.

The purpose for this mechanism is to "attach" to other objects information needed by parent objects, not the child objects themselves.

A CheckBox has no use for a Dock property unless it is in a DockPanel. Same goes for Grid.Row, Canvas.Left, Validation.HasError (read only) etc. So basically, the DockPanel is the one needing the information, but it needs all its childs to be able to store it. Hence, it's using an Attached Property for it. If you created a new Panel, called PuneetPanel, and you needed an Angel to calculate the child position, then you could define your own Attached Property, PuneetPanel.Angel inside this panel and all childs could use this without having to be subclassed.


This is a very nice question. The answer lies in how the AttchedProperty works. The AttachedProperty is used by the parent to render a child. Before rendering the child, the parent looks out for any attached property defined on child and applies to the child.

I found this from msdn which might be useful for you ::

DockPanel defines the DockPanel.Dock attached property, and DockPanel has class-level code as part of its rendering logic (specifically, MeasureOverride and ArrangeOverride).
A DockPanel instance will always check to see whether any of its immediate child elements have set a value for DockPanel.Dock. If so, those values become input for the rendering logic applied to that particular child element....

You can see this link to get detailed overview ::
http://http://msdn.microsoft.com/en-us/library/ms749011.aspx

Hope it helps you!!


For your own custom attached properties there are two options to achieve what you are looking for:

1. If the number of combinations of settable values are not to complex you could make your attached property of type enum that has the FlagsAttribute set. You can the combines the values you want to set using bitwise-or |:

[Flags]
public enum MultiDock
{
  Left,
  Top,
  Right,
  Bottom
}

And its usage in code:

MyCustomPanelOrWhatever.SetMultiDock(MultiDock.Left | MultiDock.Bottom);

This has one small proplem though, you can not do the above in xaml directly, you would have to write a MarkupExtension that can convert string to flagged enum values. Its usage would then look like this:

<CheckBox src:MyCustomPanelOrWhatever.MulitDock="{src:FlaggedEnum Left|Bottom}"  />

2. Since attached properties can be of any type, they can of course also be complex types (with multiple subproperties) or even collections, so it is easily possible to do something like this:

MyCustomPanelOrWhatever.SetMultiDock(new List<MultiDock> { MultiDock.Left, MultiDock.Bottom });

If you have defined your attached property that way, you do not need any converters for xaml, you can use it directly:

<CheckBox>
    <src:MyCustomPanelOrWhatever.MultiDock>
        <src:MultiDock.Left/>
        <src:MultiDock.Bottom/>
    </src:MyCustomPanelOrWhatever.MultiDock>
</CheckBox>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜