0

community.

In advance, I apologize if this really has a simple solution. I have a troublesome problem, considering my skill level with Xamarin, that I need to get resolved.

The problem is it seems like Xamarin doesn't have an event/function/etc to call when a page is FULLY displayed, as in you can see everything the page is supposed to display, and then that function is called. Quick note, what does not work for me is the OnAppearing function because it fires off too early before the screen is visible.

I was attempting to decipher a solution here. In this post, a user answers with the following code.

Here is step 1):

private bool _toggleTemp;
public bool ToggleTemp
{
    get => _toggleTemp;
    set => SetProperty(ref _toggleTemp, value);
}

Step 2)

LoadingVm.ToggleTemp = true;

Step 3)

<Switch IsToggled="{Binding ToggleTemp}" Toggled="Switch_OnToggled" IsVisible="False" />

Step 4)

private async void Switch_OnToggled(object sender, ToggledEventArgs e)
{ 
    /* Your code goes here... */ 
}

First concern. I created a ViewModel file, it's inside of a folder called "ViewModels", and the user who posted the code in the link said to create a property in the view model, for some reason I'm getting an error stating "the name set property does not exist in the current context". So is it alright I swap that code out and just put the following instead? I mean it SEEMS like the same thing, right?

public bool Temp
{
    get { return _toggleTemp; }
    set { _toggleTemp = value; }
}

Second concern. I have no clue what "LoadingVm" is in his code. It doesn't come up for me. Is it because I'm missing a "using" at the top? But regardless, the whole code line was this "LoadingVm.ToggleTemp = true;", so he's just calling the function to set it to be true.

In the end, I'm ASSUMING that this will no doubt help me get the code working where I can do whatever I please AFTER the page is completely loaded, correct? I don't really see too many people disagreeing with the method the guy in the link has given, but if so, feel free to give other suggestions.

Again, please forgive me if this is a simple error. I'm still getting used to Xamarin and C# is still somewhat fresh in my mind from not having used it in a while.

Omar Moodie
  • 263
  • 3
  • 13
  • 1) it's not the same, you are not using INotifyPropertyChanged, 2) LoadingVM is just the name of his VM class – Jason Aug 25 '20 at 20:32
  • 1) I believe I tried including some form of "NotifyPropertyChanged" as the base class before. But for some reason, I must've messed up. I'll try and search what I need to include to get access to it. 2) Oh, understandable. – Omar Moodie Aug 25 '20 at 20:37
  • even if you included it in your base class, you still need to call the method in your property setter – Jason Aug 25 '20 at 20:38
  • I definitely get that. I just need to PROPERLY include it, if I wasn't clear before. A few red lines popped up the last time I tried. So I'll have at it again, and make sure I call it as the property setter. – Omar Moodie Aug 25 '20 at 20:40
  • Does my solution work for you? If yes, can you please accept it (click the ☑️ in the upper left corner of this answer ) so that we can help more people with same problem:). – nevermore Aug 27 '20 at 05:54

1 Answers1

4

You can use custom renderer of ContentPage to know if the view is fully loaded and then use MessagingCenter to notify your shared project:

In iOS:

[assembly:ExportRenderer (typeof(ContentPage), typeof(CameraPageRenderer))]
namespace App362.iOS
{
    public class CameraPageRenderer : PageRenderer
    {

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            Console.WriteLine("ViewDidAppear");

            MessagingCenter.Send<object>(new object(), "ViewLoaded");

        }

    }     
}

In Android:

[assembly: ExportRenderer(typeof(ContentPage), typeof(CameraPageRenderer))]
namespace App362.Droid
{
    [Obsolete]
    public class CameraPageRenderer : PageRenderer{

        protected override void OnAttachedToWindow()
        {
            base.OnAttachedToWindow();

            Console.WriteLine("OnAttachedToWindow");

            MessagingCenter.Send<object>(new object(), "ViewLoaded");
        }
    }

}

In Shared project:

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

    protected override void OnAppearing()
    {
        base.OnAppearing();
        Console.WriteLine("OnAppearing");

        MessagingCenter.Subscribe<object>(new object(), "ViewLoaded", (sender) =>
        {
            // Do something whenever the "ViewLoaded" message is received
            Console.WriteLine("Do something whenever the ViewLoaded message is received");
        });
    }
}
nevermore
  • 15,432
  • 1
  • 12
  • 30
  • 1
    A problem with this implementation is that anytime a ContentPage triggers OnAppearing it will trigger ViewLoaded via MessagingCenter to be sent regardless of the Page as it applies to all so ViewLoaded wouldn't be confined to the MainPage – metoyou Jan 05 '21 at 20:00
  • Instead of using MessagingCenter, write a `public class BasePage : ContentPage`, and use that as the base for project's ContentPages. In `BasePage`, declare `public Action NextAppearAction;` Then in each custom renderer, where this answer publishes a message, instead do `var page = Element as YourProject.BasePage; if (page.NextAppearAction != null) { page.NextAppearAction(); page.NextAppearAction = null; }` This fires `NextAppearAction` once. In a page's code behind, set `NextAppearAction` to the desired action. – ToolmakerSteve Apr 06 '22 at 17:17