5

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?

Community
  • 1
  • 1
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
  • Hi, what you could do as well is to call InvalidateVisual within your DP change value event handler, which to me is a cleaner way of doing that. –  Oct 04 '11 at 08:13

1 Answers1

2

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;
}
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • Looking at the implementation of the `FrameworkPropertyMetadata`, it maintains other state so cloning in general probably wouldn't be a good idea. – Jeff Mercado Oct 04 '11 at 06:54
  • It doesn't support 'Clone' anyway. BUT... turns out this isn't the issue. I'm posting a new question related to what we're dealing with, which is a ListBoxItem that gets resized, but which doesn't internally call the MeasureOverride even though that flag is set for the Width property, and we don't know why. – Mark A. Donohoe Oct 04 '11 at 23:18