none
Data binding "dies" in release build

    Question

  • I have a window that displays the results of a lengthy asynchronous operation. (The actual operation is performed by a BackgroundWorker.) In my RunWorkerCompleted handler, I set some properties on an object that implements INotifyPropertyChanged. In the XAML that describes the window, I bind some TextBlocks to the values of those properties.

     

    In a Debug build, everything works exactly as expected. In a Release build, however, the property changes are not propagated from the object to the window. In other words, I have coded a bunch of tracing in my object, and I see that the object properties are being set to values that I expect (and that the lengthy operation is completing), but the TextBlocks on the window remain empty.

     

    I turned on the built-in WPF tracing for data binding (http://www.beacosta.com/blog/?p=52) and the messages for a Debug build look normal, but in the Release build, the data binding "dies" after the first time it's called (with <null>).

     

    Here is a snipped trace from the Debug build:

     

    System.Windows.Data Warning: 52 : BindingExpression (hash=49590434): Default update trigger resolved to PropertyChanged
    System.Windows.Data Warning: 53 : BindingExpression (hash=49590434): Attach to System.Windows.Controls.TextBlock.Text (hash=16977025)
    System.Windows.Data Warning: 58 : BindingExpression (hash=49590434): Resolving source
    System.Windows.Data Warning: 61 : BindingExpression (hash=49590434): Found data context element: TextBlock (hash=16977025) (OK)
    System.Windows.Data Warning: 69 : BindingExpression (hash=49590434): Activate with root item UpdatesWindowViewModel (hash=25768654)
    System.Windows.Data Warning: 98 : BindingExpression (hash=49590434):   At level 0 - for UpdatesWindowViewModel.Title found accessor RuntimePropertyInfo(Title)
    System.Windows.Data Warning: 94 : BindingExpression (hash=49590434): Replace item at level 0 with UpdatesWindowViewModel (hash=25768654), using accessor RuntimePropertyInfo(Title)
    System.Windows.Data Warning: 91 : BindingExpression (hash=49590434): GetValue at level 0 from UpdatesWindowViewModel (hash=25768654) using RuntimePropertyInfo(Title): <null>
    System.Windows.Data Warning: 71 : BindingExpression (hash=49590434): TransferValue - got raw value <null>
    System.Windows.Data Warning: 73 : BindingExpression (hash=49590434): TransferValue - user's converter produced ''
    System.Windows.Data Warning: 78 : BindingExpression (hash=49590434): TransferValue - using final value ''
    System.Windows.Data Warning: 85 : BindingExpression (hash=49590434): Got PropertyChanged event from UpdatesWindowViewModel (hash=25768654)
    System.Windows.Data Warning: 91 : BindingExpression (hash=49590434): GetValue at level 0 from UpdatesWindowViewModel (hash=25768654) using RuntimePropertyInfo(Title): 'Checking for updates...'
    System.Windows.Data Warning: 71 : BindingExpression (hash=49590434): TransferValue - got raw value 'Checking for updates...'
    System.Windows.Data Warning: 73 : BindingExpression (hash=49590434): TransferValue - user's converter produced 'Checking for updates...'
    System.Windows.Data Warning: 78 : BindingExpression (hash=49590434): TransferValue - using final value 'Checking for updates...'

    And here is the same trace from the Release build:

     

    System.Windows.Data Warning: 52 : BindingExpression (hash=54308798): Default update trigger resolved to PropertyChanged
    System.Windows.Data Warning: 53 : BindingExpression (hash=54308798): Attach to System.Windows.Controls.TextBlock.Text (hash=19017142)
    System.Windows.Data Warning: 58 : BindingExpression (hash=54308798): Resolving source
    System.Windows.Data Warning: 61 : BindingExpression (hash=54308798): Found data context element: TextBlock (hash=19017142) (OK)
    System.Windows.Data Warning: 69 : BindingExpression (hash=54308798): Activate with root item UpdatesWindowViewModel (hash=36936550)
    System.Windows.Data Warning: 98 : BindingExpression (hash=54308798):   At level 0 - for UpdatesWindowViewModel.Title found accessor RuntimePropertyInfo(Title)
    System.Windows.Data Warning: 94 : BindingExpression (hash=54308798): Replace item at level 0 with UpdatesWindowViewModel (hash=36936550), using accessor RuntimePropertyInfo(Title)
    System.Windows.Data Warning: 91 : BindingExpression (hash=54308798): GetValue at level 0 from UpdatesWindowViewModel (hash=36936550) using RuntimePropertyInfo(Title): <null>
    System.Windows.Data Warning: 71 : BindingExpression (hash=54308798): TransferValue - got raw value <null>
    System.Windows.Data Warning: 73 : BindingExpression (hash=54308798): TransferValue - user's converter produced ''
    System.Windows.Data Warning: 78 : BindingExpression (hash=54308798): TransferValue - using final value ''

    (The messages just stop after that point; I don't get the second PropertyChanged event as I do in Debug.) I added a no-op converter just to watch the value.

     

    Any ideas what's going on here? Is there something else I should try?

    Tuesday, April 08, 2008 7:57 PM

Answers

  • I found the answer.

     

    My implementation of INotifyPropertyChanged includes a trick that somebody showed me:

     

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)

    {

    PropertyChangedEventHandler tmp = PropertyChanged;

    if (tmp != null)

    {

    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

    }

    return;

    }

     

    protected virtual void OnPropertyChanged()

    {

    // This overload is very convenient to use,

    // but it doesn't always work in a Release build!

    StackTrace stackTrace = new StackTrace();

    string propertyName = stackTrace.GetFrame(1).GetMethod().Name.Substring(4);

    OnPropertyChanged(propertyName);

    return;

    }

    #endregion

     

     

    When I change the setter in my viewmodel to use the OnPropertyChanged(propertyName) overload, everything works as expected in both Debug and Release builds. However, calling the OnPropertyChanged() version (that looks up the property from the stack trace) does not always fire the event. I haven't traced through the OnPropertyChanged() to see what happens in a Release build.

    Wednesday, April 09, 2008 1:23 PM

All replies

  • FYI... I was just able to repro this issue in a very simple test application. I'll be happy to send it along if anybody wants to take a look.

     

    The problem actually appears to be even more straightforward than my earlier description: Basically, if code in the Loaded handler for the window affects an object (like a viewmodel) that has properties to which controls in the window are bound, then data binding stops working "automatically". I was able to update the binding targets explicitly with code triggered by a button click, but I'd like to do more investigation there.

     

    And remember, this only happens for Release builds run outside of the debugger. Debug builds and running the Release configuration inside the debugger are fine.

    Tuesday, April 08, 2008 9:29 PM
  • I found the answer.

     

    My implementation of INotifyPropertyChanged includes a trick that somebody showed me:

     

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)

    {

    PropertyChangedEventHandler tmp = PropertyChanged;

    if (tmp != null)

    {

    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

    }

    return;

    }

     

    protected virtual void OnPropertyChanged()

    {

    // This overload is very convenient to use,

    // but it doesn't always work in a Release build!

    StackTrace stackTrace = new StackTrace();

    string propertyName = stackTrace.GetFrame(1).GetMethod().Name.Substring(4);

    OnPropertyChanged(propertyName);

    return;

    }

    #endregion

     

     

    When I change the setter in my viewmodel to use the OnPropertyChanged(propertyName) overload, everything works as expected in both Debug and Release builds. However, calling the OnPropertyChanged() version (that looks up the property from the stack trace) does not always fire the event. I haven't traced through the OnPropertyChanged() to see what happens in a Release build.

    Wednesday, April 09, 2008 1:23 PM
  • I would suggest avoiding the trick with StackTrace completely.

    You might find the approaches shown in this discussion more useful: “Best Practices: How to implement INotifyPropertyChanged right?”.

    Saturday, April 18, 2009 8:43 PM