Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change only a single option of a DependencyProperty's metadata in a subclass?

We need to override a DependencyProperty's metadata for our subclass. Now I know that I can use OverrideMetadata and specify entirely new FrameworkPropertyMetadata object, but for the most part I want this new metadata to be exactly the same as the existing metadata except with one additional flag set (specifically AffectsMeasure)

My thought is to get the existing metadata, create a new metadata object, hand-copy all the members over from the old to the new (it doesn't support Clone) changing the one I want, then use the new one in the OverrideMetadata call. But da** that is a lot of work for something otherwise so simple!

Am I missing something here?

EDIT

First things first, I meant AffectsMeasure not AffectsRender (which I've changed above),

BUT... I just found out our class already has the AffectsMeasure flag set for the Width property. The real issue is for containers of a ListBox (e.g. a ListBoxItem) the MeasureOverride is only called once, when first initialized.

Since this is technically an unrelated question, I'll start a new one and close this one.

Here's the link to the new question:

Why is a ListBoxItem not calling MeasureOverride when its width is changed?

like image 866
Mark A. Donohoe Avatar asked Nov 05 '22 13:11

Mark A. Donohoe


1 Answers

Copying the metadata from the base class' metadata is definitely the way to go. Though unfortunately the FrameworkPropertyMetadata class doesn't expose the flags as they given, they are exposed as bool properties to indicate their state. To get those values back as a FrameworkPropertyMetadataOptions, you'll have to go through the associated properties and read them back as one.

static DerivedClass()
{
    var oldMeta = (FrameworkPropertyMetadata)BaseClass.SomeProperty.GetMetadata(typeof(BaseClass));
    var flags = GetFlags(oldMeta);

    // change the values as needed
    var meta = new FrameworkPropertyMetadata(
        oldMeta.DefaultValue,
        flags,
        oldMeta.PropertyChangedCallback,
        oldMeta.CoerceValueCallback,
        oldMeta.IsAnimationProhibited,
        oldMeta.DefaultUpdateSourceTrigger
    );

    BaseClass.SomeProperty.OverrideMetadata(typeof(DerivedClass), meta);
}

static FrameworkPropertyMetadataOptions GetFlags(FrameworkPropertyMetadata metadata)
{
    FrameworkPropertyMetadataOptions flags = FrameworkPropertyMetadataOptions.None;
    if (metadata.AffectsArrange)
        flags |= FrameworkPropertyMetadataOptions.AffectsArrange;
    if (metadata.AffectsMeasure)
        flags |= FrameworkPropertyMetadataOptions.AffectsMeasure;
    if (metadata.AffectsParentArrange)
        flags |= FrameworkPropertyMetadataOptions.AffectsParentArrange;
    if (metadata.AffectsParentMeasure)
        flags |= FrameworkPropertyMetadataOptions.AffectsParentMeasure;
    if (metadata.AffectsRender)
        flags |= FrameworkPropertyMetadataOptions.AffectsRender;
    if (metadata.BindsTwoWayByDefault)
        flags |= FrameworkPropertyMetadataOptions.BindsTwoWayByDefault;
    if (metadata.Inherits)
        flags |= FrameworkPropertyMetadataOptions.Inherits;
    if (metadata.Journal)
        flags |= FrameworkPropertyMetadataOptions.Journal;
    if (metadata.IsNotDataBindable)
        flags |= FrameworkPropertyMetadataOptions.NotDataBindable;
    if (metadata.OverridesInheritanceBehavior)
        flags |= FrameworkPropertyMetadataOptions.OverridesInheritanceBehavior;
    if (metadata.SubPropertiesDoNotAffectRender)
        flags |= FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender;
    return flags;
}
like image 107
Jeff Mercado Avatar answered Nov 15 '22 08:11

Jeff Mercado