Подтвердить что ты не робот

Разница между прикрепленными и непривязанными зависимыми свойствами в Silverlight

Хорошо штабелеры, я потратил пару часов на этот вопрос, и я хочу знать, есть ли у кого-то окончательный ответ.
Для всех исследований, которые я сделал, я не могу найти НИКАКОЙ разницы между .Register и .RegisterAttached в Silverlight. Теперь, прежде чем вы скачете пистолет и скажите мне, что .RegisterAttached используется для присоединения DP к другому классу, попробуйте реализовать свойство Attached Dependency с помощью DependencyProperty.Register(). Я не нашел ни единой разницы, и поэтому я не понимаю, в чем разница.
Кроме того, в моем конкретном случае я пытаюсь расширить функциональность класса Grid и хочу дать ему дополнительные свойства. Таким образом, я пробовал листинг, передавая как typeof(Grid), так и typeof(FluidLayoutManager) (класс реализации) в качестве параметра ownerType, и это также, по-видимому, очень мало отличается... (я считаю, что это имеет значение, когда я пропускаю два пользовательские классы из одного и того же пространства имен. Однако при передаче определенного класса Microsoft и пользовательского класса я всегда показываю его в XAML как DP пользовательского класса.)
Любые разъяснения по этой теме были бы высоко оценены, поскольку я сижу здесь, царапая себе голову, и задаюсь вопросом, есть ли вообще какая-либо разница, или если Microsoft снова надавит на меня.

4b9b3361

Ответ 1

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

Основное различие между атрибутами зависимой зависимости и свойствами зависимостей (и, следовательно, между .Register и .RegisterAttached) заключается в том, что RegisterAttached позволяет присвоить значение любому объекту зависимостей, тогда как Register только позволяет привязывать его к классу, переданному как ownerType.

Как Харис Хасан упоминает (глубоко в потоке комментариев), ваш пример использует единственный допустимый тип (т.е. CustomControl) и не показывает вам, что прилагаемая версия может быть назначено ЛЮБОЙ объект зависимостей.

например. вы можете сделать это с помощью свойства Attached Dependency (но не простого DP):

<Grid local:AttacherClass.ADP1="1" x:Name="LayoutRoot" Background="White">
</Grid>

Лучшей ссылкой для ADPs, которую я могу найти, является следующий: http://msdn.microsoft.com/en-us/library/ms749011.aspx

Мы использовали ADP в качестве основы для системы локализации, так что переводы могли быть паразитированы на объекты во время загрузки, а не с использованием ужасно длинных привязок. Не удалось сделать это с помощью DP

Обновление:

Я также хотел бы пояснить, что ограничение родительского элемента относится к использованию атрибута на основе XAML. Из кода ограничение родителя, по-видимому, не применяется.

Ответ 2

Неверно полагать, что "RegisterAttached позволяет присвоить значение любому объекту зависимостей, тогда как Register допускает его присоединение к классу, переданному как параметр ownerType". Вот отличный пример прикрепленного свойства, зарегистрированного в Register:

class FooPropertyDeclaringType
{
    public static readonly DependencyProperty FooProperty = 
        DependencyProperty.Register("Foo", typeof(int), typeof(FooPropertyDeclaringType));
}

class SomeUnrelatedType : DependencyObject { }

class Program
{
    static void Main()
    {
        var obj = new SomeUnrelatedType();
        obj.SetValue(FooPropertyDeclaringType.FooProperty, 10);
        Debug.Assert(10 == (int)obj.GetValue(FooPropertyDeclaringType.FooProperty));
    }
}

Отражатель показывает, что единственная разница между Register и RegisterAttached заключается в том, что Регистр выдает большую часть предоставленных метаданных и сохраняет их только для экземпляров регистрации класса (через OverrideMetadata). Это означает, что такие атрибуты, как Наследование и различные уведомления об обновлениях, обычно указанные в метаданных, не работают с свойствами, зарегистрированными в Регистре, и привязаны к объектам других типов (кроме типа регистрации). Таким образом, на самом деле регистр - это урезанная версия RegisterAttached. Вероятно, это было сделано по причинам производительности.

В пример, связанный Харисом Хасаном в комментариях к его ответу, если вы измените RegisterAttached на Register, кнопки перестанут перемещаться (потому что свойство больше не предоставляет метаданные AffectsParentArrange для типа Button), но при изменении размера окна они все же перерисовываются в новых местах. Но если вы добавите те же самые метаданные к типу Button после вызова InitializeComponent():

RadialPanel.AngleProperty.OverrideMetadata(
    typeof(Button), 
    new FrameworkPropertyMetadata(
        0.0, FrameworkPropertyMetadataOptions.AffectsParentArrange));

тогда все работает снова, как будто вызывается RegisterAttached.

Ответ 3

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

Простой Register используется для простых свойств зависимостей, которые обычно используются для привязок и проверок, поэтому они являются обычными свойствами CLR с некоторой дополнительной магией, которая помогает в WPF

RegisterAttached обычно используется, когда вы хотите открыть свойство, к которому можно получить доступ, и установить его в дочернем классе, например DockPanel, где дочерние элементы управления указывают родителям, где они хотят быть размещены с помощью Dock.Left или Dock.Right, Таким образом, они являются особыми свойствами зависимостей, к которым можно получить доступ в дочерних элементах управления (что не относится к простым свойствам Register), и они (в случае DockPanel) помогают родительскому контролю при отображении дочерних элементов

Короче говоря, cay say Register используется для регистрации dependency properties, которые используются в том же классе, в то время как RegisterAttached используется для регистрации специальных свойств зависимостей, называемых attached properties, и они используются и доступны классами, отличными от одного, которые определил его

Это является хорошим объяснением прикрепленных свойств и чего не может быть достигнуто с помощью простого DP

Ответ 4

Если вы зарегистрируетесь в RegisterAttached, он становится глобальным как свойство в хранилище любого DependencyObject, т.е. вы можете SetValue для любого объекта зависимости

Если вы используете Register при вызове Get/Setvalue, будет проверяться, что вызов prom является объектом, который может быть записан в тип регистрации.

Пример свойства, которое ведет себя как RegisterAttached, это Grid.Row и Grid.Column.

Ответ 5

Итак, что такое "ownerType", который используется в RegisterAttached? Эта проблема уже несколько лет дергается за меня, поэтому я, наконец, более подробно рассмотрел код 4.6.1 в WindowsBase.

Для любого DependencyProperty, прикрепленного или иным образом, к чему он в конечном итоге сводится к тому, какой тип PropertyDescriptor WPF получает для ограниченного доступа XAML, и это не определяется до первого раза (по одному типу /property pairing), такой попыток доступа. Эта отсрочка необходима, поскольку PropertyDescriptor инкапсулирует свойство, привязанное к определенному типу, тогда как точка прикрепленных свойств должна избегать именно этого.

К тому времени, когда происходит доступ к XAML, различие Register(...) versus RegisterAttached(...) было потеряно для времени тумана (пробега). Как отмечали другие на этой странице, "DependencyProperty" сам по себе не кодирует различие между прикрепленным и неэволюционным. Предполагается, что каждый DP имеет право на любое использование, при условии только того, что может быть выяснено во время выполнения.

Например, нижеприведенный код .NET полагается не на поиск подходящего свойства экземпляра в типе 'tOwner' в качестве первого требования для разрешенного доступа. Чтобы подтвердить этот диагноз, он затем проверяет, предоставляет ли "tOwner" один из методов статического доступа. Это неопределенная проверка, поскольку она не проверяет сигнатуры метода. Эти подписи имеют значение только для доступа XAML; все действительные цели выполнения для прикрепленного свойства должны быть DependencyObject s, которые WPF обращается через DependencyObject.GetValue/SetValue, когда это возможно. (Сообщается, что VS Designer использует статические аксессоры, и ваш XAML не будет компилироваться без них)

Соответствующий .NET-код представляет собой статическую функцию DependencyPropertyDescriptor.FromProperty, показанную здесь с моими собственными комментариями (ниже):

internal static DependencyPropertyDescriptor FromProperty(DependencyProperty dp, Type tOwner, Type tTarget, bool _)
{
    /// 1. 'tOwner' must define a true CLR property, as obtained via reflection, 
    /// in order to obtain a normal (i.e. non-attached) DependencyProperty
    if (tOwner.GetProperty(dp.Name) != null)
    {
        DependencyPropertyDescriptor dpd;

        var dict = descriptor_cache;
        lock (dict)
            if (dict.TryGetValue(dp, out dpd))
                return dpd;

        dpd = new DependencyPropertyDescriptor(null, dp.Name, tTarget, dp, false);
        lock (dict)
            dict[dp] = dpd;

        /// 2. Exiting here means that, if instance properties are defined on tOwner,
        /// you will *never* get the attached property descriptor. Furthermore,
        /// static Get/Set accessors, if any, will be ignored in favor of those instance
        /// accessors, even when calling 'RegisterAttached'
        return dpd;
    }

    /// 3. To obtain an attached DependencyProperty, 'tOwner' must define a public,
    /// static 'get' or 'set' accessor (or both).

    if ((tOwner.GetMethod("Get" + dp.Name) == null) && (tOwner.GetMethod("Set" + dp.Name) == null))
        return null;

    /// 4. If we are able to get a descriptor for the attached property, it is a
    /// DependencyObjectPropertyDescriptor. This type and DependencyPropertyDescriptor
    /// both derive directly from ComponentModel.PropertyDescriptor so they share
    /// no 'is-a' relation.

    var dopd = DependencyObjectProvider.GetAttachedPropertyDescriptor(dp, tTarget);
    /// 5. Note: If the this line returns null, FromProperty isn't called below (new C# syntax)

    /// 6. FromProperty() uses the distinction between descriptor types mentioned in (4.)
    /// to configure 'IsAttached' on the returned DependencyProperty, so success here is 
    /// the only way attached property operations can succeed.
    return dopd?.FromProperty(dopd);
}

Сводка: при вызове RegisterAttached для создания прикрепленного DependencyProperty используется только свойство ownerType, чтобы идентифицировать тип, который определяет соответствующие статические приемники Get/Set. По крайней мере, один из этих аксессуаров должен существовать на "ownerType", или присоединенный доступ XAML не будет компилироваться или не работать. Хотя RegisterAttached не прерывается в этом случае и вместо этого успешно возвращает несуществующий DP. Для DP, предназначенных только для присоединенного использования, "tOwner" не должен выводиться из DependencyObject. Вы можете использовать любой обычный .NET-класс, статический или нестатический, и на самом деле может быть даже структурой!