Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Databound controls shouldn't update if they're not visible

I have a WPF application, and the design follows the standard MVVM model.

When the underlying data changes, my view model fires the PropertyChanged event so that the controls can update.

My main view is a tab control, so the majority of the controls are invisible at any one time. There are performance problems, and I've realised that much of the CPU time is dedicated to fetching data to update invisible controls. (My view model uses lazy evaluation, so it fires the PropertyChanged events, but doesn't actually calculate the final displayable properties until asked).

Does WPF have a standard way to deal with this problem?

Idealy, if an invisible control receives a relevant PropertyChanged event, it should just think "I must requery that property once I'm visible again".

like image 383
Andrew Shepherd Avatar asked May 04 '11 23:05

Andrew Shepherd


2 Answers

I don't think there is any infrastructure to handle deactivating bindings associated with non-visible controls. Unfortunately there are many situations in which you would want a control that is not visible to participate in databinding. Most importantly, you often have a control whose visibility itself depends on a binding. Also, you might have a binding between properties of a visible control and a non-visible control. Or someone might want the exact opposite of what you want: the control to populate itself while non-visible and then jump out fully populated once visible.

I think the only good solution for your situation is to avoid having heavyweight non-visible controls, if that is possible. Specifically for your tab control, I would have thought that would be the default behavior, but perhaps it depends on your situation. Ironically some people complain that the TabControl destroys its children when switching between tabs and would like to know how to prevent that because keeping all the background tabs in memory takes some work. But you seem to have the opposite problem.

For reference, here is the source I mentioned for TabControl children:

  • Keeping the WPF Tab Control from destroying its children

You might be able to do some experiments in a small project to "turn on" the recycling behavior they are trying to turn off. If your control were loaded on demand then tab switching might be little slower but the performance on a tab would improve.

like image 199
Rick Sladkey Avatar answered Nov 12 '22 13:11

Rick Sladkey


We did something along these lines in our base ViewModel..

Note, You have to freeze/thaw corresponding with the View's visibility.

It basically traps all the PropertyChanged events while frozen, and pushes them out when thawed. While also not keeping dupes, as they don't matter in our case.

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private readonly HashSet<string> hashSet = new HashSet<string>();
    private bool isFrozen;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (isFrozen)
        {
            lock (hashSet)
            {
                hashSet.Add(propertyName);
                return;
            }
        }

        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    protected void Freeze()
    {
        isFrozen = true;
    }

    /// <summary>
    /// Enable PropertyChanged Events to fire again
    /// </summary>
    protected void Thaw(bool fireQueued)
    {
        isFrozen = false;
        if (fireQueued)
        {
            lock (hashSet)
            {
                PropertyChangedEventHandler handler = PropertyChanged;
                if (handler != null)
                {
                    foreach (string propertyName in hashSet)
                    {
                        handler(this, new PropertyChangedEventArgs(propertyName));
                    }
                }

                hashSet.Clear();
            }
        }
        else
        {
            hashSet.Clear();
        }
    }
}
like image 24
Peter Drier Avatar answered Nov 12 '22 12:11

Peter Drier