2
votes

Currently for an application I'm developing, I hide a parent container in the view and show a loading animation in its place while loading is in progress - updating the UI seems to struggle (and hang pretty hard) when all the databound controls are visible while being updated.

Ideally, I'd like to be able to disable the parent container, reduce its opacity and overlay the loading animation on top - but keep the parent container visible the way it was before loading. Once loading is complete, I'd like to then allow the databound controls to update.

I haven't had much luck tracking down a solution for this... the closest I've been able to find is the delay property that can be set on a binding, but obviously that's not very useful in this case.

I have a boolean IsLoading property in my viewmodel that I'd like to drive this.

Any suggestions?

2
This is why we have priority bindings. Look 'em up.user1228

2 Answers

0
votes

There is a way to explicitly control when the source of a two-way binding is updated (using UpdateSourceTrigger="Explicit"), but I don't think you can control when the target is updated.

The easiest option is probably to clear the DataContext of the container while you're loading the data, and set it back when it's done.

0
votes

I typically solve this type of problem this way. Let's say your ViewModel is representing an object of type Dog, and so your ViewModel is likely named DogViewModel or DogVM (I prefer the latter, unless I'm writing software to manage virtual machines, but I digress). So let's say this DogVM class looks like this:

public sealed class DogVM : INotifyPropertyChanged // because bindings, yeah?
{
    public string Name { /* stuff here */ }
    public string Breed { /* stuff here */ }
    public string Coat { /* stuff here */ }
    public DateTime BornOn { /* stuff here */ }
    public bool IsLoading { /* stuff here */ }

    // other stuff as well, like INotifyPropertyChanged implementation
}

If your VM looks like this, what you've got is mixed concerns. You have two concerns: loading the data (and reflecting that state in a bindable way), and adapting your model to your view in a bindable way.

I'd recommend teasing this code apart into two classes. One to handle the loading state, and another to handle the display details of the Dog class. For example:

public sealed class DogLoaderVM : INotifyPropertyChanged
{
    public DogVM Dog { /* stuff here */ }
    public bool IsLoading { /* stuff here */ }

    // other stuff here
}

public sealed class DogVM : INotifyPropertyChanged
{
    public string Name { /* stuff here */ }
    public string Breed { /* stuff here */ }
    public string Coat { /* stuff here */ }
    public DateTime BornOn { /* stuff here */ }

    // other stuff here
}

Then, for any given binding that was originally something like this:

<TextBlock Text="{Binding Name}" />

You update it to be:

    <TextBlock Text="{Binding Dog.Name}" />

Using this pattern, you have a couple of options. You could leave the Dog property in DogLoaderVM with a value of null until it's loaded, and then deal with the absence of values in your XAML directly (say, via TargetNullValue).

However, if that's too complex and would require dirty, ugly, nasty things in your XAML (such things being, of course, a relative term when dealing in XAML), you could extract an interface from DogVM, and use the null object pattern to get fine-grained control over what data gets bound to your view while the load is still pending. Some folks like to put "(loading...)" into the UI, for instance, while loads are pending and that can get pretty cumbersome and redundant in XAML, whereas it's less tedious in C#.