Can't load a local html file into a .NET MAUI WebView - c#

I have a basic webpage that I am attempting to load into a WebView on a XAML page. The relevant code is such:
<WebView x:Name="WebViewQuestionText" Source="editor.html" HeightRequest="500" WidthRequest="500" />
As per the official Microsoft .NET MAUI documentation, I have editor.html located in /Resources/Raw/editor.html and set to a Build Action of MauiAsset.
During runtime I don't generate any errors but the WebView is blank. An inspection of the WebView reveals a webpage that is barebones with nothing in it, I assume is the default for a WebView control. If I throw an actual URL in, the page loads up and works as expected, displaying the contents of the given website.
I believe it's simply not finding my page to display it. I'm building for Windows currently but this application will be eventually deployed to both Windows and Mac. How can I ensure it finds it correctly?
As pointed out below - I have also tried it this way, with the same result - when I click the link, I get a blank page.
<WebView x:Name="WebViewQuestionText" HeightRequest="500" WidthRequest="500">
<WebView.Source>
<HtmlWebViewSource>
<HtmlWebViewSource.Html>
<![CDATA[
<html>
<head>
</head>
<body>
<h1>.NET MAUI</h1>
<p>The CSS and image are loaded from local files!</p>
<p>next page</p>
</body>
</html>
]]>
</HtmlWebViewSource.Html>
</HtmlWebViewSource>
</WebView.Source>
</WebView>
My editor.html page is as follows:
<!DOCTYPE html>
<HTML>
<BODY>
<H1>This is a test</H1>
<P>This is only a test</P>
</BODY>
</HTML>

I've fixed this with this PR into .Net Maui. Will be in the SR2 release due in the next few weeks.
The docs suggested it worked consistently on all platforms, but it simply had never been implemented on Windows... slightly concerning.
The workaround I've posted on the PR (mentioned also by Reinaldo below) will get around this for the mean time, however you should probably remove it once SR2 is released and you update to it.

This ends up being a currently open bug against .NET MAUI on the Windows platform.
https://github.com/dotnet/maui/issues/5523
There appears to be a workaround here but it is not ideal. The issue appears to be one of resolving the correct path on Windows for the local file, so the workaround solution is to load the file directly via StreamReader

As mentioned before it is an open bug at the moment. However there is a workaround besides using a StreamReader.
#if WINDOWS
private static readonly System.Lazy<bool> _isPackagedAppLazy = new System.Lazy<bool>(() =>
{
try
{
if (Windows.ApplicationModel.Package.Current != null)
return true;
}
catch
{
// no-op
}
return false;
});
private static bool IsPackagedApp => _isPackagedAppLazy.Value;
// Allow for packaged/unpackaged app support
string ApplicationPath => IsPackagedApp
? Windows.ApplicationModel.Package.Current.InstalledLocation.Path
: System.AppContext.BaseDirectory;
#endif
private async void WebView_HandlerChanged(object sender, EventArgs e)
{
#if WINDOWS
await ((sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView).EnsureCoreWebView2Async();
((sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView).CoreWebView2.SetVirtualHostNameToFolderMapping(
"localhost",
ApplicationPath,
Microsoft.Web.WebView2.Core.CoreWebView2HostResourceAccessKind.Allow);
var wv = (sender as WebView).Handler.PlatformView as Microsoft.Maui.Platform.MauiWebView;
wv.LoadUrl($"https://localhost/{wv.Source.AbsolutePath}");
#endif
}
The WebView would look something like this:
<WebView x:Name="dashBoardWebView" BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
IsVisible="True"
HandlerChanged="WebView_HandlerChanged"
Source="test.html"></WebView>
Hope it helps.
Note: Taken from https://github.com/dotnet/maui/pull/7672

Related

WPF Webbrowser - Access to Document Body on IE11

I'm developing a Desktop application which stores the GUI layer on html files as embedded resources. And I have a WPF Web Browser that manages the user interface lifecycle. I'm able to do all the job with no problems. But I've recently found out that when enabling the FEATURE_BROWSER_EMULATION to IE 11 (11000), the document body becomes inaccessible. Then, when using IE 10 (10000) everything works nicely.
The example below shows how to get the document body OffsetHeight:
dynamic document = (this.wbContent.Document as dynamic);
if ((document == null) || (document.body == null)) return 0;
return document.body.OffsetHeight;
The HTML is:
<html>
...
<body style="width: 170px; height: 240px">
...
</body>
</html>
When using IE 11 it throws an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'.
When using IE 10 it returns 240.
Have you got any idea about how to access body on IE 11?
As I did not get any answer about solving the problem, I had to trick in order to work around the bug. What is did is to put a simple JavaScript on the html file, so I call the method window.resizeTo(a, b). After this event is called, the application get back working, but I actually don't know why.

Windows phone webbrowser Control is Blank?

Im trying to open a URL(Some link) in Webbrowser Control.
The link return a html page which contain Google Graph , but my Webbrowser Control is Blank and dont display any thing on it. It works fine on WebBrowserTask and on my pc so their is no problem in this link but it is blank on webBrowser Control Any Idea How i can Do this ??
public GraphPage()
{
InitializeComponent();
webBrowser1.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(Browser_Navigated);
webBrowser1.Navigating += new EventHandler<NavigatingEventArgs>(Browser_Navigating);
loadPage(getBaseUrl(graphType));
}
private void loadPage(String url )
{
webBrowser1.IsScriptEnabled = true;
webBrowser1.Source = new Uri("Link");
}
As mentioned by user112553, set IsScriptEnabled true. Can be done under the XAML-code or in the code-behind with
XAML
<phone:WebBrowser x:Name="Browser" IsScriptEnabled="True" />
Code-Behind
Browser.IsScriptEnabled = true;
I encountered a similar situation, with Windows Phone 8 and a HTML page using JQuery.
IsScriptEnabled=true wasn't enough (the page didn't render properly).
I solved adding to the html page a
doctype declaration:
<!DOCTYPE html>
<html>
...
Seems like the WebBrowser component refuses to render HTML5 pages without explicit defining the document-type.
Since it's a common problem with rendering pages in IE<11 when not defining this tag, the cause of why my scripts didn't run could be many and most likely a reference to a HTML5 tag which was not handled correctly.
ref: http://msdn.microsoft.com/en-us/hh779632.aspx
Since windows phone 8.0 is based on Internet Explorer 10, it makes sense, the confusing part with debugging this behavior is that Internet Explorer on your phone renders the page perfectly. Still the WebBrowser component will not.
If this is documented in the API specifications, it should be easier to find, because I was not able to find any information that would point me to this solution at all, this would be mostly because my pages was rendered in WebViews for Android and IOS without any problems.
Thanks to Antonio Pelleriti for providing this solution.

Navigating trough objects of a web page, using an embedded web browser

I have a Windows Forms application that uses a WebBrowser control to display an embedded web page. The file is (successfully) loaded using:
webHelp.DocumentStream=
Assembly.GetExecutingAssembly()
.GetManifestResourceStream("MyAssembly.help.html");
In order for this to work (i.e. the file to be loaded/displayed) I set the webHelp.AllowNavigation = false;. I don't fully understand why, but if it's set to true, the page is not displayed.
In my HTML document (see bellow) I want to be able to navigate trough different sections. But when I click on a link, the browser control does not go to the targeted element. The web page works fine in the stand-alone Internet Explorer 10, so it must have something to do with the control, more specifically the AllowNavigation property. MSDN didn't help much.
How can I achieve this navigation behavior? Is there another way of loading the HTML file without setting the AllowNavigation property to false?
This is my simple HTML file:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Using this tool</title>
</head>
<body>
<h3>Description</h3>
<div><p id="contents">Contents</p></div>
<div>
<p id="general">Using the file converter</p>
<p>*converter description*</p>
Go To Top!
</div>
<div class="divBlock" >
<p id="selectOption">Selecting a conversion action</p>
<p>*action selection*</p>
Go To Top!
</div>
</body>
</html>
EDIT: After additional tests I found the root of the problem. The problem appeared after setting a value for the URL property, running the application and afterwards clearing this value. The embedded page is not loaded any more, unless the AllowNavigation property is set to false. There are two solutions, described in my answer bellow.
I also have my own WebBrowser. I've tested it and it loads your HTML file perfectly.
I simply used:
webBrowser1.Navigate("C:\\myPath\\SofNavigate.html");
When I click on links it goes to "#contents" without problems.
I am not sure why you need to use webHelp.Docstream instead of simple Navigate.
By the way, when I turn off navivation, then I am not able to go anywhere from the page that I started on. So Navigation must be on in order to go anywhere from the "home page".
Try to debug that part, as it appears to be the bigger problem that you have.
Here is a good example on how to set up simple webBrowser. Try to use it as a base and see what you do differently that messes up your navigation.
[EDITED] Win8/IE10, your code works for me unmodified inside Form.Load event on a simple form which has just a single WebBrowser control with all default settings (and WebBrowser.AllowNavigation is true by default). Check the properties of your WebBrowser control in the Designer, you may have something wrong in there.
[/EDITED]
You're using HTML5, which handles anchor links via id attribute (i.e. <p id="contents"> ... <a href="#contents">. By default, WebBrowser control works in legacy IE7 mode with HTML5 disabled. You need to turn it on with FEATURE_BROWSER_EMULATION feature control, before WebBrowser object gets created. The best place to do this is a static constructor of your form:
static MainForm()
{
SetBrowserFeatureControl();
}
private static void SetBrowserFeatureControl()
{
// http://msdn.microsoft.com/en-us/library/ee330730(v=vs.85).aspx#browser_emulation
// FeatureControl settings are per-process
var fileName = System.IO.Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
// make sure the control is not running inside Visual Studio Designer
if (String.Compare(fileName, "devenv.exe", true) == 0 || String.Compare(fileName, "XDesProc.exe", true) == 0)
return;
// web pages containing standards-based !DOCTYPE directives are displayed in Standards mode
using (var key = Registry.CurrentUser.CreateSubKey(
#"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
RegistryKeyPermissionCheck.ReadWriteSubTree))
{
key.SetValue(fileName, (UInt32)9000, RegistryValueKind.DWord);
}
}
Try it and your links should work as expected. This solution does NOT require admin rights, the affected key is under HKEY_CURRENT_USER.
[UPDATE] There may be a better solution, it works at least for IE10 here on my side. Add <meta http-equiv="X-UA-Compatible" content="IE=edge" /> as below and leave the registry intact. If you see document.compatMode: CSS1Compat, document.documentMode: 10, you should be good to go, but test with older IE versions too.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title></title>
<script type="text/javascript">
window.onload = function () {
info.firstChild.data =
"document.compatMode: " + document.compatMode +
", document.documentMode: " + document.documentMode;
}
</script>
</head>
<body>
<pre id="info"> </pre>
</body>
</html>
EDIT: After finding the cause of the problem (see the edit to the question) I can now propose three solutions:
1. WebBrowser control replacement:
Simply delete the existing WebBrowser control and add a new one. This solution does not require any modification of the AllowNavigation property. DO NOT modify the URL property.
2. When deleting and adding a new WebBrowser control is not an option:
Since the AllowNavigation property was influencing the loading and displaying of the web page, there was no reason for it to be left to false afterwards. Setting back the property in the Shown event solved the navigation problem, without requiring other alterations (e.g. in the HTML file or the Registry):
private void helpForm_Shown(object sender, EventArgs e)
{
webHelp.AllowNavigation = true;
}
3. Reseting the Document
It seams that the Document property gets (automatically) initialized if URL property is at one time set and reset. Adding webHelp.Document.OpenNew(true); before loading the resource stream solves the problem without the need for re-adding the WebBrowser and without modifying the AllowNavigation property.

My javascript works great locally but crashes when it is on server, why?

Hy,
In my aplication I use Cute Editor for editing some html files.
Everything works great locally, but when I publish my aplication on a server it doesn't recognize the javascript that loads this editor, and if I clear the cache from my browser and then refresh the page it works.
This is the code for integrating the editor to my aspx page:
<CE:Editor ID="Editor1" runat="server" Height="730px" Width="1100px" CssClass="CuteCSS"
OnPostBackCommand="SaveClick" EditCompleteDocument="true" EnableStripStyleTagsCodeInjection="false">
</CE:Editor>
Does anyone have any idea why is this thing happening?
I have implemented Cute Editor in my .net application and working fine on sever also with the following settings:
<CE:Editor ID="Editor1" runat="server" Height="380px" Width="100%" UseFontTags="True"
DisableAutoFormatting="true" EditorOnPaste="default" >
<TextAreaStyle Height="100%" BorderWidth="4px" BorderStyle="Solid" BorderColor="#DDDDDD"
Width="100%" BackColor="White"></TextAreaStyle>
</CE:Editor>
<script language="JavaScript" type="text/javascript">
function CuteEditor_OnCommand(editor,command,ui,value)
{
if(command=='PostBack' && value=='Save')
{
if(SaveData() == false)
return true;
else
return false;
}
}
</script>
try with the given code it might be helpful for you and also notice that you should have all the necessary Cute Editor dll and files in your application.
Now for caching write given code on page load:
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(DateTime.Now);
Response.Cache.SetNoServerCaching();
Response.Cache.SetNoStore();
}
The above code snippet is server side code. Is this appearing in the HTML delivered to your page as well? If so this will be what is causing your problem.
Also I'd suggest checking that your config files are not different on dev and live (and that you have installed appropriate Possible reasons could be differences in config files between your live and dev environment. I'd certainly check that out.
Also you might want to confirm that your server has the right CuteEditor files installed though I would expect some other error if you were missing dlls.
If none of the above is relevant then it might be worth checking that the HTML delivered to the client has sensible valid script to add in the right javsascript files. Load function not being defined sounds like your script file not being loaded which may be that there is no script tag to load it or that it is pointing at an incorrect location (which is valid on your local but not on your dev machine).
I hope some of the above suggestions help.

C#: Open a browser and POST to a url from a windows desktop app

I have a small WPF app (although I guess it doesn't really matter whether it's a wpf form or a webform app?) that I want to have launch a new browser window and POST to a specific url. I've been messing around with:
System.Diagnostics.Process.Start("http://myurl.com");
to launch the window but I don't think I can use the same process to actually post to a url...I've also experimented with HttpWebRequest but I would like the user to be able to use the app after I have posted to this url, not just show them the results...What can I look at to able to do something like this?
There is no direct way to do it. What you could do is generate a HTML page with a form filled with the data you need to post, and a bit of javascript to post the page automatically when it is loaded. Then you just have to open that page in the browser...
The generated HTML could look like that :
<html>
<head>
<script language="Javascript">
function submitForm() {
var theForm = document.getElementById("theForm");
theForm.submit();
}
</script>
</head>
<body onload="submitForm()">
<form id="theForm" action="http://myurl.com" method="POST">
<input type="text" name="username" value="myusername"/>
<input type="password" name="password" value="mypassword"/>
</form>
</body>
</html>
If the page must be displayed in your application, load it in a WebBrowser control
Use the WebBrowser Class instead.
There are multiple solutions, not sure which one would be the best for you...
Proceed with your original approach
Embed web browser control in your applicaiton as suggested in other answers
Do everything programmatically "behind the scene"
For #3 you may want to look here: http://geekswithblogs.net/rakker/archive/2006/04/21/76044.aspx
If you want to go with #1 - it is more tricky, since you need to control external application and different browsers would behave differently.
I've used "javascript:" protocol and the code below with IE as default browser when dealing with one "user-unfriendly" application. Please note that it's not "production-ready" code. There is no error handling, user may shift focus away from launched browser, or use browser without "javascript:" protocol support etc.
static void Main()
{
Settings s = Settings.Default;
Process.Start(s.URL1);
Thread.Sleep(s.Delay1);
SendKeys.SendWait("%D");
Thread.Sleep(100);
SendKeys.SendWait(EncodeForSendKey(s.URL2));
SendKeys.SendWait("{ENTER}");
}
public static string EncodeForSendKey(string value)
{
StringBuilder sb = new StringBuilder(value);
sb.Replace("{", "{{}");
sb.Replace("}", "{}}");
sb.Replace("{{{}}", "{{}");
sb.Replace("[", "{[}");
sb.Replace("]", "{]}");
sb.Replace("(", "{(}");
sb.Replace(")", "{)}");
sb.Replace("+", "{+}");
sb.Replace("^", "{^}");
sb.Replace("%", "{%}");
sb.Replace("~", "{~}");
return sb.ToString();
}
URL1: http://www.google.com
URL2: javascript:function x(){document.all.q.value='stackoverflow';document.forms[0].submit();} x();
You can create a hidden WebBrowser control and do Navigate() (using the overload that allows you to specify the request method). You will need to specify a "_blank" target frame to cause the navigation to happen in a new browser window.

Categories

Resources