My UI did not response for orientation change - xamarin

I am developing a native mobile app for all platforms. I have created my own theme content page. Then after deployment on android when I make phone landscape it did not respond. what's the reason here.
Here is my base content page.
public abstract class BaseContentPage : ContentPage
{
public readonly BaseViewModel BaseViewModel;
protected bool _isNavigated = false;
public BaseContentPage(BaseViewModel baseViewModel)
{
BaseViewModel = baseViewModel;
}
public abstract void Navigate(SelectedItemChangedEventArgs e);
protected abstract override void OnAppearing();
protected override void OnDisappearing()
{
_isNavigated = true;
}
public BaseContentPage()
{
}
}
here Xaml
<views:BaseContentPage
xmlns:views="clr-namespace:DipsDemoXaml.Views"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Resource="clr-namespace:DipsDemoXaml.Resources"
x:Class="DipsDemoXaml.Views.WardListPage" Title="{x:Static Resource:AppResources.WardListPageTitle}">
<StackLayout BackgroundColor="{StaticResource DefaultBackgroundColor}" Orientation="Vertical" x:Name="s1">
I even try this also in code behind constructor I call size changed and create a method called Wardpagesizechanged.
public WardListPage(WardListPageViewModel wardListViewModel) : base(wardListViewModel)
{
InitializeComponent();
this.SizeChanged += wardpagesizechanged;
}
Wardpagesizechanged method
private void wardpagesizechanged(object sender, EventArgs e)
{
if(this.Width> this.Height)
{
s1.Orientation = StackOrientation.Horizontal;
}
else
{
s1.Orientation = StackOrientation.Vertical;
}
}
what is the problem here, I am clueless

Related

How can we assign Application.Current to BindingContext

Iam very much new to xamarin and wondering about how BindingContext is used.
I was going through a tutorial wherein they used BindingContext = Application.Current
according to the docs Application.Current should return Application.
so how can this above statement work?
Firstly, create one property in APp.cs, implement interface INotifyPropertyChanged.
public partial class App : Application, INotifyPropertyChanged
{
private string _str;
public string str
{
get { return _str; }
set
{
_str = value;
RaisePropertyChanged("str");
}
}
public App()
{
InitializeComponent();
str = "this is test";
MainPage = new NavigationPage(new simplecontrol.Page26());
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
Then binding Application.Current for ContentPage BindingContext.
<ContentPage.Content>
<StackLayout>
<!--<local:View2 Items="{Binding modelas}" />-->
<Label
HorizontalOptions="CenterAndExpand"
Text="{Binding str}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
this.BindingContext = Application.Current;

Pass OnAppearing to a ViewModel in Xamarin Forms MVVM?

I have business logic that loops around and does waits and other things. Currently this is in the code behind.
From what I have been able to read this is the wrong place and I should be placing this in the viewModel (correct me if wrong). If that's the case then should I have an OnAppearing method in my VM and if so how should I pass the OnAppearing to the View Model?
Currently my page OnAppearing looks like this:
protected async override void OnAppearing()
{
base.OnAppearing();
Title = Settings.mode.Text() + " Deck";
vm.LearnViewVisible = Settings.mode.IsLearn();
vm.PracticeViewVisible = Settings.mode.IsPractice();
vm.QuizViewVisible = Settings.mode.IsQuiz();
vm.QuizStartViewVisible = false;
If I am to be moving most of the business logic to the ViewModel then would that mean that all of this would move to an OnAppearing() method I create in the ViewModel?
Other way is using Behaviors.Forms from David Britch
...
<ContentPage.Behaviors>
<behaviors:EventHandlerBehavior EventName="Appearing">
<behaviors:InvokeCommandAction Command="{Binding PageAppearingCommand}" />
</behaviors:EventHandlerBehavior>
<behaviors:EventHandlerBehavior EventName="Disappearing">
<behaviors:InvokeCommandAction Command="{Binding PageDisappearingCommand}" />
</behaviors:EventHandlerBehavior>
</ContentPage.Behaviors>
...
Original
Or Xamarin Community Toolkit EventToCommandBehavior
<ContentPage.Behaviors>
<xct:EventToCommandBehavior
EventName="Appearing"
Command="{Binding PageAppearingCommand}" />
<xct:EventToCommandBehavior
EventName="Disappearing"
Command="{Binding PageDisappearingCommand}" />
</ContentPage.Behaviors>
Related Question: EventHandlerBehavior vs EventToCommandBehavior
This is how i link my Viewmodel. I would recommend setting up a ViewModelBase with : VModelActive and VModelInactive
Code Behind:
public partial class YourClass : ContentPage
{
ViewModelClass viewModelClass;
public YourClass()
{
InitializeComponent();
viewModelClass = new ViewModelClass();
this.BindingContext = viewModelClass;
}
protected override void OnAppearing()
{
base.OnAppearing();
viewModelClass.VModelActive(this, EventArgs.Empty);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
viewModelClass.VModelInactive(this, EventArgs.Empty);
}
}
View Model
public override void VModelActive(Page sender, EventArgs eventArgs)
{
base.VModelActive(sender, eventArgs);
//your code
}
public override void VModelInactive(Page sender, EventArgs eventArgs)
{
base.VModelInactive(sender, eventArgs);
//your code
}
I prefer a pattern I first encountered in some Realm sample code.
A ViewModel base provides empty overrideable OnAppearing/Disappearing
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(field, value))
{
return false;
}
field = value;
OnPropertyChanged(propertyName);
return true;
}
internal virtual void OnAppearing() { }
internal virtual void OnDisappearing() { }
}
User classes descend from a base that conditionally invokes the VM.
public class BasePage : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();
(BindingContext as BaseViewModel)?.OnAppearing();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
(BindingContext as BaseViewModel)?.OnDisappearing();
}
}
// used as
public class JournalEntryDetailsViewModel : BaseViewModel
Warning: if you change the base class like this you need to use it in the XAML - use a scoped version of BasePage instead of the <ContentPage top element.
Otherwise you will get an error [CS0263] Partial declarations of 'JournalEntriesPage' must not specify different base classes
<?xml version="1.0" encoding="UTF-8"?>
<v:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:v="clr-namespace:QuickJournal.Views"
x:Class="QuickJournal.Views.JournalEntriesPage"
Title="Journal"
x:Name="page">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Command="{Binding AddEntryCommand}" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
Here is example from my solution
public partial class TaskDetailsPage : MvvmContentPage
{
private readonly TaskDetailsViewModel _model;
public TaskDetailsPage()
{
InitializeComponent();
Shell.SetNavBarIsVisible(this, true);
Shell.SetTabBarIsVisible(this, false);
_model = BindingContext as TaskDetailsViewModel;
}
protected override string NavigationRoute => UniqeCodes.Routes.TaskDetailsPage;
protected override void OnAppearing()
{
_model.Init();
}
}

Xamarin Forms Button Command doesn't fire after adding button effect

I have a button like this:
<Button Margin="0,20,0,0" Command="{Binding OnSkip}" BackgroundColor="{StaticResource Primary}" CornerRadius="2"
Text="Terms and Conditions of Use" VerticalOptions="End" TextColor="White">
<Button.Effects>
<effects1:ButtonClickEffect></effects1:ButtonClickEffect>
</Button.Effects>
</Button>
Upon adding the button effect inside the button, the 'OnSkip' command no longer fires and I'm not sure why.
The button click effect code is implemented as follows:
public class AndroidButtonClickEffect : PlatformEffect
{
protected override void OnAttached()
{
this.Control.Touch += this.Control_Touch;
}
private void Control_Touch(object sender, Android.Views.View.TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
this.SetColor(Android.Graphics.Color.Blue);
}
else if (e.Event.Action == MotionEventActions.Up)
{
this.SetColor(Android.Graphics.Color.LightBlue);
}
}
private void SetColor(Android.Graphics.Color color)
{
this.Control.SetBackgroundColor(color);
}
protected override void OnDetached()
{
this.Control.Touch -= this.Control_Touch;
}
}
Removing the button effect causes the command to fire again. Why does the button effect interfere with the command firing? Is there a way I can get the effect to invoke the desired command (generically so I can reuse the effect)?
Thanks.
In the main project, I added the following class, which binds the Command:
public class ButtonClickEffect : RoutingEffect
{
public ButtonClickEffect() : base("Framework.ButtonClickEffect") { }
public static readonly BindableProperty CommandProperty =
BindableProperty.Create("Command", typeof(ICommand), typeof(ButtonClickEffect));
public static ICommand GetCommand(BindableObject view)
{
return (ICommand)view.GetValue(CommandProperty);
}
public static void SetCommand(BindableObject view, ICommand value)
{
view.SetValue(CommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.CreateAttached("CommandParameter", typeof(object),
typeof(ButtonClickEffect), (object)null);
public static object GetCommandParameter(BindableObject view)
{
return view.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(BindableObject view, object value)
{
view.SetValue(CommandParameterProperty, value);
}
}
The Android implementation was implemented as follows:
[assembly:ResolutionGroupName("Framework")]
[assembly:ExportEffect(typeof(AndroidButtonClickEffect), "ButtonClickEffect")]
namespace Framework.Droid.Effects
{
public class AndroidButtonClickEffect : PlatformEffect
{
protected override void OnAttached()
{
Control.Touch += Control_Touch;
}
private void Control_Touch(object sender, Android.Views.View.TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
SetColor(Color.LightBlue);
}
else if (e.Event.Action == MotionEventActions.Up)
{
SetColor(Color.Blue);
}
var command = ButtonClickEffect.GetCommand(Element);
command?.Execute(ButtonClickEffect.GetCommandParameter(Element));
}
private void SetColor(Color color)
{
Control.SetBackgroundColor(color);
}
protected override void OnDetached()
{
Control.Touch -= Control_Touch;
}
}
}
I then removed the 'Command' property from my button and replaced it as follows:
<Button Margin="0,20,0,0" BackgroundColor="{StaticResource Primary}" CornerRadius="2"
Text="Terms and Conditions of Use" VerticalOptions="End" TextColor="White"
effects1:ButtonClickEffect.Command="{Binding OnSkip}" effects1:ButtonClickEffect.CommandParameter="{Binding .}">
<Button.Effects>
<effects1:ButtonClickEffect></effects1:ButtonClickEffect>
</Button.Effects>
</Button>
In all honesty, the command binding is a lot more awkward now (all this code just to get a simple button effect), but the important thing is that it now works. Now I need to work out how implement for iOS.
Credit from here for the answer and whoever posted this URL as an answer (it got deleted).

Xamarin forms - How do I set font for toolbaritems

I have a toolbar in my mainpage and would like to set the font for each toolbaritem (so I can set custom fonts or normal fonts). So far I have been trying to get this done by implementing my own effect and this code works for labels but not for toolbaritems.
Whenever I run this code the effects gets added to the toolbaritem, but the effect code in android doesn't get called.
Does anyone know why I am unable to set fonts for toolbaritems with effects?
GitHub: https://github.com/jashan07/CustomEffectTest
Edit:
Brad Dixon suggested using TitleView which allows me to place labels in my navigationbar. As mentioned before the effect works for every control except toolbaritems.
This is a workaround which works for now (don't know about the limits or effects this will have) but I am still wondering why this isn't working for toolbaritems.
(TitleView was introduced in Xamarin.Forms V3.2)
My effect class:
public static class ChangeFontEffect
{
public static readonly BindableProperty FontProperty = BindableProperty.CreateAttached("Font",
typeof(string),
typeof(ChangeToolbarFontEffect),
null, propertyChanged: OnFontChanged);
private static void OnFontChanged(BindableObject bindable, object oldValue, object newValue)
{
if(bindable is Label labelControl)
{
if (!labelControl.Effects.Any((e) => e is ChangeToolbarFontEffect))
labelControl.Effects.Add(new ChangeToolbarFontEffect());
}
else if(bindable is ToolbarItem toolbarItem)
{
if (bindable is ToolbarItem)
if (!toolbarItem.Effects.Any((e) => e is ChangeToolbarFontEffect))
toolbarItem.Effects.Add(new ChangeToolbarFontEffect());
}
return;
}
public static string GetFont(BindableObject view)
{
return (string)view.GetValue(FontProperty);
}
public static void SetFont(BindableObject view, string value)
{
view.SetValue(FontProperty, value);
}
class ChangeToolbarFontEffect : RoutingEffect
{
public ChangeToolbarFontEffect() : base("CustomEffectTest.ChangeToolbarFontEffect") { }
}
}
XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:effects="clr-namespace:CustomEffectTest.Effects"
x:Class="CustomEffectTest.MainPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="normal text"></ToolbarItem>
<ToolbarItem Text="ﭗ" effects:ChangeFontEffect.Font="materialdesignicons-webfont.ttf"></ToolbarItem>
</ContentPage.ToolbarItems>
Android
[assembly: ResolutionGroupName("bottomNavTest")]
[assembly: ExportEffect(typeof(ChangeToolbarFontEffect), "ChangeToolbarFontEffect")]
namespace bottomNavTest.Droid
{
public class ChangeToolbarFontEffect : PlatformEffect
{
TextView control;
protected override void OnAttached()
{
try
{
control = Control as TextView;
Typeface font = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, ChangeFontEffect.GetTextFont(Element));
control.Typeface = font;
}
catch(Exception e)
{
}
}
protected override void OnDetached()
{
}
protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)
{
if (args.PropertyName == ChangeFontEffect.TextFontProperty.PropertyName)
{
var val = ChangeFontEffect.GetTextFont(Element);
if (val != null)
{
Typeface font = Typeface.CreateFromAsset(Forms.Context.ApplicationContext.Assets, ChangeFontEffect.GetTextFont(Element));
control.Typeface = font;
}
}
}
}
}

How to update progressbar from customwebview renderer in xamarin forms for android?

I'm currently developing an app in Xamarin Forms with an Android background so I wanted to create an Android app first and an iOS app later.
I'm new to Xamarin Forms and I'm struggling on how to update a ProgressBar from a WebView using a custom renderer for the WebView.
In Android, you can do something like this, with the ProgressBar and WebView that are in the main_layout.xml
public class MainActivity extends Activity {
private ProgressBar progressBar;
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
progressBar = (ProgressBar) findViewById(R.id.progress);
webView = (AdvancedWebView) findViewById(R.id.webView);
// webview initialisation
webView.setWebChromeClient(new WebChromeClient(){
#Override
public void onProgressChanged(WebView view, int newProgress) {
// update progressbar progress
progressBar.setProgress(newProgress);
}
});
webView.setWebViewClient(new WebViewClient(this) {
#Override
public void onPageFinished(WebView view, String url) {
// hide progressbar when it's done
progressBar.setVisibility(View.GONE);
}
});
}
}
In Xamarin Forms I have this layout in MainPage.xaml in the shared project
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="False">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ProgressBar
x:Name="progress"
Grid.Row="3"
HorizontalOptions="FillAndExpand"
Progress="0"
VerticalOptions="Center" />
<WebView
x:Name="webview"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="0"
HorizontalOptions="FillAndExpand"
IsVisible="False"
Source="https://google.com"
VerticalOptions="FillAndExpand" />
</Grid>
public partial class App : Application
{
public App ()
{
InitializeComponent();
MainPage = new MainPage();
}
}
And this custom WebView render for android in the android project
[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebviewRenderer))]
namespace MyApp.Droid
{
public class CustomWebviewRenderer: WebViewRenderer
{
private readonly Context context;
public CustomWebviewRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
var formsWebView = e.NewElement as Xamarin.Forms.WebView;
if (formsWebView != null)
{
var webView = Control as Android.Webkit.WebView;
webView.SetWebViewClient(new CustomWebViewClient());
webView.SetWebChromeClient(new CustomWebChromeClient());
webView.Settings.LoadWithOverviewMode = true;
webView.Settings.UseWideViewPort = true;
SetNativeControl(webView);
}
}
private class ScoritoWebChromeClient : WebChromeClient
{
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
// how to update progressbar progress?
base.OnProgressChanged(view, newProgress);
}
}
private class CustomWebViewClient : WebViewClient
{
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
// how to hide progressbar?
base.OnPageFinished(view, url);
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
return base.ShouldOverrideUrlLoading(view, request);
}
}
}
}
How can I update the ProgressBar that I have in my MainPage.xaml from the OnPageFinished in the CustomWebviewRenderer class to show the webpage has finished loading? Should I use the MainActivity.cs in the Android project?
Can someone point me in the right direction on how to solve this?
Update:
Create a custom WebView class in your PCL:
public class CustomWebView: WebView
{
public static readonly BindableProperty ActionProperty = BindableProperty.Create(propertyName: nameof(Action), returnType: typeof(Action),
declaringType: typeof(CustomWebView),
defaultValue: null,
defaultBindingMode: BindingMode.OneWay);
public void InvokeAction()
{
if (Action == null || data == null)
{
return;
}
Action.Invoke();
}
public Action Action
{
get { return (Action)GetValue(ActionProperty); }
set { SetValue(ActionProperty, value); }
}
}
Use this CustomWebView with its namespace like this:
<namespace:CustomWebView x:Name="webview"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="0"
HorizontalOptions="FillAndExpand"
IsVisible="False"
Source="https://google.com"
VerticalOptions="FillAndExpand"/>
But if you still insist to use your renderer what you can do is update the progress bar using the element property and get a callback or change a property something like below:
[assembly: ExportRenderer(typeof(CustomWebView), typeof(CustomWebviewRenderer))]
namespace MyApp.Droid
{
public class CustomWebviewRenderer: WebViewRenderer
{
private readonly Context context;
public CustomWebviewRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
var formsWebView = e.NewElement as Xamarin.Forms.WebView;
if (formsWebView != null)
{
var webView = Control as Android.Webkit.WebView;
webView.SetWebViewClient(new CustomWebViewClient());
webView.SetWebChromeClient(new CustomWebChromeClient());
webView.Settings.LoadWithOverviewMode = true;
webView.Settings.UseWideViewPort = true;
SetNativeControl(webView);
}
}
private class ScoritoWebChromeClient : WebChromeClient
{
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
// how to update progressbar progress?
base.OnProgressChanged(view, newProgress);
}
}
private class CustomWebViewClient : WebViewClient
{
private _webView;
public CustomWebViewClient (Xamarin.Forms.WebView webView)
{
_webView=webView;
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
// how to hide progressbar?
_webView.InvokeAction();
base.OnPageFinished(view, url);
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
return base.ShouldOverrideUrlLoading(view, request);
}
}
}
}
Note that this is just an example and can be changed as per your requirements.
In case it doesn't work or you have queries revert!
So after 10 days I have finally found a solution to this by using bindableproperties...
So I've added a CustomWebView in the PCL
public class CustomWebView : WebView
{
public static readonly BindableProperty PageProgressProperty = BindableProperty.Create(
nameof(PageProgress),
typeof(int),
typeof(CustomWebView),
default(int));
public int PageProgress
{
get => (int)GetValue(PageProgressProperty);
set => SetValue(PageProgressProperty, value);
}
}
Also a CustomProgressBar in the PCL
public class CustomProgressBar : ProgressBar
{
public CustomProgressBar()
{
}
public static readonly BindableProperty CurrentProgressProperty =
BindableProperty.Create(
nameof(CurrentProgress),
typeof(int),
typeof(CustomProgressBar),
default(int),
propertyChanged: CustomProgressPropertyChanged);
private static void CustomProgressPropertyChanged(BindableObject sender, object oldValue, object newValue)
{
CustomProgressBar thisProgressBar = (CustomProgressBar)sender;
double percent = Convert.ToDouble(newValue) / 100;
thisProgressBar.ProgressTo(percent, 100, Easing.Linear);
}
public int CurrentProgress
{
get => (int)GetValue(CurrentProgressProperty);
set => SetValue(CurrentProgressProperty, value);
}
}
And now I can update the progress from my CustomWebviewRenderer as follows
public class CustomWebviewRenderer : WebViewRenderer
{
private readonly Context context;
public CustomWebviewRenderer(Context context) : base(context)
{
this.context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
var formsWebView = e.NewElement as WebView;
if (e.OldElement == null)
{
var x = Control;
var webView = Control as Android.Webkit.WebView;
webView.SetWebViewClient(new CustomWebViewClient(Element));
webView.SetWebChromeClient(new CustomWebChromeClient(Element));
webView.Settings.LoadWithOverviewMode = true;
SetNativeControl(webView);
}
}
private class CustomWebViewClient : WebViewClient
{
private readonly WebView formsWebView;
public CustomWebViewClient(WebView webView)
{
formsWebView = webView;
}
public override void OnReceivedError(Android.Webkit.WebView view, IWebResourceRequest request, WebResourceError error)
{
base.OnReceivedError(view, request, error);
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
{
return base.ShouldOverrideUrlLoading(view, request);
}
}
private class CustomWebChromeClient : WebChromeClient
{
private WebView element;
public CustomWebChromeClient(WebView element)
{
this.element = element;
}
public override void OnProgressChanged(Android.Webkit.WebView view, int newProgress)
{
base.OnProgressChanged(view, newProgress);
element.SetValueFromRenderer(CustomWebView.PageProgressProperty, newProgress);
}
}
}
And finally in the .xaml views these properties: BindingContext and CurrentProgress. The BindingContext is set to the webview, and the CurrentProgress is a custom property bound to PageProgress which is a property that lives in the CustomWebView
<local:CustomProgressBar
x:Name="progress"
Grid.Row="3"
BindingContext="{x:Reference webview}"
CurrentProgress="{Binding Path=PageProgress}"
HorizontalOptions="FillAndExpand"
ProgressColor="#FFB800"
VerticalOptions="Center" />
<local:CustomWebView
x:Name="webview"
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="0"
HorizontalOptions="FillAndExpand"
IsVisible="False"
VerticalOptions="FillAndExpand" />
So yeah, took a while to figure this out...

Resources