Using WebViewOnNavigated with custom Renderer [Xamarin forms] - xamarin.forms

I'm using a custom WebViewRenderer in my Xamarin Forms android project that looks like this:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(HybridWebViewRenderer))]
namespace ClotureSiadForms.Droid.Renderer
{
internal class HybridWebViewRenderer : WebViewRenderer
{
public HybridWebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.Settings.JavaScriptEnabled = true;
Control.Settings.DomStorageEnabled = true;
Control.Settings.SavePassword = true;
}
}
}
}
I checked that it is well used, however passwords are still not saved. When I write login and password on the webpage, it asks is Google should save them, I press "yes" but next time sign in data is not proposed, what should I check ?

Please try the OnElementChanged method like below.
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Settings.JavaScriptEnabled = true ;
Control.Settings.DomStorageEnabled = true ;
Control.Settings.SavePassword = true;
}
}

Related

Xamarin Forms Switch Controller width change

How can i change the switch width in xamarin forms switch?
tried with adding render class to android but couldn't found a way to do that.
-------this is the Render class in android
[assembly: ExportRenderer(typeof(ExtendedSwitch), typeof(ExtendedSwitchRenderer))]
namespace Common.Droid.Renderers
{
public class ExtendedSwitchRenderer : SwitchRenderer
{
public ExtendedSwitchRenderer(Context context)
: base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement != null)
{
var element = (ExtendedSwitch) e.NewElement;
Control.TextOn = element.YesText ?? string.Empty;
Control.TextOff = element.NoText ?? string.Empty;
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
Control.SwitchMinWidth = 300;
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == ExtendedSwitch.YesTextProperty.PropertyName ||
e.PropertyName == ExtendedSwitch.NoTextProperty.PropertyName)
{
var element = (ExtendedSwitch) Element;
Control.TextOn = element.YesText ?? string.Empty;
Control.TextOff = element.NoText ?? string.Empty;
}
Control.SwitchMinWidth = 300;
}
}
}

Using Global.asax to set/check session variable and redirect (for user testing)

I would like to add very simple, temporary security to my site.
I made a page at Home/UnderConstruction where people testing the site can enter a hard-coded password which will then set the "underconstruction" session variable to "false".
This is what I have so far, but it results in too many redirects:
protected void Session_Start(Object sender, EventArgs e)
{
HttpContext.Current.Session["underconstruction"] = "true";
}
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
var underconstruction = HttpContext.Current.Session["underconstruction"];
if (underconstruction != null)
{
string oc = underconstruction.ToString();
if (oc != "false") Response.Redirect("~/Home/UnderConstruction");
}
}
}
Is this close to what I would need to do?
Here is the code we got to work:
Controller Code for UnderConstruction View
public ViewResult UnderConstruction()
{
return View();
}
[HttpPost]
public ActionResult UnderConstruction(string ocp)
{
if (ocp == "mypassword")
{
Session["underconstruction"] = "false";
return RedirectToAction("Index", "Home");
}
else
{
Session["beingredirected"] = "false";
return View();
}
}
Global.Asax
protected void Session_Start(Object sender, EventArgs e)
{
HttpContext.Current.Session["underconstruction"] = "true";
HttpContext.Current.Session["beingredirected"] = "false";
}
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
bool uc = false;
var underconstruction = HttpContext.Current.Session["underconstruction"];
if (underconstruction != null)
{
uc = Boolean.Parse(underconstruction.ToString());
}
bool redirected = false;
var beingredirected = HttpContext.Current.Session["beingredirected"];
if (beingredirected != null)
{
redirected = Boolean.Parse(beingredirected.ToString());
}
if (uc && !redirected)
{
if (Request.HttpMethod == "GET")
{
HttpContext.Current.Session["beingredirected"] = "true";
Response.Redirect("~/Home/UnderConstruction");
}
else if (Request.HttpMethod == "POST")
{
}
}
HttpContext.Current.Session["beingredirected"] = "false";
}
}
Is ~/Home/UnderConstruction in a different website? If not, wont it always redirect because oc will always be true? ie - do you also need to add a check for the page you're requesting so you can bypass the redirect if already going to the UnderConstruction page?
UPDATE
Not sure if checking the page name is a great idea, but something like this might work:
protected void Session_Start(Object sender, EventArgs e)
{
HttpContext.Current.Session["underconstruction"] = "true";
HttpContext.Current.Session["beingredirected"] = "false";
}
protected void Application_AcquireRequestState(Object sender, EventArgs e)
{
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
bool uc = false;
var underconstruction = HttpContext.Current.Session["underconstruction"];
if (underconstruction != null)
{
uc = Boolean.Parse(underconstruction);
}
bool redirected = false;
var beingredirected = HttpContext.Current.Session["beingredirected"];
if (beingredirected != null)
{
redirected = Boolean.Parse(beingredirected);
}
if (uc && !redirected)
{
HttpContext.Current.Session["beingredirected"] = "true";
Response.Redirect("~/Home/UnderConstruction");
}
HttpContext.Current.Session["beingredirected"] = "false";
}
}
Note that I would clean that up, that example was to just give the general idea.
UPDATE
If you want to use roles as mentioned in the comments, then this article from ScottGu's Blog may help. Its a little more complicated, but has the added benefit of not introducing temporary code as the above solution will

Find all textbox control in a page

i am trying to use http Module to disable textbox of each page. Here is my sample coding
public void context_OnPreRequestHandlerExecute(object sender, EventArgs args)
{
try
{
HttpApplication app = sender as HttpApplication;
if (app != null)
{
Page page = app.Context.Handler as Page;
if (page != null)
{
page.PreRender += OnPreRender;
page.PreLoad += onPreLoad;
}
}
}
catch (Exception ex)
{
throw new ApplicationException(ex.Message);
}
}
public void OnPreRender(object sender, EventArgs args)
{
Page page = sender as Page;
if (page.IsCrossPagePostBack)
{
DisableAllTextBoxes(page);
}
}
private static void DisableAllTextBoxes(Control parent)
{
foreach (Control c in parent.Controls)
{
var tb = c as Button;
if (tb != null)
{
tb.Enabled = false;
}
DisableAllTextBoxes(c);
}
}
This coding can work very well but when i use server.transer to another page. Button are not able to disable already.
For example webform1 transfer to webform2. Webform 1's button is able to disable but webform2 is not able to disable. Can anyone solve my problem?
Server.Transfer DOES NOT go through all http module pipline (thats why context_OnPreRequestHandlerExecute isn't executed for you )
you should try Server.TransferRequest or response.redirect or HttpContext.Current.RewritePath
Use LINQ to get all your textbox controls.
Don't use Server.Transfer()
Create an extension method on ControlCollection that returns an IEnumerable. That handles the recursion. Then you could use it on your page like this:
var textboxes = this.Controls.FindAll().OfType<TextBox>();
foreach (var t in textboxes)
{
t.Enabled = false;
}
...
public static class Extensions
{
public static IEnumerable<Control> FindAll(this ControlCollection collection)
{
foreach (Control item in collection)
{
yield return item;
if (item.HasControls())
{
foreach (var subItem in item.Controls.FindAll())
{
yield return subItem;
}
}
}
}
}
Taken from this answer.

ASP.NET: How to persist Page State accross Pages?

I need a way to save and load the Page State in a persistent manner (Session). The Project i need this for is an Intranet Web Application which has several Configuration Pages and some of them need a Confirmation if they are about to be saved. The Confirmation Page has to be a seperate Page. The use of JavaScript is not possible due to limitations i am bound to. This is what i could come up with so far:
ConfirmationRequest:
[Serializable]
public class ConfirmationRequest
{
private Uri _url;
public Uri Url
{ get { return _url; } }
private byte[] _data;
public byte[] Data
{ get { return _data; } }
public ConfirmationRequest(Uri url, byte[] data)
{
_url = url;
_data = data;
}
}
ConfirmationResponse:
[Serializable]
public class ConfirmationResponse
{
private ConfirmationRequest _request;
public ConfirmationRequest Request
{ get { return _request; } }
private ConfirmationResult _result = ConfirmationResult.None;
public ConfirmationResult Result
{ get { return _result; } }
public ConfirmationResponse(ConfirmationRequest request, ConfirmationResult result)
{
_request = request;
_result = result;
}
}
public enum ConfirmationResult { Denied = -1, None = 0, Granted = 1 }
Confirmation.aspx:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.UrlReferrer != null)
{
string key = "Confirmation:" + Request.UrlReferrer.PathAndQuery;
if (Session[key] != null)
{
ConfirmationRequest confirmationRequest = Session[key] as ConfirmationRequest;
if (confirmationRequest != null)
{
Session[key] = new ConfirmationResponse(confirmationRequest, ConfirmationResult.Granted);
Response.Redirect(confirmationRequest.Url.PathAndQuery, false);
}
}
}
}
PageToConfirm.aspx:
private bool _confirmationRequired = false;
protected void btnSave_Click(object sender, EventArgs e)
{
_confirmationRequired = true;
Response.Redirect("Confirmation.aspx", false);
}
protected override void SavePageStateToPersistenceMedium(object state)
{
if (_confirmationRequired)
{
using (MemoryStream stream = new MemoryStream())
{
LosFormatter formatter = new LosFormatter();
formatter.Serialize(stream, state);
stream.Flush();
Session["Confirmation:" + Request.UrlReferrer.PathAndQuery] = new ConfirmationRequest(Request.UrlReferrer, stream.ToArray());
}
}
base.SavePageStateToPersistenceMedium(state);
}
I can't seem to find a way to load the Page State after being redirected from the Confirmation.aspx to the PageToConfirm.aspx, can anyone help me out on this one?
If you mean view state, try using Server.Transfer instead of Response.Redirect.
If you set the preserveForm parameter
to true, the target page will be able
to access the view state of the
previous page by using the
PreviousPage property.
use this code this works fine form me
public class BasePage
{
protected override PageStatePersister PageStatePersister
{
get
{
return new SessionPageStatePersister(this);
}
}
protected void Page_PreRender(object sender, EventArgs e)
{
//Save the last search and if there is no new search parameter
//Load the old viewstate
try
{ //Define name of the pages for u wanted to maintain page state.
List<string> pageList = new List<string> { "Page1", "Page2"
};
bool IsPageAvailbleInList = false;
foreach (string page in pageList)
{
if (this.Title.Equals(page))
{
IsPageAvailbleInList = true;
break;
}
}
if (!IsPostBack && Session[this + "State"] != null)
{
if (IsPageAvailbleInList)
{
NameValueCollection formValues = (NameValueCollection)Session[this + "State"];
String[] keysArray = formValues.AllKeys;
if (keysArray.Length > 0)
{
for (int i = 0; i < keysArray.Length; i++)
{
Control currentControl = new Control();
currentControl = Page.FindControl(keysArray[i]);
if (currentControl != null)
{
if (currentControl.GetType() == typeof(System.Web.UI.WebControls.TextBox))
((TextBox)currentControl).Text = formValues[keysArray[i]];
else if (currentControl.GetType() == typeof(System.Web.UI.WebControls.DropDownList))
((DropDownList)currentControl).SelectedValue = formValues[keysArray[i]].Trim();
else if (currentControl.GetType() == typeof(System.Web.UI.WebControls.CheckBox))
{
if (formValues[keysArray[i]].Equals("on"))
((CheckBox)currentControl).Checked = true;
}
}
}
}
}
}
if (Page.IsPostBack && IsPageAvailbleInList)
{
Session[this + "State"] = Request.Form;
}
}
catch (Exception ex)
{
LogHelper.PrintError(string.Format("Error occured while loading {0}", this), ex);
Master.ShowMessageBox(enMessageType.Error, ErrorMessage.GENERIC_MESSAGE);
}
}
}

Add additional content into a known content placeholder from a user control

I have a UserControl that has some javascript I'd like to inject into a known ContentPlaceHolder.
I was hoping to do something like the following except when I append to add the control to found control I get an exception which says I cannot modify the control collection in the Init, Load or PreRender events:
"UserControl.ascx"
<%# Control Language="C#" %>
<asp:Checkbox runat="server" id="checkBox"/>
<app:JavascriptInjector runat="server" InjectInto="ScriptPlaceHolder">
$(function(){ $('#<%= checkBox.ClientID %>').click(function() { ... });
</script></app:JavascriptInjector>
"JavascriptInjector.cs"
using System;
using System.Diagnostics;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
public class JavascriptInjector : PlaceHolder
{
public string InjectInto
{
get { return this.ViewState["InjectInto"] as string; }
set { this.ViewState["InjectInto"] = value; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.PreRender += this.__PreRender;
}
private void __PreRender(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(this.InjectInto))
{
goto performRegularlly;
}
var injectInto = this.FindControlRecursively(this.Page);
if (injectInto == null)
{
goto performRegularlly;
}
injectInto.Controls.Add(this);
return;
performRegularlly:
Debug.WriteLine("performing regularlly");
}
private Control FindControlRecursively(Control current)
{
var found = current.FindControl(this.InjectInto);
if (found != null)
{
return found;
}
foreach (var child in current.Controls.Cast<Control>())
{
return this.FindControlRecursively(child);
}
return null;
}
}
I figured it out. The following JavascriptInjector class will work, although I don't know what the implications are of calling the render method in the PreRender. Also think I may need to do something to figure out which type of HtmlTextWriter that the base application is using.
"JavaScriptInjector.cs"
using System;
using System.IO;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
public class JavascriptInjector : PlaceHolder
{
private bool performRegularlly;
public string InjectInto
{
get { return this.ViewState["InjectInto"] as string; }
set { this.ViewState["InjectInto"] = value; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.PreRender += this.__PreRender;
}
protected override void Render(HtmlTextWriter writer)
{
if (this.performRegularlly)
{
base.Render(writer);
}
}
private void __PreRender(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(this.InjectInto))
{
goto performRegularlly;
}
var injectInto = this.FindControlRecursively(this.Page);
if (injectInto == null)
{
goto performRegularlly;
}
performRegularlly = false;
using (var stringWriter = new StringWriter())
using (var writer = new HtmlTextWriter(stringWriter))
{
base.Render(writer);
writer.Flush();
injectInto.Controls.Add(new LiteralControl(stringWriter.GetStringBuilder().ToString()));
}
this.Controls.Clear();
return;
performRegularlly: this.performRegularlly = true;
}
private Control FindControlRecursively(Control current)
{
var found = current.FindControl(this.InjectInto);
if (found != null)
{
return found;
}
foreach (var child in current.Controls.Cast<Control>())
{
return this.FindControlRecursively(child);
}
return null;
}
}

Resources