WebBrowser issue (add infinite progress in web browser) - codenameone

It takes a couple of seconds to load an url in webbrowser. Sometimes it takes more time to load. How to add infinite progress like that of connectionRequest in webbrowser?
#Override
protected void postWebView(Form f) {
WebBrowser wb = new WebBrowser();
if (businessWebsiteUrl != null && !businessWebsiteUrl.equals("")) {
wb.setURL("http://" + businessWebsiteUrl);
f.add(BorderLayout.CENTER, wb);
} else {
}
f.revalidate();
}
What I did but doesnot work
protected void beforeWebView(Form f) {
ip = new InfiniteProgress();
f.add(BorderLayout.CENTER, FlowLayout.encloseCenterMiddle(ip));
}

That's inherently problematic since a browser is effectively a peer component and while we can now paint on top of peers in Android this is still not portable.
Even if it would I'm not sure if it would be a good idea.
Overall you have the following options:
Place a progress indicator above/below the browser component
Fetch the data separately as HTML with a progress and set the HTML which should be instant
Use JavaScript and potentially an iframe to indicate progress from within the browser component itself

Related

Cefsharp - display page loading indication

I'm implemeting a win form which contains a cefsharp chromium-embedded browser.
I'm facing the following problem - sometimes it takes time until a page is loaded.
The problem is that user has no idea that something happens until the page is actually loaded.
I have no control on the pages that the browser displays.
I need to display some kind of loading indication. I searched the web and the only thing that I found was to show an animated loading image while the loading takes place and hide it when the page is loaded (using the load state changed event).
It seems to make things even slower.
Is there anything in Cefsharp infrastructure that I can use? or any other idea of solving it?
Thanks!
ChromeView = new CefSharp.Wpf.ChromiumWebBrowser();
//Adding event listener
ChromeView.NavStateChanged += ChromeView_NavStateChanged;
//Event listener
private void ChromeView_NavStateChanged(object sender, CefSharp.NavStateChangedEventArgs e)
{
if(!e.IsLoading)
{
this.Dispatcher.Invoke(()=> { //Invoke UI Thread
controller.setLoaderinBack(); //UI Update
});
}
else
{
this.Dispatcher.Invoke(() => { //Invoke UI Thread
controller.setLoaderinFront(); //UI Update
});
}
}
For Higher Versions of CefSharp (mine version 81):
ChromeView = new CefSharp.Wpf.ChromiumWebBrowser();
//Adding event listener
ChromeView.LoadingStateChanged += ChromeView_NavStateChanged;
//Event listener
private void ChromeView_NavStateChanged(object sender, LoadingStateChangedEventArgs e)
{
if(!e.IsLoading)
{
//Stuff...
}
else
{
//Stuff...
}
}

Why Doesn't My Component Appear On Top of The HTML Page Or Media Player In Codename One

I've used a media player and I'm trying to do rendering on top of it with progress indication or buttons but the code isn't working.
E.g.:
findInfiniteProgress().setVisible(true);
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
if(findMediaPlayer().getMedia() != null && findMediaPlayer().getMedia().isPlaying()){
findInfiniteProgress(f).setVisible(false);
}else{
findInfiniteProgress(f).setVisible(true);
}
}
});
}
};
Codename One uses lightweight rendering which means all components are drawn in sequence on a single thread. Native widgets (peers) need to be drawn on the native thread and are always drawn on top, that is the secret to Codname Ones portability explained here.
Common peers in Codename One include: Web browser, media playback & native maps.
The workaround is to use Dialog which is effectively a separate Form so the current peer doesn't really render underneath.

How to avoid memory leak in code of Win 7 - Onscreen keyboard while clicking in textbox inside web browser control in wpf (C#)

I am developing WPF - Web browser control based kiosk application.
I have implemented the feature like when somebody clicks on any textbox inside the page rendered in wpf web browser control then onscreen keyboard will open.
But the code which I have implemented is causing the continuous memory leak.
please find sample files here
Please refer below document to get more detail on issue.
for more detail on issue click here
whenever you will continuously browse www.google.com for 15 minutes in wpf web browser control then memory utilization of application keeps on increasing and it will never decrease, you can see increase in memory usage from task manager also.
please wait till 15 - 20 seconds after clicking inside the textbox, after 15-20 seconds onscreen keyboard will display.
Please help to avoid memory leak.
Thanks,
Pritesh
public static void LaunchOnScreenKeyboard()
{
try
{
//This is used to get the osk.exe process and enable On screen keyboard
var processes = Process.GetProcessesByName("osk").ToArray();
if (processes.Any())
return;
var keyboardManagerPath = "osk.exe";
Process.Start(keyboardManagerPath);
}
catch (Exception ex)
{
}
}
This Method is also GetProcessesByName(processname)utilizing more memory
This line of code is causing the memory leak, when I comment this code then memory leak stops.
#region On screen keyboard
//Get the HTML of current page and cast as HTMLDocument
HTMLDocument document = (mshtml.HTMLDocument)webBrowser.Document;
//For each loop to access all the HTML tags in the current page
foreach (IHTMLElement links in document.all)
{
//If condition to access all the Input, Iframe and TextArea in the current page and attach focus event to it
if (links.tagName.Contains("INPUT") || links.tagName.Contains("IFRAME") || links.tagName.Contains("TEXTAREA"))
{
HTMLInputTextElement textinput = links as HTMLInputTextElement;
if (textinput != null)
{
HTMLInputTextElementEvents_Event handler = textinput as HTMLInputTextElementEvents_Event;
if (handler != null)
{
handler.onfocus += new HTMLInputTextElementEvents_onfocusEventHandler(delegate()
{
IHTMLElement2 pwInput = null;
pwInput = (IHTMLElement2)textinput;
pwInput.focus();
//This calls the LaunchOnScreenKeyboard() to show On screen keyboard on the screen when Input, Iframe and TextArea tags are present in current page
KeyboardManager.LaunchOnScreenKeyboard();
});
}
}
}
}
#endregion

MessageBox.Show early in App startup causes app to terminate

As part of my App's startup procedure, it checks data integrity, and if it finds a problem it pops up a message to the user telling them that it might take a while to repair things.
I'm showing the message using MessageBox.Show. Because the data check is done from a worker thread, I'm switching over to the UI thread to make that call, and then setting a ManualResetEvent to tell the worker thread when the user has acknowledged the message.
I kick off the data check/load very early in the app's lifecycle from the constructor in the main Application class, by spinning off a worker thread (using the ThreadPool).
When I run with the debugger, and the message is displayed, the app just waits for input. When I run without the debugger, the app terminates after displaying the dialog for 10 seconds.
That 10 seconds is a big clue - it tells me that the OS thinks the app took too long to initialize (the OS kills apps that take too long to start up).
I think that my MessageBox.Show is blocking the UI thread before the App.RootFrameNavigating has a chance to be invoked.
My questions:
Does my diagnosis sound right?
I'd prefer to kick off my data load early, because it is almost entirely IO, except for this Message Box, and the sooner I can get my Model loaded, the better, but do you normally delay your data load until later in the app lifecycle?
Any other ideas/suggestions? I can't guarantee which page will be the start page, because the app could be resuming to any page. I'm also thinking of having the MessageBox.Show delay itself until the app has initialized, perhaps polling away for a flag set by App.RootFrameNavigating - does that make sense?
I think your problem is a result of kicking off the worker thread in the Application constructor. You should use the appropriate life-cycle event, in this case: PhoneApplicationService.Activated Event
So, the solution I've come up with is to still kick off the data load in a worker-thread from the Application's constructor, but in my PhoneService's class ShowDialog method that I invoke to invoke MessageBox.Show, I check to see if the initial navigation has occurred:
private readonly ManualResetEvent _appInitialized = new ManualResetEvent(false);
public void AppInitialized()
{
_appInitialized.Set();
}
public void ShowDialog(string caption, string text, Action<MessageBoxResult> callback, MessageBoxButton button = MessageBoxButton.OKCancel)
{
_appInitialized.WaitOne();
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var result = MessageBox.Show(text, caption, button);
if (callback != null)
{
callback(result);
}
});
}
Then in my Application class:
private bool _firstNavigate = true;
private void RootFrameNavigating(object sender, NavigatingCancelEventArgs e)
{
if (_firstNavigate)
{
_firstNavigate = false;
var navigationService = (NavigationService) sender;
navigationService.Navigated += NavigationServiceNavigated;
}
....
private void NavigationServiceNavigated(object sender, NavigationEventArgs e)
{
var navigationService = (NavigationService)sender;
navigationService.Navigated -= NavigationServiceNavigated;
PhoneServices.Current.AppInitialized();
}
Anyone see any issues with this approach? Anyone come up with a better way?

How to detect a browser refresh from Silverlight 4?

My Silverlight 4 application keeps in contact with a server side through a wcf service. Whenever the user refreshes, navigates away or terminates the browser I should do some cleanup towards the server side.
I can not use the Application Exit event; my wcf client is dead before it eventually gets called. I can not use the (new in SL4) FrameworkElement Unloaded event; it ain't called when the Silverlight app shuts down.
So, how do I detect the browser refresh, newpage or shutdown in time to do my cleanup?
BaBu,
I do this exact thing when a user navigates away from my Silverlight app (or does a refresh). Follow the steps below to catch this event.
1.) Start by listening for the HTML page's "onbeforeunload" event, like so...
public void Application_Startup(object sender, StartupEventArgs e)
{
bool ok = HtmlPage.Window.AttachEvent("onbeforeunload", Application_BeforeExit);
ok = HtmlPage.Document.AttachEvent("onbeforeunload", Application_BeforeExit);
MainPage mainPage = new MainPage();
base.RootVisual = mainPage;
}
2.) Implement Application_BeforeExit() to setup and call an ASP.NET "PageMethod", like so...
private void Application_BeforeExit(object sender, HtmlEventArgs args)
{
string methodName = "ModelShutdown";
params object[] args = new Guid().ToString());;
try
{
ScriptObject pageMethods = (ScriptObject)HtmlPage.Window.GetProperty("PageMethods");
if (pageMethods == null)
throw new ArgumentException("Web page does not support PageMethods");
object[] pageMethodArgs = { new PageMethodEventHandler(Success), new PageMethodEventHandler(Failure), null/*userContext*/};
object[] combinedArgs = new object[args.Length + pageMethodArgs.Length];
args.CopyTo(combinedArgs, 0);
pageMethodArgs.CopyTo(combinedArgs, args.Length);
pageMethods.Invoke(methodName, combinedArgs);
}
catch (Exception ex)
{
//ex.Alert();
}
}
3.) Add the PageMethod to your page code behind (Index.aspx.cs), like so,
public partial class Index : Page
{
[WebMethod] // a PageMethod called from Silverlight
public static void ModelShutdown(string identifier)
{
System.Diagnostics.Debug.WriteLine("*** Signing Off: " + identifier);
}
}
4.) Allow PageMethods on your page (Indx.aspx), like so,
<asp:ScriptManager runat="server" EnablePageMethods="true" />
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
Good luck,
Jim McCurdy, YinYangMoney.com
I don't think you can do anything server side after the user has decided to navigate away or browser is terminated. However you can write some JavaScript to prevent unloading of the current page where you can warn the user not to close it.
Second, use a small session timer that ticks every two minutes or so. Your session should timeout but when your Silverlight application is open and running in the browser, you should ping your server by writing some ping method that will keep your session alive every one minute.
So if your session is expiring (it didn't receive ping in the last 60 seconds), your session will be destroyed and you can write some cleanup code at the server's session end.
I had a similar requirement for an MVC app. What I did was use jQuery to subscribe to the unload event and make an ajax call to a controller action that killed the session:
$(window).unload(function() {
$.ajax({url: Url.Action("KillSession")});
});
public ActionResult KillSession()
{
Session.Abandon();
return new HttpStatusCodeResult(System.Net.HttpStatusCode.NotModified);
}

Resources