[BUG] Lazy View not working after update to Maui 8
Is there an existing issue for this?
- [X] I have searched the existing issues
Did you read the "Reporting a bug" section on Contributing file?
- [X] I have read the "Reporting a bug" section on Contributing file: https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md#reporting-a-bug
Current Behavior
When a view is loaded with LazyView and there is a Task.Delay() used, then after the view is loaded, the Page remains blank.
The problem started with the update from Maui 7 to 8. The code is the following:
public override async ValueTask LoadViewAsync(CancellationToken token = new CancellationToken()) { Color color;
// Content = new Grid() { Children = { new ActivityIndicator { IsRunning = true, Color = IndicatorColor}.Center() } };
//Content = new ActivityIndicator { IsRunning = true }.Center();
//await Task.Delay(400,token);
// var _view = new TView(){ BindingContext = BindingContext };
// _view = await Task.Run(() => new TView() { BindingContext = BindingContext });
// var animationTask = Task.Delay(500, toekn);
// var viewLoaderTask = Task.Run(() => _view = new TView() { BindingContext = BindingContext }, toekn);
//
// await Task.WhenAll(animationTask , viewLoaderTask);
await Task.Delay(500,token);
//Content = EmbedInScrollView ? new ScrollView() { Content = _view } : _view ;
Content = new TView() { BindingContext = BindingContext };
SetHasLazyViewLoaded(true);
}
If I remove the Task.Delay() everything works as expected but of course the whole purpose of the LazyView is lost.
Expected Behavior
The view should first display the activity indicator and then the loaded View
Steps To Reproduce
The provided project contains a main page which contains only a button. This button navigates to a conentView which only has a lazyLoaded view.
If you run the project you will see that once the ActivityIndicator goes away, the screen remains blank. There are two ways to resolve the issue:
- Embed the lazyview into a Layout (I have tried Grid)
- Remove the Task,Delay() from the CustomLazyView class.
- Remove the Border.StrokeShape into the LazyLoadedView.xaml.
In Maui Version 7 this was working without these workarrounds, thus making existing projects to break.
The exprected result is that the LazyView is working as before, being the only view in a page.
Link to public reproduction project repository
https://github.com/stgiaf/LazyuViewBlankPageIssue.git
Environment
- .NET MAUI CommunityToolkit: 7.0.0
- OS: Android
- .NET MAUI: 8.0.3
Anything else?
No response
Hi @stgiaf. We have added the "needs reproduction" label to this issue, which indicates that we cannot take further action. This issue will be closed automatically in 5 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Added reproducer and workarounds in the expected result section.
Umm @stgiaf - I think sample cuts a bit too many corners. Here's my CustomLazyView that works for me. Please try and let me know.
Host page XAML:
<ContentPage.Content>
<mviews:CustomLazyView x:Name="lazyView" x:TypeArguments="views:UserHistoryView" />
</ContentPage.Content>
Host page Code-behind:
protected override async void OnAppearing()
{
base.OnAppearing();
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
// IMPORTANT! Do not block here. We don't really need any result from the LoadViewAsync anyway.
_ = Task.Run(async()=> await lazyView.LoadViewAsync(cts.Token));
}
The CustomLazyView class that works:
using CommunityToolkit.Maui.Markup;
using CommunityToolkit.Maui.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MauiViews
{
public class CustomLazyView<TView> : LazyView
where TView : View, new()
{
public CustomLazyView()
{
}
public override async ValueTask LoadViewAsync(CancellationToken token)
{
await MainThread.InvokeOnMainThreadAsync(() =>
{ // display a loading indicator
Content = new ActivityIndicator
{
IsRunning = true,
Color = Colors.Black
}.Center();
});
// heavy loading is here - TView sets its own BindingContext.
// Feel free to modify - pass it as a param, pass it down from 'this' etc
var tv = new TView();
// must be done on a main thread
await MainThread.InvokeOnMainThreadAsync(() =>
{
Content = tv;
SetHasLazyViewLoaded(true);
});
}
}
}
Ok, scratch that. As soon as I actually assigned the BindingContext to 'tv' in the LoadViewAsync - it stopped working. The 'wrapping view in Grid' and 'wrapping view content in Grid' didn't help. I think it might be related to the ScrollView, but it is just my guess.
@stgiaf if you remove the white background on your border, you will be able to see the Labels.