WPF CustomControl: OnApplyTemplate called after PropertyChangedCallback
Asked Answered
M

1

10

I am creating a WPF CustomControl that has a dependency property with PropertyChangedCallback. In that Callback method I try to set values on some of the control's parts that I retrieve from OnApplyMethod using the GetTemplateChild() method.

The problem is that the PropertyChangedCallback is (on some systems) called before OnApplyTemplate so the control parts are still null.

The workaround I'm currently using is to save e.NewValue from the PropertyChangedCallback to a member variable and then call SetValue(dp, _savedValue) in OnApplyTemplate().

What is the proper way to deal with this problem or am I already using the best solution?

Mcarthur answered 19/8, 2009 at 10:2 Comment(1)
Not sure why anybody hasn't answered your question yet but I can say that I'm pretty much doing the same thing as you and so far it generally seems to work. I have run into a particular problem recently in a SplitButton implementation that does this where the first selected item does not show up but after manually selecting an item it does.Marna
D
8

that's what we do - doesn't solve the problme in priciple but provides with a clear way to fix it.

  1. Create a handler for the DP value changed event, let it be OnValueChanged().Generally no paramters needed as you know which DP is changed and can always obtain its current value.

  2. Create a class/struct called DeferredAction with the constructor, accepting System.Action (that's going to be a ref to your OnValueChanged()). The class will have a property Action and a method, called Execute().

Here's what I use:

class DeferredAction
{
   private Action action;

    public DeferredAction(Action action)
    {
        this.action = action;
    }

    private Action Action
    {
        get { return this.action; }
    }

    public void Execute()
    {
        this.Action.Invoke();
    }
}
  1. In your control create a List. The collection will keep the list of DeferredAction's until they can be successfully applied (typically after base.OnApplyTemplate()). Once actions are applied the collection has to be cleared to avoid double processing.

  2. Within OnValueChanged do check if your Part(s) is not null (which it likely is) and if so add a new instance of DeferredAction(OnValueChanged() to the list created at a previous step. Note, OnValueChanged() is a dual purpose handler it can be called right from your DP value changed handler, if Parts aren't null, alterantively it's used as an executable deferred action.

  3. Within you OnApplyTemplate loop through your deferred actions list (you know, if they're there, they haven't been applied) and call Execute for each of them. Clear the list at the end.

Cheers

Dakota answered 21/1, 2011 at 9:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.