Overriding OnDisappearing in custom Renderer Xamarin. Forms - xamarin.forms

I want to call a base.Dispose() on the OnDisappearing() from my Android project in Xamarin.Forms.
I have done something like this :-
namespace Project.Mobile.Droid
{
[assembly: ExportRenderer(typeof(ItemListPage), typeof(DisposeRenderer))]
class DisposeRenderer : ViewRenderer
{
public DisposeRenderer() { }
}
}
How can I go ahead with this?
Iam new to Xamarin.Forms, so it would be a great help if someone helps me on this.

As long as your ItemListPage implements IDisposable, you could try the following :-
using System;
using DisposableControlSample;
using DisposableControlSample.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(DisposablePage), typeof(DisposablePageRenderer))]
namespace DisposableControlSample.Droid
{
public class DisposablePageRenderer : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
e.NewElement.Disappearing += (sender, args) =>
{
var disposablePage = sender as IDisposable;
if (disposablePage != null)
{
disposablePage.Dispose();
}
};
}
}
}

Related

Find when a page finished loading in xamarin.forms prism

I am trying to create an optimized Event Tracker for my Xamarin.forms prism application. I would like to know whether there is any method to find out when the page load is finished. If someone could help me, please save my time.
You can implement page loading methods for different platforms through custom renderer.
For iOS, override the viewDidLoad method, ViewDidLoad(Called after the controller's view is loaded into memory.)
[assembly:ExportRenderer (typeof(ContentPage), typeof(MyRenderer))]
namespace Demo.iOS
{
public class MyRenderer : PageRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
}
}
}
For Android, rewrite the OnAttachedToWindow method, OnAttachedToWindow(This is called when the view is attached to a window.)
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyRenderer))]
namespace Demo.Droid
{
public class MyRenderer : PageRenderer
{
public MyPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
}
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
}
}
}

Xamarin SQLite db connections issue

I am trying to connect my xamarin app with SQLite, everything seems fine but in App.xaml.cs i get the following error: System.NullReferenceException: 'Object reference not set to an instance of an object.'
This is how my App.xaml.cs page looks like:
using System;
using TestAppDemo.Services;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestAppDemo
{
public partial class App : Application
{
public App()
{
InitializeComponent();
DependencyService.Get<ISQLite>().GetConnectionWithCreateDatabase();
MainPage = new NavigationPage(new MainPage());
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
}
Can anyone help? Do I need to provide you with more information?
Thanks!

How to access ViewWillAppear/ViewDidDisappear in ViewRenderer<HybridWebView, WkWebViewRenderer>?

I'm trying to port an Android existing custom ViewRenderer to iOS.
I'm using version 4.8 of Xamarin.Forms.
Specifically, I need to match Android's OnAttachedToWindow & OnDetachedFromWindow.
The Android Code is like the following:
public partial class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
protected override void OnAttachedToWindow()
{
base.OnAttachedToWindow();
...
}
protected override void OnDetachedFromWindow()
{
base.OnDetachedFromWindow();
...
}
}
According to this link, I would need to override ViewWillAppear which is the iOS equivalent to OnAttachedToWindow.
The custom Renderer for iOS is the following:
public partial class HybridWebViewRenderer : ViewRenderer<HybridWebView, WkWebViewRenderer>, IWKScriptMessageHandler
{
}
But the overrides are not available.
How can I do that?
ViewWillAppear and ViewWillDisappear are the life cycle method of UIViewController.So you could create the custom renderer of ContentPage
in the ContentPage that contains the WebView
using Foundation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using App1;
using App1.iOS;
[assembly:ExportRenderer(typeof(MainPage),typeof(MyPageRenderer))]
namespace App1.iOS
{
public class MyPageRenderer:PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
MessagingCenter.Send<Object,UIViewController>(this,"ViewWillAppear",this); // send message when the method been called .
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
MessagingCenter.Send<Object, UIViewController>(this, "ViewWillDisappear", this);
}
}
}
in WebViewRenderer
Subscribe the message in the constructor .
MessagingCenter.Subscribe<Object, UIViewController > (this, "ViewWillDisappear",(arg,controller)=> {
// controller is the current UIViewController
});

Xamarin Forms:Prism MVVM:Android:Navigate to specific page when click on Push Notification [duplicate]

I'm new to Xamarin and Prism, so forgive me if I'm missing something obvious. I am following the example of this project in GitHub. However, I am getting the following error when running my Android project.
System.InvalidOperationException: The current type, MyApp.Abstractions.IFacebookManager, is an interface and cannot be constructed. Are you missing a type mapping?
The error is occurring in EntryPage.xaml.g.cs in the LoadFromXaml() method.
[global::Xamarin.Forms.Xaml.XamlFilePathAttribute("Views\\EntryPage.xaml")]
public partial class EntryPage : global::Xamarin.Forms.ContentPage {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Forms.Build.Tasks.XamlG", "2.0.0.0")]
private void InitializeComponent() {
// Exception thrown here!
global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(EntryPage));
}
}
This leads me to believe that I'm not using the IoC container properly, but I can't see what I'm doing differently from the example. The EntryPageViewModel's constructor takes IFacebookManager as a parameter and I understand that Unity should take care of this. I have a breakpoint on the constructor, but it's not being hit. This is a .NET Standard Xamarin solution. I would appreciate any help and guidance. Thank you!
Here's my App.xaml.cs
using MyApp.Abstractions;
using MyApp.Helpers;
using MyApp.Services;
using MyApp.ViewModels;
using MyApp.Views;
using Prism;
using Prism.Ioc;
using Prism.Unity;
using Xamarin.Forms;
namespace MyApp
{
public partial class App : PrismApplication
{
public App(IPlatformInitializer initializer = null) : base(initializer) { }
protected override void OnInitialized()
{
InitializeComponent();
ServiceResolver.Instance.Add<ICloudService, AzureCloudService>();
NavigationService.NavigateAsync("NavigationPage/EntryPage");
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<EntryPage, EntryPageViewModel>();
}
}
}
Here's my MainActivity.cs
using Android.App;
using Android.Content.PM;
using Android.OS;
using MyApp.Droid.Services;
using MyApp.Abstractions;
using Android.Content;
using Xamarin.Facebook;
using Xamarin.Forms;
using Prism;
using Prism.Ioc;
namespace MyApp.Droid
{
[Activity(Label = "MyApp", Icon = "#drawable/icon", Theme = "#style/MainTheme", Name = "com.mydomain.myapp.MainActivity", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
ICallbackManager fbCallbackManager;
AndroidLoginProvider loginProvider;
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init();
global::Xamarin.Forms.Forms.Init(this, bundle);
DependencyService.Register<IFacebookManager, FacebookManager>();
LoadApplication(new App(new AndroidInitializer()));
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
var manager = DependencyService.Get<IFacebookManager>();
if (manager != null)
{
(manager as FacebookManager)._callbackManager.OnActivityResult(requestCode, (int)resultCode, data);
}
}
}
public class AndroidInitializer : IPlatformInitializer
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
}
public class AndroidInitializer : IPlatformInitializer
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
}
}
You are mixing the Xamarin Forms Dependency Service with the one provided with Prism.Unity
Instead of calling DependencyService.Register<IFacebookManager, FacebookManager>();
You need to register it with the AndroidInitializer .
public class AndroidInitializer : IPlatformInitializer
{
public void RegisterTypes(IContainerRegistry container)
{
container.RegisterSingleton<IFacebookManager, FacebookManager>();
}
}
You can then always resolve a dependency manually by calling App.Container.Resolve inside OnActivityResult.
To complete the previous answer that helped me a lot to fix a similar issue:
with prism 7, you need to resolve a dependency via IContainerProvider as follow:
var container = (App.Current as Prism.Unity.PrismApplication).Container;
var manager = container.Resolve<IFacebookManager>();
In this case, Unity is used as the IoC "container"

Use custom renderer on only one Entry control

In my Xamarin.Forms app, I have a custom renderer:
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
namespace MyApp.Controls
{
public class CustomEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (this.Control != null)
{
Control.Style = (Windows.UI.Xaml.Style)App.Current.Resources["CustomTextBoxStyle"];
}
}
}
}
But I only want to use it on 1 of my Entry controls, not all of them. How can I accomplish this?
create a custom control MyEntry that inherits from Entry
then in your renderer, specify that it only applies to type MyEntry
[assembly: ExportRenderer(typeof(MyEntry), typeof(CustomEntryRenderer))]

Resources