UWP Boolean does not update in UI if set after expected asynchronous call

I have a public boolean in my UWP app used to show / hide ProgressBar. I've used the same template elsewhere and it seems to work fine, but I have a problem on a specific page where it doesn't seem to be updated in the UI, only if I set a boolean after the expected asynchronous call (that same template as work page).

Here is my XAML View:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock Text="{ x:Bind Vm.IsLoaded }" Margin="112,272,-112,-272"></TextBlock>
</Grid>

      

And the codebehind:

public sealed partial class MainPage : Page
{
    public MainPageViewModel Vm => DataContext as MainPageViewModel;
    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = new MainPageViewModel();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        Vm.GetProjectData();
    }
}

      

Here is my MainPageViewModel.cs

public class MainPageViewModel : ViewModel
{
    public ObservableCollection<Project> Projects { get; set; } = new ObservableCollection<Project>();

    private bool _isLoaded;
    public bool IsLoaded
    {
        get { return _isLoaded; }
        set
        {
            _isLoaded = value;
            OnPropertyChanged();
        }
    }

    public async Task GetProjectData()
    {
        // If I put `IsLoaded = true;` here it displays `true` in the UI
        var projectsResponse = await HttpUtil.GetAsync(StringUtil.ProjectsUrl());
        // If I put `IsLoaded = true;` here it still displays `false` in the UI
        if (projectsResponse.IsSuccessStatusCode)
        {
            var projectsResponseString = await projectsResponse.Content.ReadAsStringAsync();
            var projects = JsonUtil.SerializeJsonToObject<List<Project>>(projectsResponseString);

            foreach (var project in projects)
            {
                Projects.Add(project);
            }

            IsLoaded = true;
       }
    }
}

      

And my ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

      

No matter where I put it IsLoaded = true;

, it always hits OnPropertyChanged ().

Here is my working code:

ProjectViewViewModel.cs:

public class ProjectViewViewModel : ViewModel
{
    public ObservableCollection<Story> MyData { get; set; } = new ObservableCollection<Story>();
    private bool _dataIsLoaded;
    public bool DataIsLoaded
    {
        get { return _dataIsLoaded; }
        set
        {
            _dataIsLoaded = value;
            OnPropertyChanged();
        }
    }

    public async Task GetData(Project project)
    {
        DataIsLoaded = false;
        var stringResponse = await HttpUtil.GetAsync(StringUtil.Query(project.Id, "MB"));
        if (stringResponse.IsSuccessStatusCode)
        {
            // Do Stuff

            DataIsLoaded = true;
        }
    }
}

      

ProjectView.xaml.cs

public sealed partial class ProjectView : Page
{
    public Project Project { get; set; }
    public bool IsLoaded { get; set; }
    public ProjectViewViewModel Vm => DataContext as ProjectViewViewModel;
    public ProjectView()
    {
        this.InitializeComponent();
        this.DataContext = new ProjectViewViewModel();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);

        Project = e.Parameter as Project;
        Vm.GetData(Project);
    }
}

      

I feel like I'm missing something extremely obvious, but I can't see the tree through the trees and it drives me crazy. Any help is greatly appreciated!

+3


source to share


1 answer


I believe the problem you are having is at your mark. x: binding has a default binding mode OneTime

; therefore, the text in the text block is bound to the IsLoaded value when the application starts or when the data context for the text block changes.

Setting the binding mode to OneWay

should cause the text block to be updated after the async function returns.



<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <TextBlock Text="{ x:Bind Path=Vm.IsLoaded, Mode=OneWay }" Margin="112,272,-112,-272"></TextBlock>
</Grid>

      

If you're interested, this article goes into detail about using x: Bind. In addition, this article covers the values ​​in the BindingMode enumeration.

+6


source







All Articles