CommunityToolkit/Maui

[BUG] DrawingView Doesn't Clear Lines When Navigating Back to Screen B

vplife1 opened this issue · 22 comments

Is there an existing issue for this?

  • I have searched the existing issues

Did you read the "Reporting a bug" section on Contributing file?

Current Behavior

I am facing an issue with the DrawingView in the MAUI Community Toolkit. The problem occurs when navigating between two screens (A and B) in my app.

Actual Behavior: The line/signature drawn on the DrawingView remains visible even after navigating away and coming back, despite attempting to clear the drawing.

Expected Behavior

When the user navigates back to Screen A and then returns to Screen B, the DrawingView should be cleared, showing a blank canvas.

Steps To Reproduce

Launch the app, which starts on Screen A.
On Screen A, there is a "Go" button. When the user clicks this button, the app navigates to Screen B.
On Screen B, the user draws a signature or line using the DrawingView.
The user then navigates back to Screen A.
Upon clicking the "Go" button again to navigate to Screen B, the previously drawn line/signature is still visible, even though I have attempted to clear the DrawingView when navigating back.

Link to public reproduction project repository

https://github.com/jamesmontemagno/MauiSignaturePad

Environment

- .NET MAUI CommunityToolkit:
- OS:
- .NET MAUI:

Anything else?

No response

@vplife1 the repo that you have provided does not replicate the steps that you've mentioned. There is only one page inside therefore there is no navigation. Can you please provide a sample that reproduces the issue.

I suspect that the issue might relate to how things are registered in your project but we can only determine that if you provide it

MauiSignaturePad-master.zip

Hello @bijington can used this Zip file

@vplife1 we don't accept zip files do to the risk of what could be inside, I've literally just marked another comment on this issue as spam for the same reason. Please provide an open GitHub or GitLab repository.

Uploading MicrosoftTeams-video.mp4…

Please check above video

I got same problem Even calling the Clear method doesn't work, It seems that the handler's is destroyed, as not even DrawingLineCompleted works anymore

@LaBoss do have any workaround?
I am facing this issue on Android only iOS its Working Fine .

Hello jfversluis Could you help me out with this issue what exactly happen?

@LaBoss do have any workaround? I am facing this issue on Android only iOS its Working Fine .

I don't have, i think the problem is on OnDrawingViewUnloaded all handler's are removed and then when you return to the page they are not added again

@LaBoss thanks for the pointer. It does sound like there is a potential issue around navigating away from a page and back to the same instance with a DrawingView and things appear disconnected.

As a workaround you can avoid navigating back to the same instance and try to use a new instance of the page each time. That is what our sample application does and that is how I have been able to get your repo working. I made the following changes:

AppShell.xaml

Remove the MainPage entry so it should look as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MauiDrawing.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiDrawing"
    Shell.FlyoutBehavior="Disabled"
    Title="MauiDrawing">

    <ShellContent
        Title="Test"
        ContentTemplate="{DataTemplate local:testview}"
        Route="testview" />
     

</Shell>

MauiProgram.cs

Register a route to the MainPage -> Routing.RegisterRoute(nameof(MainPage), typeof(MainPage));.

This will result in your MauiProgram file looking as follows:

using Microsoft.Extensions.Logging;
using CommunityToolkit.Maui;

namespace MauiDrawing;
public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder.UseMauiApp<App>().ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
        }).UseMauiCommunityToolkit();
#if DEBUG
        builder.Logging.AddDebug();
#endif
        
        Routing.RegisterRoute(nameof(MainPage), typeof(MainPage));
        
        return builder.Build();
    }
}

testview.xaml.cs

Change the query when navigating to MainPage.

namespace MauiDrawing;

public partial class testview : ContentPage
{
	public testview()
	{
		InitializeComponent();
	}

    void Button_Clicked(System.Object sender, System.EventArgs e)
    {
         Shell.Current.GoToAsync($"{nameof(MainPage)}");
    }
}

Another potential workaround is registering the main page as Transient.

Another potential workaround is registering the main page as Transient.

What is the default lifecycle of a page if it's not registered? I assumed it would be transient as anything else feels a little dangerous

bijington Still facing the same issue do you have any other workaround?

Did you try my workaround? That solves it

@bijington Yes I have tried but still it's not working
@LaBoss @VladislavAntonyuk


Bug Description

I encountered an issue in my .NET MAUI project involving navigation between views. The problem occurs when navigating from HomeView to AppointmentDetailsView, which contains a DrawingView. The DrawingView works correctly on the first navigation, but after navigating back to HomeView and then returning to AppointmentDetailsView, the DrawingView does not work properly on the Android platform. This issue is not present on iOS.

Code Details

In my project, the HomeView is bound to the HomeViewModel like this:

public HomeView(HomeViewModel homeViewModel)
{
    try
    {
        InitializeComponent();
        this.BindingContext = homeViewModel;
        vm = homeViewModel;
        Subscribe();
    }
    catch (Exception ex)
    {
        // Handle exception
    }
}

The navigation to AppointmentDetailsView is managed in the HomeViewModel as follows:

[RelayCommand]
private async Task OpenAppointment(object appointmentData)
{
    try
    {
        Frame views = appointmentData as Frame;
        if (views != null)
        {
            var data = views.BindingContext as Grouping;
            if (data != null)
            {
                Dictionary<string, object> CurrentAppointmentData = new Dictionary<string, object>();
                CurrentAppointmentData.Add("CurrentAppointment", data);

                if (data.actualStartTime.Date != DateTime.Today.Date)
                {
                    UserDialogs.Instance.Toast("The current appointment is scheduled for a future date, so it cannot be rendered", TimeSpan.FromSeconds(7));
                }
                else if (data.appointmentStatus.Contains(AppMessages.RenderedStatus) && data.isParentSignatureCaptured && data.isTherapistSignatureCaptured)
                {
                    UserDialogs.Instance.Toast("Rendered appointment cannot be edited", TimeSpan.FromSeconds(7));
                }
                await _navigationService.NavigateToAsync($"//{nameof(AppointmentDetailsView)}", CurrentAppointmentData);
            }
        }
    }
    catch (Exception ex)
    {
        CommonUtility.Instance.HideLoading();
        CommonUtility.Instance.ExceptionLogs($"{AppMessages.PageName} {Pagename} ,{AppMessages.FunctionName} OpenAppointment ," +
       $"{AppMessages.Date} {DateTime.Today} , {AppMessages.Exception} {ex}");
    }
}

The issue arises after navigating back to HomeView and then trying to open AppointmentDetailsView again:

[RelayCommand]
private async Task Back()
{
    try
    {
        await _navigationService.NavigateToAsync($"//{nameof(HomeView)}");
    }
    catch (Exception ex)
    {
        // Handle exception
    }
}

Registration in MauiProgram and AppShell.xaml

Both views are registered in MauiProgram.cs and AppShell.xaml like this:

MauiProgram.cs:

mauiAppBuilder.Services.AddTransient<AppointmentDetailsView>();
mauiAppBuilder.Services.AddTransient<HomeView>();

AppShell.xaml:

<ShellContent            
    Title="Appointment Details"
    ContentTemplate="{DataTemplate views:AppointmentDetailsView}"
    Route="AppointmentDetailsView"
    Shell.FlyoutItemIsVisible="False"/>   

<ShellContent
    Icon="homemen.png"
    Title="Home" Shell.FlyoutItemIsVisible="False"
    ContentTemplate="{DataTemplate views:HomeView}"
    Route="HomeView"/>

Issue

Even after ensuring both pages are properly registered and navigating as described, the DrawingView in AppointmentDetailsView fails to work correctly when returning to this view after navigating back to HomeView. This issue seems to be isolated to the Android platform.


Those aren't the same changes as I proposed. You want to remove the HomeView from your AppShell

Hello @bijington ,

My previous issue was resolved by adding the control in the OnAppearing method of the .cs page. However, I've encountered a new problem.

Issue Details:

After the user draws a line near the border of the DrawingView and navigates back and forth between pages, the lines are cleared correctly, but some residual pixels remain at the border. I've attached an image below to demonstrate the issue.

My Current Implementation:

In the OnAppearing method, I'm resetting the DrawingView as follows:

protected override void OnAppearing()
{
    try
    {
        vm = this.BindingContext as AppointmentDetailsViewModel;
        if (vm == null)
            return;

        // Clear previous drawings
        caregiverDrawBoard.Clear();

        if (drawingView != null)
            drawingView.Lines.Clear();

        // Recreate DrawingView
        drawingView = new DrawingView
        {
            BackgroundColor = Color.FromArgb("#ebe9e9"),
            LineColor = vm.ProviderlineColor,
            ShouldClearOnFinish = false,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            VerticalOptions = LayoutOptions.FillAndExpand,
            HeightRequest = 113,
            LineWidth = 2,
            Margin = new Thickness(10, 0, 10, 0),
            IsVisible = vm.ProviderSignPadVsible,
            IsMultiLineModeEnabled = true,
            IsEnabled = vm.ProviderSignatureIsEnable,
            Background = Color.FromArgb("#ebe9e9")
        };

        drawingView.SetBinding(DrawingView.LineColorProperty, "ProviderlineColor");
        drawingView.SetBinding(DrawingView.IsEnabledProperty, "ProviderSignatureIsEnable");
        drawingView.SetBinding(DrawingView.IsVisibleProperty, "ProviderSignPadVsible");
        drawingView.DrawingLineCompleted += DrawBoard_DrawingLineCompleted;

        na.SetColumn(drawingView, 0);
        na.Children.Add(drawingView);
    }
    catch (Exception ex)
    {
        // Handle exception
    }
}

Issue Observed:

When the user draws near the borders of the DrawingView, and then navigates away from the page and returns, the lines are cleared as expected, but some small pixels remain at the edges. This issue occurs despite clearing the Lines collection and recreating the DrawingView in the OnAppearing method.

Request:

Could you please provide guidance or a solution to ensure that the DrawingView is fully cleared, including these border pixels?

Screenshot 2024-09-03 at 5.22.10 PM

I'm not convinced this is solving the issue but the obvious issue that I see you have introduced is that you aren't removing drawingView from na.Children. If you put that inside your if (drawingView != null) statement then you probably won't see the issue. It should look something like:

if (drawingView != null)
{
    drawingView.Lines.Clear();
    na.Children.Remove(drawingView);
}

Currently it looks like it is working because you are just putting another DrawingView on top of the existing one(s).

And the reason why I don't believe your solution solves your problem is because you still see these lines which means it isn't clearing the lines as you originally suggested. If you follow the workaround that I provided it does solve your original issue.

I have encountered similar Issue But as I am using prism for navigation is there any workaround that would help me

How are your pages registered in Prism? Transients/singletons etc?

I use prism to, i register pages with RegisterForNavigation, inside the register is Transients.

This issue is currently when the same instance is being rendered between unloading of the DrawingView. If you can't control the lifetime of the page and therefore the view I am not sure there is a workaround until this issue is fixed sadly