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
});
Related
I am using Shiny for xamarin to schedule background jobs.
I am trying to call my startup class from my mainApplication class but AndroidShinyHost is not available. My Target is Android 10.
I used the following sample
https://github.com/shinyorg/samples/tree/main/Jobs
MainApplication.CS
using System;
using Shiny;
using Android.App;
using Android.Runtime;
namespace Inventory.Droid
{
[Application]
public class MainApplication : Application
{
public MainApplication(IntPtr handle, JniHandleOwnership ownerShip) : base(handle, ownerShip)
{
}
public override void OnCreate()
{
base.OnCreate();
Shiny.AndroidShinyHost.Init(this, new Startup()); //Not available
}
}
}
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!
I have an activity, and three fragments are called from it. Now, I want to use Back Press method to come back to the previous fragment or screen in Xamarin.Android? How, can I achieve this??
This will do the job:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using SupportTolbar = Android.Support.V7.Widget.Toolbar;
using Android.Support.V7.App;
using Android.Support.V4.Widget;
using Android.Graphics;
using SupportFragment = Android.Support.V4.App.Fragment;
using Android.Content.PM;
using Android.Graphics.Drawables;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
namespace App
{
[Activity(Label = "", Theme = "#style/MyTheme", ScreenOrientation = ScreenOrientation.Portrait)]
public class HomeActivity : AppCompatActivity
{
//Views that switch the fragments
public ImageView _viewTab1;
public ImageView _viewTab2;
public ImageView _viewTab3;
//fragmentContainer
private FrameLayout _frameLayoutFragmentContainer;
//fragments
public SupportFragment _currentFragment;
public SupportFragment _customFragment1;
public SupportFragment _customFragment2;
public SupportFragment _customFragment3;
private Stack<SupportFragment> _StackFragment;
protected async override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
_frameLayoutFragmentContainer = FindViewById<FrameLayout>(Resource.Id.frameContainer);
//initialize views that switch fragments
_viewTab1 = FindViewById<ImageView>(Resource.Id.viewTab1);
_viewTab2 = FindViewById<ImageView>(Resource.Id.viewTab2);
_viewTab3 = FindViewById<ImageView>(Resource.Id.viewTab3);
//catch events on button click what ever is the thing that switches the fragments
_viewTab1.SetOnClickListener(new TabOnClickListener(this));
_viewTab2.SetOnClickListener(new TabOnClickListener(this));
_viewTab3.SetOnClickListener(new TabOnClickListener(this));
//create fragments
_customFragment1 = new Fragment1();
_customFragment3 = new Fragment2();
_customFragment2 = new Fragment3();
_currentFragment = _customFragment1;
_StackFragment = new Stack<SupportFragment>();
var trans = SupportFragmentManager.BeginTransaction();
trans.Add(Resource.Id.frameContainer, _customFragment1, "First Fragment");
trans.Commit();
}
public override void OnBackPressed()
{
base.OnBackPressed();
}
public void ReplaceFragment(SupportFragment fragment) {
if (fragment.IsVisible)
return;
var trans = SupportFragmentManager.BeginTransaction();
trans.Replace(Resource.Id.frameContainer, fragment);
trans.AddToBackStack(null);
trans.Commit();
_currentFragment = fragment;
}
}
public class TabOnClickListener : Java.Lang.Object, View.IOnClickListener
{
private HomeActivity homeActivity;
public TabOnClickListener(HomeActivity homeActivity)
{
this.homeActivity = homeActivity;
}
public void OnClick(View v)
{
switch (v.Id)
{
case Resource.Id.viewTab1:
homeActivity.ReplaceFragment(homeActivity._customFragment1);
break;
case Resource.Id.viewTab2:
homeActivity.ReplaceFragment(homeActivity._customFragment2);
break;
case Resource.Id.viewTab3:
homeActivity.ReplaceFragment(homeActivity._customFragment3);
break;
}
}
}
}
I made static delegate:
static class FragmentOnBackRouter
{
public static Action RegisteredAction { get; set; }
}
what I used here:
public override void OnBackPressed()
{
if (FragmentOnBackRouter.RegisteredAction != null)
FragmentOnBackRouter.RegisteredAction.Invoke();
else
base.OnBackPressed();
}
Then you can just assign delegate - usually assign it in your fragment's OnStart method and then pass null there in OnStop method. Simple. For functions simply use generics (type Function< T >).
I do not use activities much (2-3 per app) so it's easy and if I would have to handle it more complex, you can always create some abstract activity, inherite and override OnBackPressed there.
I am facing issue in using WebAPI action filter.
I wrote the following custom filter to perform some logic on the http request header before executing the controller method.
using System;
using System.Web.Mvc;
namespace WebApi.Filters
{
public class dataCheck : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Console.Write("custom filter called");
}
}
}
Then added filter attribute on top of controller method
[dataCheck ]
[HttpGet]
[Route("GetInfo")]
public LatestInfo GetInfo()
{
TestContext context = new TestContext ();
LatestInfo latestReleaseInfo = new LatestInfo ();
return LatestInfo ;
}
Problem:
I put debugger to my custom filter and found it is never invoked.
What is wrong here?
Am i using the right type filter for my logic?
Please advise.
You have to be sure your code uses the ActionFilterAttribute from the System.Web.Http.Filters namespace and not the one from System.Web.Mvc.
Karthik's answer is correct - there are a couple of other things in your class that you should correct.
Your override function should accept a HttpActionContext as opposed to ActionExecutingContext. Also, you should call base.OnActionExecuting(actionContext); at the end of your function
using System;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace WebApi.Filters
{
public class dataCheck : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
Console.WriteLine("debugger stop here");
// custom filter code
base.OnActionExecuting(actionContext);
}
}
}
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();
}
};
}
}
}