Notifying all properties of the viewmodel has changed with null or string empty
Asked Answered
S

3

2

I'm coming from developing WPF solutions where to update all properties of the viewmodel was as simple as:

OnPropertyChanged(String.Empty);

In the Universal Windows Platform scenario, I just have the same method to update/refresh the properties. This works fine in most of cases but sometimes it raise an error something like this:

COMException Error HRESULT E_FAIL has been returned from a call to a COM component. at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e) at GeekyTool.Base.BindableBase.OnPropertyChanged(String propertyName) at Pooo.set_Root(UserRoot value) at Booo.d__26.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at GeekyTool.Base.PageBase.d__1.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.b__6_0(Object state) at System.Threading.WinRTSynchronizationContext.Invoker.InvokeCore()

The OnPropertyChanged method with an INotifyPropertyChanged interface implementation look like this:

public abstract class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public virtual bool Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
    {
        if (object.Equals(storage, value))
            return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

You can explore the mvvm library, but nothing different on the INotifyPropertyChanged implementation.

GeekyTool Library on Github

Stinkwood answered 27/3, 2017 at 14:22 Comment(3)
I surprised if this ever worked on UWP. There is nothing special in the code to handle a property name of String.Empty. Do you have a full repro available? stackoverflow.com/help/mcveExanthema
@MattLacey, raising the INotifyPropertyChanged.PropertyChanged event with string.empty is an "old" trick that AFAIK, works fine in UWP to force all (classical or compiled) bindings to refresh!Zavras
if you are using x:bind you can call 'this.Bindings.Update()' from the code behind of the page to force all bindings on that page to update.Gaggle
S
2

Thank's for all the answers, I was trying to fix an error that it isn't was there.

In the OnPropertyChanged(string.Empty) method raise the error because it comes with an sync context issue from the page before.

It happens when you are navigating between two page very fast and has some async calls in the OnNavigatedTo method where they aren't finished yet. The async method are awaited, but in this page was not handled that the user wait until this is finished.

Just to know that no need to apply @PedroLamas fix. Ensuring on the page before that all async calls are finished it's done.

Stinkwood answered 30/3, 2017 at 10:12 Comment(0)
Z
2

I see on the stack trace that there's some async code, so I'd suggest only invoking OnPropertyChanged(String.Empty) with the Dispatcher, like so:

Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    OnPropertyChanged(string.Empty);
});
Zavras answered 27/3, 2017 at 16:38 Comment(2)
The question is that the OnPropertyChanged(string.Empty); is done in a setter, so what I can do is an async operation without awaiting it. Is that correct? Thanks!Stinkwood
Correct, you don't need to await that Dispatcher call, it doesn't matter for what you need here!Zavras
S
2

Thank's for all the answers, I was trying to fix an error that it isn't was there.

In the OnPropertyChanged(string.Empty) method raise the error because it comes with an sync context issue from the page before.

It happens when you are navigating between two page very fast and has some async calls in the OnNavigatedTo method where they aren't finished yet. The async method are awaited, but in this page was not handled that the user wait until this is finished.

Just to know that no need to apply @PedroLamas fix. Ensuring on the page before that all async calls are finished it's done.

Stinkwood answered 30/3, 2017 at 10:12 Comment(0)
J
1

CallerMemeberName pulls calling member name if you pass in nothing (or null) that isn’t the same string.empty

I’d fix that first.

public bool IsValid
{
    get { return isValid; }
    set
    {
        if (isValid == value)
        {
            return;
        }

        isValid = value;
        OnPropertyChanged();
    }
}

This should work. Often where I can’t use ReactiveObject or ObservableObject I tend to use this.

Jadotville answered 27/3, 2017 at 22:26 Comment(1)
Yes, but as @PedroLamas says, raising the INotifyPropertyChanged.PropertyChanged event with string.Empty is an "old" trick to force all binding to update/refresh. That is what I'm doing, updating all at once.Stinkwood

© 2022 - 2024 — McMap. All rights reserved.