I need to create a Web-based Dashboard tool for a LOB application. Essentially users need to be able to log in to a web-site which will allow them to view stats for various bits of data, as well as see any notifications that pertain to them. Our primary application is built for the desktop using WPF. We also need to provide an identical dashboard that will be hosted in our WPF app. The main difference being that in the WPF version they will have buttons that will open up other parts of the application to make changes to the data, or perform whatever actions are necessary.
The main issue is that management only wants to write 1 version that can be used both on the web and in the WPF shell. They don't want to write to different version of the UI. So the solution would be to write the dashboard for the web, but host it inside our desktop application for local users, and in the browser for remote users.
So here's my questions:
How do I go about hosting a web page inside my WPF app
How could I hide/remove buttons based on whether I'm inside my WPF app vs. inside something like IE explorer?
If links or buttons are clicked inside the browser, how can the WPF app react to those clicks and open the pertinent screen inside the app?
What's a better approach?
I realize this idea is probably bad so don't flame me for it. I'm simply trying to supply management with the right approach. All suggestions are welcome.
Thanks!
You can host a web page in a WPF application using the WebBrowser controls that was added in .NET 3.5 SP1:
<Grid>
<WebBrowser Name="browser" />
</Grid>
And in the code-behind you have to set the Uri to your page and an object (which should be com-visible) that is to be called from the java script:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
string uri = AppDomain.CurrentDomain.BaseDirectory + "TestPage.html";
this.browser.Navigate(new Uri(uri, UriKind.Absolute));
this.browser.ObjectForScripting = new ScriptingHelper();
}
[ComVisible(true)]
public class ScriptingHelper
{
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
}
}
And finally in your page you must call the code using window.external like below:
<head>
<title></title>
<script type="text/javascript">
function OnClick()
{
var message = "Hello!";
window.external.ShowMessage(message);
}
</script>
</head>
<body>
Click me
</body>
o, and you should add
saved from url=(0014)about:internet comment
above the head tag to make IE not block the javascript
Related
Right now we use the old WPF WebBrowser control to show a web site in our program. Since this old control is based on Internet Explorer 11 and a lot of newer web sites show a message, that they are not running on Internet Explorer 11, we are looking for a replacement for this old control.
We took a look into WebView2 but unfortunately this browser doesn't show up in our setup (WPF control hosted in an ElementHost in WinForms, hosted in an ocx in COM, used in MS Access).
So we take a look in CefSharp now. I didn't get to trying if this browser shows up in our setup because I don't find a solution for a simple requirement in my test program.
I'd like to restrict the user to follow links that might be part of the web site. In WebView2 there's a NavigationStarting event which can be canceled, but I didn't find anything like that in CefSharp.
There's an AddressChanged event, but this also fires when the web site is re-directing.
So, is it somehow possible with CefSharp to load an initial website (including any re-directions) and then doing nothing when a link inside the web site is clicked?
You can cancel navigation in OnBeforeBrowse
public class CustomRequestHandler : CefSharp.Handler.RequestHandler
{
protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture, bool isRedirect)
{
if (request.TransitionType == TransitionType.LinkClicked)
{
//Cancel the request by returning true
return true;
}
return base.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect);
}
}
browser.RequestHandler = new CustomRequestHandler();
Last year I built a WPF application using page navigation and no MVVM.
Recently I was asked to build a new application for the same customer which I did in WPF MVVM with Caliburn Micro and MEF. Now my customer asks me to integrate the new application into the old one.
My thought was to add a new page to the old application and to integrate the shell of the new application into a ContentControl of this page.
My problem now is that the old application is started by an
<StartupUri="Views\NavWindow.xaml">
entry in the app.xaml, while the new application is started by a bootstrapper like
<local:AppBootstrapper x:Key="bootstrapper" />
where AppBootstrapper looks like
class AppBootstrapper : Bootstrapper<ShellViewModel>
{
private CompositionContainer container;
protected override void Configure()
{
container = new CompositionContainer(new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));
CompositionBatch batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);
container.Compose(batch);
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues<object>(contract);
if (exports.Count() > 0)
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
}
So, as far as I understand, in case of the new app the bootstrapper initializes the whole app, calls the ShellViewModel and eventually the ShellView.
Because I use the EventAggregator in the new app to send messages from one viewmodel to another, I think I canĀ“t just get rid of the bootstrapper and use the view-first model of Caliburn Micro.
So my problem is: can I call the bootstrapper from my old app by myself, and if so, where should I store the instance of it, and how do I tell Caliburn Micro where to put the ShellView?
Any help is appreciated.
CM is so light that in these situations it's actually worth having a peek at the source to see what a particular class is actually doing.
The Bootstrapper works because declaring it in the resources file of the application forces an instantiation of it. The constructor calls Start on the instance and that sets up the aggregator, IOC, etc.
https://caliburnmicro.codeplex.com/SourceControl/changeset/view/4de6f2a26b21#src/Caliburn.Micro.Silverlight/Bootstrapper.cs
If you were to load the application into a ContentControl in another application, I can't see a reason why it wouldn't kick off CM as the resources for the loaded application would still be processed, instantiating and starting up the Bootstrapper etc. Have you tried it in a test project? That might be your first option.
There may be some areas where CMs default implementation of Bootstrapper might not be ideal, but on first glance I can't see any glaring issues (not sure what happens to the application events such as OnStartup etc when you load a sub-application so you might want to look at that). Worst case you can roll your own Bootstrapper for the sub-app and just rebuild with the tweaked functionality.
I am having a my problem is I can not redirect my page in silverlight like most of people who are not familiar with this technology .
I design a login page first and if password is correct I want it to direct to MainPage.xaml
as you can see I tried methods which are commented already it did not work . I searched in this web page there are some posts about this problem but I could not solve please help me .
when i try that one;
Uri target = new Uri("MainPage",UriKind.Relative);
NavigationService.Navigate(target);
error message : Object reference not set to an instance of an object.
actually we found a solution with my friend ;
instead of directing a web page , when code goes into if block we are changing the content of page with {this.Content = new MainPage() ; } method and it is working .But System.Windows.Browser.HtmlPage.Window.Navigate(target) this one is directing us same login page or pages like www.---.com outside normal html pages .
Normally you need to use the NavigationService to do this:
NavigationService.Navigate(new Uri("/MainPage", UriKind.Relative));
The NavigationService is a property on the Page object so it will be available in the Login code-behind.
However, after you mentioned that you've "already done this" I realized the issue. Silverlight Navigation uses a Frame control. This Frame control lives in MainPage.xaml for the default project. So you're not navigating inside the frame, but you want to change the entire screen to a different one and do so without the Navigation services built into Silverlight.
I'd suggest you either (a) have the Login run as a page inside of the Frame on MainPage (you can load or unload the links on the top based on if the user is authenticated) or (b) don't use the Navigation for the remainder of the application and use a framework like Caliburn.Micro to handle all the Navigation between views.
I am trying to implement a simple Facebook login flow using WPF. It turns out that I need to use some sort of embedded browser within the application if the application is a desktop application. Therefore I am using WebBrowser control, but I can't seem to correctly detect the redirecting URL.
Once I load the web page for facebook login, and after login, the browser redirects to a page of the form
https://www.facebook.com/connect/login_success.html#access_token=....
But if I look at the URI source, it only shows up to login_success.html and is cutting off whatever is after the # sign. I need this information for further processing, so I was wondering if anyone could advise on retrieving that access token using WebBrowser (or any other way) in WPF. Thanks!
I was having the saving problem with the WPF Sample in the SDK today. I figured it was a problem with the WPF Webbrowser control (like you had infered). So I used the windows.forms.webbrowser instead of the WPF webcontrol. It is a simple fix.
System.Windows.Forms.Integration.WindowsFormsHost host =
new System.Windows.Forms.Integration.WindowsFormsHost();
_webBrowser = new System.Windows.Forms.WebBrowser();
host.Child = _webBrowser;
this.grid1.Children.Add(host);
_webBrowser.Navigated += new WebBrowserNavigatedEventHandler(webBrowser_Navigated);
_webBrowser.Navigate(_navigateUrl.AbsoluteUri);
I know this may sound pretty dumb but how do I add a new webpage to the Silverlight Project?
I did a "Add new Item" and select an xaml file.
Now I want to open that file via the webbrowser. The File is called PrintPage.xaml.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
HtmlPage.Window.Navigate(new Uri("PrintPage.xaml" , UriKind.Relative), "_blank");
}
Page not found error.
Xaml pages are Silverlight Pages, not Web pages. With Silverlight you are always on the same Web page, but displaying different Silverlight pages internally within the Silverlight object.
If you want to change Silverlight pages, start with either the Silverlight Navigation App or Silverlight Business App templates as an example. The Silverlight navigation systems all work using browser "bookmark" links (they have a # at the end of the HTML page) and use the parameters after the # to determine the target page. By using bookmark links the hosting web page does not get refreshed (otherwise the Silverlight application would reload).
If you actually want to go to a new web page, with a new Silverlight application, you want to add an ASPX or HTML page instead and browse to that.
Use this code
HtmlPage.Window.Invoke("ShowBrowserIFrame", url);
url is path of your hemp page, and ShowBrowserIFrame is java script function, used to open html web page.
function ShowBrowserIFrame(url) {
BrowserDivContainer.css('display', 'block');
$('<iframe id="' + jobPlanIFrameID + '" src="' + url + '" style="height:100%;width:100%;" />')
.appendTo(BrowserDivIFrameContainer);
slHost.css('width', '0%');
}
Follow this link to add html page inside silver light project.