I'm using CefSharp Offscreen in my wpf application to generate screenshot of website. It works well but I need to check if there is some certificate errors on page and it should be configurable while application is running.
I added checkbox: "Ignore certificate errors" to form. Then I implemented MyRequestHandler for ChrominiumWebBrowser IRequestHandler.
private class MyRequestHandler : IRequestHandler
{
public event EventHandler<LoadErrorEventArgs> CertificateError;
public bool IgnoreCertErrors { get; set; }
public bool OnBeforeBrowse(IWebBrowser browser, IRequest request, bool isRedirect, bool isMainFrame)
{
return false;
}
public bool OnCertificateError(IWebBrowser browser, CefErrorCode errorCode, string requestUrl)
{
if (IgnoreCertErrors)
{
return true;
}
var handler = CertificateError;
if (handler != null)
{
handler(browser, new LoadErrorEventArgs(requestUrl, errorCode, Resources.InvalidCert));
}
return false;
}
public void OnPluginCrashed(IWebBrowser browser, string pluginPath)
{
}
public CefReturnValue OnBeforeResourceLoad(IWebBrowser browser, IRequest request, bool isMainFrame)
{
return CefReturnValue.Continue;
}
public bool GetAuthCredentials(IWebBrowser browser, bool isProxy, string host, int port, string realm, string scheme, ref string username, ref string password)
{
return true;
}
public bool OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, WebPluginInfo info)
{
return false;
}
public void OnRenderProcessTerminated(IWebBrowser browser, CefTerminationStatus status)
{
}
}
Browser Initialization:
browser = new ChromiumWebBrowser();
browser.LoadError += BrowserLoadError;
requestHandler = new MyRequestHandler() { IgnoreCertErrors = ignoreCertErrors };
requestHandler.CertificateError += BrowserLoadError;
browser.RequestHandler = requestHandler;
If I start application with IgnoreCertErrors = true it works ok and certificate errors are ignored.
If I start with IgnoreCertErrors = false it also works ok and CertificateError is raised.
Problem is when I try to change IgnoreCertErrors when application is running. When I start app with false and then switch from false --> true it is ok, but when I try change it from true to false the OnCertificateError method is not raised so I have no chance to check my parameter.
Is there caching or something? Maybe whole my approach is wrong?
Is there any possibility to reinitialize CefSharp?
Better example:
Xaml:
<Window x:Class="ceftest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Closed="Window_Closed">
<Grid>
<StackPanel>
<Button Grid.Column="1" Click="Button_Click">Generate Screenshot</Button>
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">Ignore cert errors</CheckBox>
</StackPanel>
</Grid>
</Window>
Code-behind:
public partial class MainWindow : Window
{
ChromiumWebBrowser browser;
bool ignoreCertErrors = false;
string url = ""; // some page with invalid certificate
public MainWindow()
{
Cef.Initialize(new CefSettings());
InitializeComponent();
}
private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (browser != null && browser.IsBrowserInitialized)
{
browser.Dispose();
}
browser = new ChromiumWebBrowser();
browser.LoadError += BrowserLoadError;
var requestHandler = new RequestHandler() { IgnoreCertErrors = ignoreCertErrors };
requestHandler.CertificateError += BrowserLoadError;
browser.RequestHandler = requestHandler;
System.Threading.Thread.Sleep(100);
browser.Size = new System.Drawing.Size(1000, 700);
browser.NewScreenshot += ScreenshotGenerated;
browser.Load(url);
}
private void ScreenshotGenerated(object sender, System.EventArgs e)
{
// I get here screenshot from browser.ScreenshotAsync and put it into Image control
}
private void BrowserLoadError(object sender, LoadErrorEventArgs e)
{
MessageBox.Show(e.ErrorCode + " " + e.ErrorText);
}
private void CheckBox_Checked(object sender, System.Windows.RoutedEventArgs e)
{
ignoreCertErrors = true;
}
private void CheckBox_Unchecked(object sender, System.Windows.RoutedEventArgs e)
{
ignoreCertErrors = false;
}
private void Window_Closed(object sender, EventArgs e)
{
Cef.Shutdown();
}
}
class RequestHandler : IRequestHandler
{
public event EventHandler<LoadErrorEventArgs> CertificateError;
public bool IgnoreCertErrors { get; set; }
public bool GetAuthCredentials(IWebBrowser browser, bool isProxy, string host, int port, string realm, string scheme, ref string username, ref string password)
{
return true;
}
public bool OnBeforeBrowse(IWebBrowser browser, IRequest request, bool isRedirect, bool isMainFrame)
{
return false;
}
public bool OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, WebPluginInfo info)
{
return false;
}
public CefReturnValue OnBeforeResourceLoad(IWebBrowser browser, IRequest request, bool isMainFrame)
{
return CefReturnValue.Continue;
}
public bool OnCertificateError(IWebBrowser browser, CefErrorCode errorCode, string requestUrl)
{
if (IgnoreCertErrors)
{
return true;
}
var handler = CertificateError;
if (handler != null)
{
handler(browser, new LoadErrorEventArgs(requestUrl, errorCode, "certificate error"));
}
return false;
}
public void OnPluginCrashed(IWebBrowser browser, string pluginPath)
{
}
public void OnRenderProcessTerminated(IWebBrowser browser, CefTerminationStatus status)
{
}
}
CefSharp Offscreen version 41.0.1.0
Related
WPF GeckoBrowser Not able to load url in the windows browser
I am using gecko web browser for my WPF windows application. We have a particular URL which is opening in all the system browser but not working on the windows browser.But we use any other it loads. When contacted the support team they were saying need to enable javascript. So please help me how to enable the javascript in gecko browser.
The URL load is the partial load. we are getting the background related UI for the URL. The body part of the url is not loading
I have used inbuilt .net browser but that URL is not loading in that application also.
If you want to use WebView2 in your project you can do the following:
Add nuget package Microsoft.Web.WebView2
Create WPF view with WebView2:
<wpf:WebView2 x:Name="WebView2">
<i:Interaction.Behaviors>
<behaviors:WebView2NavigateBehavior Url="{Binding Url}" RefreshInterval="{Binding RefreshInterval}" />
</i:Interaction.Behaviors>
</wpf:WebView2>
With code behind:
public partial class BrowserView : IDisposable
{
private bool disposed;
static BrowserView()
{
string loaderPath = ServiceLocator.Current.Resolve<IPathResolver>().GetWebView2LoaderDllDirectory(RuntimeInformation.ProcessArchitecture);
CoreWebView2Environment.SetLoaderDllFolderPath(loaderPath);
}
public BrowserView()
{
this.InitializeComponent();
this.InitializeAsync();
}
private async void InitializeAsync()
{
try
{
await this.WebView2.EnsureCoreWebView2Async();
}
catch (Exception ex)
{
//Log exception here
}
}
public void Dispose()
{
if (!this.disposed)
{
this.WebView2?.Dispose();
this.disposed = true;
}
}
}
Here's the code for view behavior:
public sealed class WebView2NavigateBehavior : BehaviorBase<WebView2>
{
public static readonly DependencyProperty UrlProperty =
DependencyProperty.Register(nameof(Url), typeof(WebsiteUrl), typeof(WebView2NavigateBehavior),
new PropertyMetadata(default(WebsiteUrl), PropertyChangedCallback));
public static readonly DependencyProperty RefreshIntervalProperty =
DependencyProperty.Register(nameof(RefreshInterval), typeof(TimeSpan), typeof(WebView2NavigateBehavior),
new PropertyMetadata(default(TimeSpan), PropertyChangedCallback));
private DispatcherTimer? timer;
public WebsiteUrl? Url
{
get => (WebsiteUrl?)this.GetValue(UrlProperty);
set => this.SetValue(UrlProperty, value);
}
public TimeSpan RefreshInterval
{
get => (TimeSpan)this.GetValue(RefreshIntervalProperty);
set => this.SetValue(RefreshIntervalProperty, value);
}
protected override void OnSetup()
{
base.OnSetup();
this.AssociatedObject.CoreWebView2InitializationCompleted += this.OnCoreWebView2InitializationCompleted;
}
protected override void OnCleanup()
{
base.OnCleanup();
this.StopRefresh();
}
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var behavior = (WebView2NavigateBehavior)d;
if (e.Property == UrlProperty && e.NewValue is WebsiteUrl url)
behavior.Navigate(url);
else if (e.Property == RefreshIntervalProperty && e.NewValue is TimeSpan interval)
{
behavior.StopRefresh();
if (interval != TimeSpan.Zero)
behavior.StartRefresh(interval);
}
}
private void Navigate(WebsiteUrl? url)
{
if (this.AssociatedObject.IsInitialized && this.AssociatedObject.CoreWebView2 != null && url != null)
this.AssociatedObject.CoreWebView2.Navigate(url.ToString());
}
private void OnCoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e)
{
this.AssociatedObject.CoreWebView2InitializationCompleted -= this.OnCoreWebView2InitializationCompleted;
if (e.IsSuccess)
this.Navigate(this.Url);
}
private void StartRefresh(TimeSpan interval)
{
this.timer = new DispatcherTimer { Interval = interval };
this.timer.Tick += this.OnTick;
this.timer.Start();
}
private void StopRefresh()
{
if (this.timer != null)
{
this.timer.Stop();
this.timer.Tick -= this.OnTick;
}
this.timer = null;
}
private void OnTick(object sender, EventArgs e)
{
if (this.AssociatedObject.IsInitialized)
this.AssociatedObject.CoreWebView2?.Reload();
}
}
The code for the ViewModel:
public class BrowserViewModel : ViewModelBase<BrowserViewModel>
{
private WebsiteUrl? url;
private string? title;
private TimeSpan refreshInterval;
public WebsiteUrl? Url
{
get => this.url;
set => this.SetProperty(ref this.url, value);
}
public string? Title
{
get => this.title;
set => this.SetProperty(ref this.title, value);
}
public TimeSpan RefreshInterval
{
get => this.refreshInterval;
set => this.SetProperty(ref this.refreshInterval, value);
}
}
I have a HybridWebView in my app and i need to change the uri dynamically (When the user click at some menu the uri changes), but it does not change at all... I use WebView and it works great, but when I use the HybridWebView the Uri is not changing.
This ContentView where is my HybridWebView is inside an AbsoluteLayout...
<ContentView AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
x:Name="contentView">
<local1:HybridWebView x:Name="hybridWebView"/></ContentView>
This is the code behind (Where i handle the click on the menus to change the url, every click is a different content):
public async void ChangeURL() { hybridWebView.Uri = MyUrl; }
This is my HybridWebView class:
public class HybridWebView : WebView
{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: nameof(Uri),
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
action = callback;
}
public void Cleanup()
{
action = null;
}
public void InvokeAction(string data)
{
if (action == null || data == null)
{
return;
}
action.Invoke(data);
}
public HybridWebView()
{
}
}
I just resolved it like this:
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control.Url != null)
{
var idn = new System.Globalization.IdnMapping();
var dotnetUri = new System.Uri(Element.Uri);
_url = ((HybridWebView)Element).Uri;
NSUrl nsUrl = new NSUrl(dotnetUri.Scheme, idn.GetAscii(dotnetUri.DnsSafeHost), dotnetUri.PathAndQuery);
Control.LoadRequest(new NSUrlRequest(nsUrl));
}
}
I had to add the OnElementPropertyChanged to change the url dynamically by the CustomRenderer
I thought that my bug was a Xamarin Forms issue because there was no bug in XF3.4, but it appeared after I upgraded to XF4.4.
Just to make sure, I want to show you guys the code. I have a XAML page with the loading icon:
<ActivityIndicator IsRunning="{Binding Loading}"
IsVisible="{Binding Loading}"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.2, 0.2">
<ActivityIndicator.Color>
<OnPlatform x:TypeArguments="Color" iOS="#2499CE" WinPhone="#2499CE" />
</ActivityIndicator.Color>
</ActivityIndicator>
The "Loading" boolean is binded in the page model here:
public class MyLoginWebPageModel : BasePageModel
{
private BrowserOptions _options;
private Action<BrowserResult> _trySetResult;
private BrowserResult _result = new BrowserResult() { ResultType = BrowserResultType.UserCancel };
private Boolean _navPopped = false;
public string StartUrl { get; private set; }
public bool Loading { get; set; } = false; // RIGHT HERE!!!!!!!!!!!!!!!!!!!!!!
public OidcLoginWebPageModel(ICoreDataRepository repository, ILoginProvider loginProvider, ICache cache, IEventTrace trace, IUsageTimer usageTimer, IPlatform platform)
: base(loginProvider, cache, trace, usageTimer, platform){}
public override void Init(object initData)
{
base.Init(initData);
Tuple<BrowserOptions, Action<BrowserResult>> initObject = initData as Tuple<BrowserOptions, Action<BrowserResult>>;
_options = initObject.Item1;
_trySetResult = initObject.Item2;
StartUrl = _options.StartUrl;
}
protected override void OnPageWasPopped(object sender, EventArgs e)
{
base.OnPageWasPopped(sender, e);
_trySetResult(_result);
}
internal async Task OnBrowserNavigated(object sender, WebNavigatedEventArgs e)
{
Loading = false;
if (!(sender is WebView browser))
{
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl))
{
if (uri.LocalPath.ToLowerInvariant() == "/account/logout")
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success };
if (!_navPopped)
{
_navPopped = true;
await PopPageModel();
}
}
}
}
internal async Task OnBrowserNavigating(object sender, WebNavigatingEventArgs e)
{
Loading = true;
if (!(sender is WebView browser))
{
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl) == false)
{
if (uri.AbsoluteUri.StartsWith(_options.EndUrl))
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success, Response = uri.Fragment.Substring(1) };
e.Cancel = true;
if (!_navPopped)
{
_navPopped = true;
Loading = false;
await PopPageModel();
}
}
}
}
}
Is there anything in here that would indicate a loading icon not disappearing at all?
Thanks!
edit: So this is what I'm thinking I need to do.
First I change my boolean situation
private bool Loading = false;
public bool currentlyLoading
{
get { return Loading; }
set
{
currentlyLoading = Loading;
onPropertyChanged();
}
}
Then in the same file I implement the onPropertyChanged() function to.. let the Bindable property in my xaml file know that the property has changed?
Is this a good implementation?
// Option 1
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// Option 2
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
your class (or it's base class) needs to implement INotifyPropertyChanged. Then your Loading property would look something like this
private bool loading = false;
public bool Loading
{
get { return loading; }
set
{
loading = value;
OnPropertyChanged();
}
}
Option 1 is best. But it would be good if you move your property changed logic to BasePageModel.
Try this one:
private bool _loading { get; set; }
public bool Loading { get {return _loading; } set{value = _loading } }
And in your OnBrowserNavigating:
internal async Task OnBrowserNavigating(object sender, WebNavigatingEventArgs e)
{
Loading = true;
if (!(sender is WebView browser))
{
Loading = false;
throw new Exception($"Sender is not of type WebView");
}
if (!Uri.TryCreate(e.Url, UriKind.Absolute, out Uri uri))
{
Loading = false;
throw new Exception($"Uri creation failed for: {e.Url}");
}
if (string.IsNullOrEmpty(_options.EndUrl) == false) //IF THE CONDITION OVER HERE & FOR INNER IF CONDITIONS FAILS, LOADER WASNT SET TO FALSE
{
if (uri.AbsoluteUri.StartsWith(_options.EndUrl))
{
_result = new BrowserResult() { ResultType = BrowserResultType.Success, Response = uri.Fragment.Substring(1) };
e.Cancel = true;
if (!_navPopped)
{
_navPopped = true;
Loading = false;
await PopPageModel();
}
}
}
Loading = false;
}
I want to show a progressbar while the webview gets loaded and hide the progessbar when the webview gets loaded completely.
Here is my Activity.cs
progress = new ProgressDialog(this);
progress.Indeterminate = true;
progress.SetProgressStyle(Android.App.ProgressDialogStyle.Spinner);
progress.SetMessage("Loading... Please wait...");
progress.SetCancelable(false);
progress.Show();
_faq = FindViewById<Android.Webkit.WebView>(Resource.Id.wv_FAQ);
_web.AppWebViewClients(progress);
_web.ShouldOverrideUrlLoading(_faq, _url);
_web.OnPageFinished(_faq, _url);
here is my ResourceWebView.cs
public class ResourceWebView: WebViewClient
{
Android.App.ProgressDialog progress;
public void AppWebViewClients(ProgressDialog progressBar)
{
this.progress = progressBar;
progress.Show();
}
public bool ShouldOverrideUrlLoading(WebView view, String url)
{
view.LoadUrl(url);
progress.Show();
return true;
}
public void OnPageFinished(WebView view, String url)
{
OnPageFinished(view, url);
progress.Hide();
}
}
But this code is not work for me..
Try this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view);
urlEditText = (EditText) findViewById(R.id.urlField);
webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
progress = (ProgressBar) findViewById(R.id.progressBar);
progress.setVisibility(View.GONE);
Button openUrl = (Button) findViewById(R.id.goButton);
openUrl.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
String url = urlEditText.getText().toString();
if (validateUrl(url)) {
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(url);
}
}
private boolean validateUrl(String url) {
return true;
}
});
}
private class MyWebViewClient extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
#Override
public void onPageFinished(WebView view, String url) {
progress.setVisibility(View.GONE);
WebViewActivity.this.progress.setProgress(100);
super.onPageFinished(view, url);
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
progress.setVisibility(View.VISIBLE);
WebViewActivity.this.progress.setProgress(0);
super.onPageStarted(view, url, favicon);
}
}
Reference this for more reference : http://stacktips.com/tutorials/android/progressbar-while-loading-webview
I am trying to implement SwipeRefreshLayout in a webview in Xamarin.android but the layout keeps loading infinitely only works well as a progress bar but when swiping to refresh it doesn't work. Please help me fix it.
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.gameofthrones);
myWebClient = new WebClient();
myWebView = FindViewById<WebView>(Resource.Id.webView);
myProgressBar = FindViewById<ProgressBar>(Resource.Id.progressBar);
myswipeRefreshLayout = FindViewById<SwipeRefreshLayout>(Resource.Id.refresher);
myswipeRefreshLayout.SetColorScheme(Resource.Color.Red, Resource.Color.Orange,
Resource.Color.Yellow, Resource.Color.Green,
Resource.Color.Blue, Resource.Color.Indigo,
Resource.Color.Violet);
var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
myWebView.Settings.JavaScriptEnabled = true;
myWebView.LoadUrl("http://www.google.com");
myWebView.SetWebViewClient(myWebClient);
//Toolbar will now take on default actionbar characteristics
SetSupportActionBar(toolbar);
SupportActionBar.Title = "GAME OF THRONES";
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetHomeButtonEnabled(true);
myswipeRefreshLayout.Refresh += MyswipeRefreshLayout_Refresh;
}
private void MyswipeRefreshLayout_Refresh(object sender, EventArgs e)
{
myWebClient.myOnProgressChanged += (int state) =>
{
if (state == 0)
{
(sender as SwipeRefreshLayout).Refreshing = false;
myswipeRefreshLayout.Refreshing = false;
//page loaded no progress bar visible
//myProgressBar.Visibility = ViewStates.Invisible;
}
else
{
(sender as SwipeRefreshLayout).Refreshing = true;
myswipeRefreshLayout.Refreshing = true;
//myProgressBar.Visibility = ViewStates.Visible;
}
};
}
public override bool OnKeyDown(Android.Views.Keycode keyCode, Android.Views.KeyEvent e)
{
if (keyCode == Keycode.Back && myWebView.CanGoBack())
{
myWebView.GoBack();
return true;
}
return base.OnKeyDown(keyCode, e);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
if (item.ItemId == Android.Resource.Id.Home)
Finish();
return base.OnOptionsItemSelected(item);
}
}
public class WebClient : WebViewClient
{
public delegate void ToggleProgreeBar(int state);
public ToggleProgreeBar myOnProgressChanged;
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
view.LoadUrl(url);
return true;
}
public override void OnPageStarted(WebView view, string url, Bitmap favicon)
{
if (myOnProgressChanged != null)
{
myOnProgressChanged.Invoke(1);
}
base.OnPageStarted(view, url, favicon);
}
public override void OnPageFinished(WebView view, string url)
{
if (myOnProgressChanged != null)
{
myOnProgressChanged.Invoke(0);
}
base.OnPageFinished(view, url);
}
SwipeRefreshLayout.Refresh get triggered when user down swipes. According to your requirement, when user swipes, you need to manually refresh the webview:
private void SwipeRefresh_Refresh(object sender, System.EventArgs e)
{
webview.LoadUrl(webview.Url);
}
And register myWebClient.myOnProgressChanged event inside OnCreate. So codes should looks like below:
public class MainActivity : Activity
{
WebView webview;
SwipeRefreshLayout mySwipeRefresh;
WebClient myWebClient;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
webview = FindViewById<WebView>(Resource.Id.webview);
webview.Settings.JavaScriptEnabled = true;
webview.LoadUrl("http://www.google.com");
mySwipeRefresh = FindViewById<SwipeRefreshLayout>(Resource.Id.swiperefresh);
myWebClient = new WebClient();
//register myOnProgressChanged here
myWebClient.myOnProgressChanged += (int state) =>
{
if (state == 0)
{
mySwipeRefresh.Refreshing = false;
}
else
{
mySwipeRefresh.Refreshing = true;
}
};
webview.SetWebViewClient(myWebClient);
mySwipeRefresh.Refresh += SwipeRefresh_Refresh;
}
private void SwipeRefresh_Refresh(object sender, System.EventArgs e)
{
//refresh the webview when user swipes.
webview.LoadUrl(webview.Url);
}
}