Каковы различия между PropertyMetaData, UIPropertyMetadata и FrameworkMetaData в WPF
Я знаю основную разницу между этими классами, которую PropertyMetadata используется при резервном свойстве, UIPropertyMetadata, когда мы хотим иметь поддержку для анимации, и свойства FrameworkMetadata for Framework, которые будут использоваться в пользовательских элементах управления.
Но я понимаю только теоретическую часть.
Это будет отличная идея, если вы объясните простейший пример, который использует все эти 3 класса в 3 различных свойствах зависимости, четко различая их.
Спасибо заранее.
Ответы
Ответ 1
Источник: PropertyMetadata и FrameworkPropertyMetadata
Когда вы реализуете настраиваемое свойство зависимостей, и вы регистрируете свойство, вызывая DependencyProperty.Register
, вы указываете некоторые метаданные для свойства, передавая его экземпляр PropertyMetadata
. Это может быть экземпляр класса PropertyMetadata
или экземпляр одного из его подклассов. Различия показаны ниже.
PropertyMetadata
- Основные метаданные, относящиеся к свойствам зависимостей
-
CoerceValueCallback
- принуждение значения при установке -
DefaultValue
- значение по умолчанию для свойства -
PropertyChangedCallback
- ответьте на новое эффективное значение для свойства
UIPropertyMetadata
- происходит от PropertyMetadata
и добавляет:
-
IsAnimationProhibited
- отключить анимацию для этого свойства?
FrameworkPropertyMetadata
- происходит от UIPropertyMetadata
и добавляет:
-
AffectsArrange
, AffectsMeasure
, AffectsParentArrange
, AffectsParentMeasure
, AffectsRender
- Должны ли повторные запуска вычислений компоновки после изменения значения свойства? -
BindsTwoWayByDefault
, DefaultUpdateSourceTrigger
, IsDataBindingAllowed
, IsNotDataBindable
- Диктует, как свойство участвует в привязке данных -
Inherits
, OverridesInheritanceBehavior
- Работает ли наследование для этого свойства? -
Journal
- сохранить это значение при ведении журнала? -
SubPropertiesDoNotAffectRender
- Проверьте свойства этого объекта при изменении макета?
Ответ 2
Важным практическим различием между PropertyMetadata и FrameworkPropertyMetadata является то, что последний позволяет указать набор FrameworkPropertyMetadataOptions.
Например, указание FrameworkPropertyMetadataOptions.AffectsRender
заботится о том, чтобы инициировать повторный рендеринг элемента UIE, для которого изменилось свойство. Без этого флага вам придется делать это вручную в PropertyChangedCallback.
Ответ 3
Все поведения, предоставляемые FrameworkPropertyMetadata
и UIPropertyMetadata
, управляются битами флага, которые записываются в одном поле enum
(32-bit uint
), называемом _flags
которое объявлено в базовом классе PropertyMetadata
, даже при том, что ни один из флагов на самом деле публично не предоставляется из там. Вот объявление этого enum
:
internal enum MetadataFlags : uint
{
DefaultValueModifiedID /**/= 0b_00000000_00000000_00000000_00000001, //0x00000001
SealedID /**/= 0b_00000000_00000000_00000000_00000010, //0x00000002
Inherited /**/= 0b_00000000_00000000_00000000_00010000, //0x00000010
UI_IsAnimationProhibitedID /**/= 0b_00000000_00000000_00000000_00100000, //0x00000020
FW_AffectsMeasureID /**/= 0b_00000000_00000000_00000000_01000000, //0x00000040
FW_AffectsArrangeID /**/= 0b_00000000_00000000_00000000_10000000, //0x00000080
FW_AffectsParentMeasureID /**/= 0b_00000000_00000000_00000001_00000000, //0x00000100
FW_AffectsParentArrangeID /**/= 0b_00000000_00000000_00000010_00000000, //0x00000200
FW_AffectsRenderID /**/= 0b_00000000_00000000_00000100_00000000, //0x00000400
FW_OverridesInheritanceBehaviorID /**/= 0b_00000000_00000000_00001000_00000000, //0x00000800
FW_IsNotDataBindableID /**/= 0b_00000000_00000000_00010000_00000000, //0x00001000
FW_BindsTwoWayByDefaultID /**/= 0b_00000000_00000000_00100000_00000000, //0x00002000
FW_ShouldBeJournaledID /**/= 0b_00000000_00000000_01000000_00000000, //0x00004000
FW_SubPropertiesDoNotAffectRenderID /**/= 0b_00000000_00000000_10000000_00000000, //0x00008000
FW_SubPropertiesDoNotAffectRenderModifiedID= 0b_00000000_00000001_00000000_00000000, //0x00010000
FW_InheritsModifiedID /**/= 0b_00000000_00010000_00000000_00000000, //0x00100000
FW_OverridesInheritanceBehaviorModifiedID = 0b_00000000_00100000_00000000_00000000, //0x00200000
FW_ShouldBeJournaledModifiedID /**/= 0b_00000001_00000000_00000000_00000000, //0x01000000
FW_UpdatesSourceOnLostFocusByDefaultID /**/= 0b_00000010_00000000_00000000_00000000, //0x02000000
FW_DefaultUpdateSourceTriggerModifiedID/**/= 0b_00000100_00000000_00000000_00000000, //0x04000000
FW_ReadOnlyID /**/= 0b_00001000_00000000_00000000_00000000, //0x08000000
FW_DefaultUpdateSourceTriggerEnumBit1 /**/= 0b_01000000_00000000_00000000_00000000, //0x40000000
FW_DefaultUpdateSourceTriggerEnumBit2 /**/= 0b_10000000_00000000_00000000_00000000, //0x80000000
};
Обратите также внимание на то, как взаимодействуют следующие три свойства, все объявленные FrameworkPropertyMetadata
. То есть IsDataBindingAllowed
- это не то же самое, что !IsNotDataBindable
; первый добавляет дополнительное ограничение, исключающее использование неправильного направления привязки для свойств "только для чтения".
private bool ReadOnly => (_flags & FW_ReadOnlyID) != 0;
public bool IsDataBindingAllowed =>
(_flags & FW_IsNotDataBindableID) == 0 && !this.ReadOnly;
public bool IsNotDataBindable => (_flags & FW_IsNotDataBindableID) != 0;
[edit:] ALERT/WARNING: По какой-то неизвестной причине флаги, показанные выше, не разделяют значения, указанные в соответствующем флаге FrameworkPropertyMetadataOptions
! [Flags]
public enum FrameworkPropertyMetadataOptions
{ // FPMO MetadataFlags
// ---------- ----------
// 0x00000010 ←┐
None /**/ = 0x00000000, // │
AffectsMeasure /**/ = 0x00000001, // << 6 0x00000040 │
AffectsArrange /**/ = 0x00000002, // << 6 0x00000080 │
AffectsParentMeasure /**/ = 0x00000004, // << 6 0x00000100 │
AffectsParentArrange /**/ = 0x00000008, // << 6 0x00000200 │
AffectsRender /**/ = 0x00000010, // << 6 0x00000400 │
Inherits /**/ = 0x00000020, // >> 1 → → ────┘
OverridesInheritanceBehavior /**/ = 0x00000040, // << 5 0x00000800
NotDataBindable /**/ = 0x00000080, // << 5 0x00001000
BindsTwoWayByDefault /**/ = 0x00000100, // << 5 0x00002000
Journal /**/ = 0x00000400, // << 4 0x00004000
SubPropertiesDoNotAffectRender /**/ = 0x00000800, // << 4 0x00008000
};