Как может AttachedProperty иметь несколько значений?

Как можно AttachedProperty, которое представляет собой отдельное свойство, определенное родительским элементом-владельцем, задать несколько значений через несколько дочерних элементов этого родительского элемента?

Например:

Если бы у меня был:

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

Здесь у нас есть один элемент DockPanel и одно свойство Dock. Как его можно установить одновременно на «Сверху», а затем «Снизу»?


person teenup    schedule 08.11.2010    source источник


Ответы (3)


В итоге получится метод, похожий на этот

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

Как видите, на самом деле он устанавливается не для родительского элемента, а для самого CheckBox с помощью статического метода SetDock на DockPanel, а не для родительского экземпляра. Выполнение этого в коде позади делает это немного понятнее, обратите внимание, как мы никогда не используем экземпляр DockPanel.

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

Надеюсь, это было ясно, если только вы не спросили, как это работает «под капотом». В этом случае см. этот вопрос.

Цитата по ссылке.

Целью этого механизма является «прикрепление» к другим объектам информации, необходимой родительским объектам, а не самим дочерним объектам.

CheckBox не может использовать свойство Dock, если оно не находится в DockPanel. То же самое и с Grid.Row, Canvas.Left, Validation.HasError (только для чтения) и т. Д. Итак, в основном, DockPanel - это тот, который нуждается в информации, но ему нужны все его дочерние элементы, чтобы иметь возможность хранить ее. Следовательно, он использует для этого прикрепленное свойство. Если вы создали новую панель с именем PuneetPanel и вам нужен Ангел для вычисления дочерней позиции, тогда вы можете определить свое собственное присоединенное свойство, PuneetPanel.Angel внутри этой панели, и все дочерние элементы могут использовать это без необходимости быть подклассом.

person Fredrik Hedblad    schedule 08.11.2010
comment
Итак, я не понимаю, каково использование AttachedProperty, для чего он нужен, это также можно было сделать с помощью некоторого свойства в CheckBox, когда в конечном итоге оно сохраняется с CheckBox. Почему DockPanel определяет свойство и владеет им, а также поддерживает с ним идентификатор свойства. - person teenup; 08.11.2010

Это очень хороший вопрос. Ответ заключается в том, как работает AttchedProperty. AttachedProperty используется родителем для рендеринга дочернего элемента. Перед рендерингом дочернего элемента родитель просматривает все присоединенные свойства, определенные для дочернего элемента, и применяется к нему.

Я нашел это в msdn, которое может быть вам полезно ::

DockPanel определяет присоединенное свойство DockPanel.Dock, а DockPanel имеет код уровня класса как часть своей логики отрисовки (в частности, MeasureOverride и ArrangeOverride).
Экземпляр DockPanel всегда будет проверять, установил ли какой-либо из его непосредственных дочерних элементов значение для DockPanel.Dock. Если это так, эти значения становятся входными для логики визуализации, применяемой к этому конкретному дочернему элементу ....

Вы можете просмотреть эту ссылку, чтобы получить подробный обзор ::
http://http://msdn.microsoft.com/en-us/library/ms749011.aspx

Надеюсь, это поможет вам !!

person GuruC    schedule 08.11.2010
comment
Я уже читал эту страницу msdn, читая только эту страницу, у меня возникли сомнения. Я знаю, что родитель будет запрашивать у дочерних элементов это свойство, но в каком объекте будут сохранены различные значения свойства? Поскольку свойство является переменной с одним членом в классе-владельце и может иметь только одно значение за раз. Я предполагаю, что свойство будет храниться отдельно в двух флажках в этом примере, но тогда у CheckBox нет самого свойства Dock. - person teenup; 08.11.2010
comment
Да, присоединенное свойство может иметь только одно значение за раз для одного экземпляра DependencyObject (CheckBox). Он не будет храниться в объекте напрямую. Механизм WPF поддерживает внутреннюю таблицу поиска, в которой каждый экземпляр объекта связан с установленными присоединенными свойствами. Когда вы получаете значения с помощью XAML или метода доступа get, вы фактически заставляете WPF искать значения в таблице. Со стороны это выглядит так, как будто вы получили его напрямую от объекта. - person bitbonk; 08.11.2010

Для ваших собственных добавленных свойств есть два варианта достижения того, что вы ищете:

1. Если количество комбинаций устанавливаемых значений не является слишком сложным, вы можете сделать присоединенное свойство типа enum, которое имеет FlagsAttribute установлен. Вы можете комбинировать значения, которые хотите установить, с помощью побитового или |:

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

И его использование в коде:

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

У этого есть одна небольшая проблема: вы не можете сделать это напрямую в xaml, вам придется написать MarkupExtension, который может преобразовывать строку в помеченные значения перечисления. Тогда его использование будет выглядеть так:

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

2. Поскольку присоединенные свойства могут быть любого типа, они, конечно, также могут быть сложными типами (с несколькими подсвойствами) или даже коллекциями, поэтому легко можно сделать что-то вроде этого:

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

Если вы определили присоединенное свойство таким образом, вам не нужны конвертеры для xaml, вы можете использовать его напрямую:

<CheckBox>
    <src:MyCustomPanelOrWhatever.MultiDock>
        <src:MultiDock.Left/>
        <src:MultiDock.Bottom/>
    </src:MyCustomPanelOrWhatever.MultiDock>
</CheckBox>
person bitbonk    schedule 08.11.2010