I’m trying to add a ChromiumWebBrowser components inside a C#/WPF addin. (Before the addin used CefSharp but the new version of the host application run addin inside custom AppDomain so CefSharp doesn’t work anymore.)
To the problem is, when I call ChromiumWebBrowser.Initialize() a new instance of the host application is launch 🤔 (with some command line args which are dropped by the application).
I really don’t understand the stuff around this command line.
Can you explain to me where I do a mistake ? ChromiumWebBrowser cannot be used inside addin ? I miss somethings ?
Here the C# sample of my code
public partial class myWindow : Window
{
public myWindow()
{
CfxRuntime.LibCefDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Release64";
ChromiumWebBrowser.OnBeforeCfxInitialize += ChromiumWebBrowser_OnBeforeCfxInitialize;
ChromiumWebBrowser.OnBeforeCommandLineProcessing += ChromiumWebBrowser_OnBeforeCommandLineProcessing;
Chromium.WebBrowser.ChromiumWebBrowser.Initialize();
InitializeComponent();
// browser is a ChromiumWebBrowser instance
browser.MouseClick += Wb_MouseClick;
browser.Show();
}
private void Wb_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
(sender as ChromiumWebBrowser).LoadUrl("https://www.google.com"); // properly trigger but nothings will be displayed
}
static void ChromiumWebBrowser_OnBeforeCommandLineProcessing(CfxOnBeforeCommandLineProcessingEventArgs e)
{
Console.WriteLine(e.CommandLine.CommandLineString); // here the command line create a new instance of the application where the plugin is loaded
}
static void ChromiumWebBrowser_OnBeforeCfxInitialize(OnBeforeCfxInitializeEventArgs e)
{
e.Settings.LocalesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\locales";
e.Settings.ResourcesDirPath = #"E:\sources\app\Output\Debug_msvc2017_x64\Addins\cef\Resources";
}
}
And the xaml part
<Window x:Class="App.Views.myWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:App.Views"
xmlns:webbrowser="clr-namespace:Chromium.WebBrowser;assembly=ChromiumWebBrowser"
mc:Ignorable="d"
Title="myWindow" Height="800" Width="1200">
<Grid x:Name="grid1">
<WindowsFormsHost x:Name="wpfContainer">
<webbrowser:ChromiumWebBrowser x:Name="browser"></webbrowser:ChromiumWebBrowser>
</WindowsFormsHost>
</Grid>
</Window>
Thanks in advance for your help ;)
Related
I have called a WPF form from Windows.Forms programatically. Now the concern here is i need to close the wpf form when clicked the button inside the wpf form but its not happening and staying in the WPF screen only. Any idea how do we close the wpf form and proceed for further steps.
Form dialog = new Form();
dialog.Width = 200;
dialog.Height = 100;
ctrlHost = new ElementHost();
ctrlHost.Dock = DockStyle.Fill;
prompt.Controls.Add(ctrlHost);
wpfControl = new User_Control();
wpfControl.InitializeComponent();
ctrlHost.Child = wpfControl;
wpfControl.dialogResult = dialog.ShowDialog();
If you see my above code i have created the form in the run time and assigned the wpf to that. But after showdialog i am struck in that screen and not able to come out. So need a code to close the wpf and come out of that form.
Any idea how do we come out of the wpf back. As i have created some buttons in WPF and need to come out when clicked on that button to the next code where i have loaded the form.
Well a solution could be manage a custom Form and an event.
I've created a simple test project with:
FormMain: the main form with a button to open a HostForm
FormHost: a form with the ElementHost where the wpf usercontrol will be showed
TestControl: the wpf control to show on the ElementHost
Code of the FormMain
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var dialog = new FormHost();
dialog.Width = 200;
dialog.Height = 100;
var result = dialog.ShowDialog();
}
}
Has you can see i just called the FormHost and wait its result
Code of the FormHost:
public partial class FormHost : Form
{
public FormHost()
{
InitializeComponent();
elementHost1.Dock = DockStyle.Fill;
var wpfControl = new TestControl();
wpfControl.InitializeComponent();
//Code your events management here
wpfControl.Close += WpfControl_Close;
elementHost1.Child = wpfControl;
}
private void WpfControl_Close(DialogResult result)
{
//Manage the result as you like
DialogResult = result;
Close();
}
}
In the FormHost I've managed the initilization of the WPF control also the management of events.
Xaml code of the TestControl
<UserControl x:Class="TestHost.TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestHost"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Content="Ok" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Ok_Click" Margin="10"/>
<Button Content="Cancel" Width="60" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10" Click="Cancel_Click"/>
</StackPanel>
Code behind of the TestControl:
public partial class TestControl : System.Windows.Controls.UserControl
{
public event Action<DialogResult> Close;
public TestControl()
{
InitializeComponent();
}
private void Ok_Click(object sender, RoutedEventArgs e)
{
Close?.Invoke(DialogResult.OK);
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
Close?.Invoke(DialogResult.Cancel);
}
}
As you can see i've created an event and managed on the parent Form of the ElementHost, than I've closed the FormHost and setted its DialogResult.
Yesterday I posted thread about VLC player and it's controls.
Adding xaml elements for VLC player to WPF application
After some time, I found a possible solution here:
Integrate VLC player in C# (WPF) project using Vlc.DotNet
I changed it just a little to fir my specific case:
Xaml:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vlc="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<vlc:VlcControl x:Name="vlcPlayer" />
<MediaElement x:Name="movOld" HorizontalAlignment="Left" Height="100" Margin="57,74,0,0" VerticalAlignment="Top" Width="100" Source="Resources/Global_Large_crate_opens.mp3"/>
</Grid>
Code:
public MainWindow()
{
InitializeComponent();
vlcPlayer.MediaPlayer.VlcLibDirectory = new DirectoryInfo(#"D:\VideoLAN\VLC\");
vlcPlayer.MediaPlayer.EndInit();
Uri thisUri = new Uri(#"C:\Users\User\Documents\Visual Studio 2017\Projects\WpfApp1\WpfApp1\Resources\VideoFallingFromTable.ogv", UriKind.RelativeOrAbsolute);
vlcPlayer.MediaPlayer.Play(thisUri);
}
This code works perfectly, when I give a full path from my computer.
However, for my game, I need to take the path from MediaElements, like movOld in this case.
However, when I try to do this:
Uri thisUri = new Uri(movOld.Source.ToString(), UriKind.RelativeOrAbsolute);
vlcPlayer.MediaPlayer.Play(thisUri);
I get this exception:
{"This operation is not supported for a relative URI."}
All my attempts to get file name, or file path as a string, or to use "ToAbsolute()" brought same extension.
Can someone please help me find where the error is, and how to fix it?
Since the game is to be used on many computers, with different possible installation places, it is of vital importance to load the new source for existing MediaElements.
I'm not sure why you are using Media Element when you have VLC control. Anyways, make sure that the Media Element source path "Resources/Global_Large_crate_opens.mp3" exists. Are you sure that its a forward slash there? usually in Windows, paths use a backslash. Also if your path is absolute then you need to define it like below:
Uri thisUri = new Uri(movOld.Source.ToString(), UriKind.Absolute);
vlcPlayer.MediaPlayer.Play(thisUri);
The problem is only with your Media Element Source path. Just make sure whatever you put there exists and accessible.
Update:
I recently worked with VLC control, where I built my own User Control to hide VLC library logic and exposed File Path & other dependency properties to specify them from XAML.
You can try using the minimal version of that control in your app.
public partial class VLCControl : UserControl
{
public VLCControl()
{
InitializeComponent();
var currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
string platform = Environment.Is64BitProcess ? "x64" : "x86";
var dirPath = System.IO.Path.Combine(currentDirectory, "vlclib", platform);
vlc.MediaPlayer.VlcLibDirectory = new DirectoryInfo(dirPath);
vlc.MediaPlayer.EndInit();
}
public void Play()
{
if (vlc.IsInitialized && !String.IsNullOrWhiteSpace(FilePath))
{
var options = new string[]
{
String.Format("input-repeat={0}", Repeat)
};
vlc.MediaPlayer.SetMedia(new Uri(FilePath), options);
if (!String.IsNullOrWhiteSpace(AspectRatio))
vlc.MediaPlayer.Video.AspectRatio = AspectRatio;
vlc.MediaPlayer.Play();
}
}
public void Stop()
{
vlc.MediaPlayer.Stop();
}
public string AspectRatio
{
get { return (string)GetValue(AspectRatioProperty); }
set { SetValue(AspectRatioProperty, value); }
}
public static readonly DependencyProperty AspectRatioProperty =
DependencyProperty.Register("AspectRatio", typeof(string), typeof(VLCControl));
public string FilePath
{
get { return (string)GetValue(FilePathProperty); }
set { SetValue(FilePathProperty, value); }
}
public static readonly DependencyProperty FilePathProperty =
DependencyProperty.Register("FilePath", typeof(string), typeof(VLCControl));
public int Repeat
{
get { return (int)GetValue(RepeatProperty); }
set { SetValue(RepeatProperty, value); }
}
public static readonly DependencyProperty RepeatProperty =
DependencyProperty.Register("Repeat", typeof(int), typeof(VLCControl), new PropertyMetadata(-1));
private void vlc_Loaded(object sender, RoutedEventArgs e)
{
Play();
}
}
The XAML file code is:
<UserControl x:Class="VLCControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:vlc="clr-namespace:Vlc.DotNet.Wpf;assembly=Vlc.DotNet.Wpf"
d:DesignHeight="300" d:DesignWidth="300" >
<vlc:VlcControl x:Name="vlc" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Loaded="vlc_Loaded"/>
</UserControl>
If it helped you then don't forget to accept the answer :)
I use MVVM framework and got this tutorial on net: https://code.msdn.microsoft.com/windowsdesktop/How-to-use-MVVM-Pattern-0e2f4571 and http://www.c-sharpcorner.com/UploadFile/raj1979/simple-mvvm-pattern-in-wpf/
Now, my problem is:
I can't display the mainpage.xaml even there is no semantic error. Here's my code on app.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
window.Show();
}
Can anyone help me? Thanks for any help! :)
Thanks to everyone who helped.
[SOLVED]
Change the startupuri in app.xaml to where the page you want to load. In my case
1: I change it:
StartupUri="View/MainPage.xaml"
2: In app.xaml.cs, I typed in this code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
}
from my previous code, delete this code: window.show(); because it startup the page twice coming from app.xaml and app.xaml.cs. To prevent that, delete: window.show();
Thank you again! :)
Set the starting page in app.xaml, not the app.xaml.cs file - in the Application tag, if there is no property StartupUri - add one and set its value to your page name, this way the page will be automatically shown as soon as your application is started. It should look something like this:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainPage.xaml">
I am considering that you are doing it this way because you wish to set the DataContext of the page, but there is a better way to set the DataContext of your page and it is by setting it directly into your XAML code. Here is an example:
<Page x:Class="WpfApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" >
<Page.DataContext>
<local:UserViewModel/>
</Page.DataContext>
xmlns:local is a prefix mapping to the namespace you have set for it. Having this you are able to access the types contained in the namespace using the prefix - local:UserViewModel.
what you can do is instead of setting data context in app.xaml.cs, just hook up the loaded event of main window and add the following code.
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
}
This should work. Dont forget to remove the codes from App.xaml.cs.
Thanks
SO in your case you have a main window inside that main window you need to load the page.
What you can do is add a frame to your mainwindow like
<Frame x:Name="myFrame"/>
then inside the mainwindow loaded event add the below code
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
myFrame.Content = new MainPage();
}
This is like we are adding a frame and loading your view to that frame.
I'm currently doing a touch application in WPF. It works great so far but sometimes I need to launch the built-in web browser control. My problem is that despite that the zoom, scroll and such are working, I can't get the Windows 8 virtual keyboard (like in IE 11) to show up when the user gets the focus on web text inputs.
Is there any way to achieve such behavior ? Please keep in mind my WPF app is supposed to run topmost and entirely fullscreen all the time so I can't ask the user to bring up the virtual keyboard manually.
Finally found it here... As written, the Winforms WebBrowser has better wrapper for HTMLDocument, making it way easier than using MSHTML interop. Here's a code snippet :
C# :
public partial class BrowserWindow : Window
{
public BrowserWindow(string url)
{
InitializeComponent();
WebView.ScriptErrorsSuppressed = true;
WebView.AllowNavigation = true;
WebView.Navigate(new Uri(url));
WebView.DocumentCompleted += LoadCompleteEventHandler;
}
private void LoadCompleteEventHandler(object sender, WebBrowserDocumentCompletedEventArgs navigationEventArgs)
{
HtmlElementCollection elements = this.WebView.Document.GetElementsByTagName("input");
foreach (HtmlElement input in elements)
{
if (input.GetAttribute("type").ToLower() == "text")
{
input.GotFocus += (o, args) => VirtualKeyBoardHelper.AttachTabTip();
input.LostFocus += (o, args) => VirtualKeyBoardHelper.RemoveTabTip();
}
}
}
}
XAML :
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
x:Class="PlayPlatform.BrowserWindow"
Title="Browser" ResizeMode="NoResize"
WindowStartupLocation="CenterScreen" WindowState="Maximized" Topmost="True" ShowInTaskbar="False" WindowStyle="None" AllowDrop="False" AllowsTransparency="False">
<WindowsFormsHost HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<wf:WebBrowser x:Name="WebView" />
</WindowsFormsHost>
</Window>
The VirtualKeyBoardHelper methods are manuallly launching and terminating tabtip.exe.
I need to delete some certain files, then user closes program in WPF. So I tried MDSN code from here http://msdn.microsoft.com/en-us/library/system.windows.application.exit.aspx this way:
this code located here App.xml.cs
public partial class App : Application
{
void App_Exit(object sender, ExitEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}
}
// App.xaml
<Application x:Class="ModernUIApp1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit">
<Application.Resources>
First of all it doesn't delete files, secondly this program stays in the process after I pushed exit button( this is really strange). This code don't give any errors. And finally it doesn't show MessageBox So anything wrong here?
I think he just can`t find this function.
It's quite simple:
Add "Exit" property to the application tag
<Application x:Class="WpfApplication4.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit">
</Application>
and handle it in the "code behind"
private void Application_Exit(object sender, ExitEventArgs e)
{
// Perform tasks at application exit
}
The Exit event is fired when the application is shutting down or the Windows session is ending. It is fired after the SessionEnding event. You cannot cancel the Exit event.
you should add app_exit in your xaml code
<Application x:Class="CSharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
ShutdownMode="OnExplicitShutdown"
Exit="App_Exit"
>
</Application>
you can just hook the event Closing on your main window like this -
<Window Closing="Window_Closing">
And in your event do all the work you need
private void Window_Closing(object sender, CancelEventArgs e)
{
MessageBox.Show("File deleted");
var systemPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
var _directoryName1 = Path.Combine(systemPath, "RadiolocationQ");
var temp_file = Path.Combine(_directoryName1, "temp.ini");
if (File.Exists(temp1_file))
{
File.Delete(temp1_file);
}
}
If you don't like adding Exit event to XAML, you could try this alternative.
Add following method to your App.xaml.cs:
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
// Your code here
}
If you want to follow MVVM principle you can use System.Windows.Interactivity.WPF.
MainWindow.xaml
<Window x:Class="Endonext.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding WindowClosingCommand, Mode=OneTime}" />
</i:EventTrigger>
</i:Interaction.Triggers>
MainWindowViewModel.cs
public class MainWindowViewModel
{
ICommand WindowClosingCommand => new RelayCommand(arg => this.WindowClosing());
private void WindowClosing()
{
// do what you want.
}
}
This approach is more testable.
Have a nice day.
Make sure that the namespace (MyApp) matches "x:Class=MyApp..."
Under properties for <Application></Application>, double click on the textbox next to 'Exit'.
If you get "Unable to add event handler" then Rebuilding the project fixed it for me.
XAML
<Application x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
Exit="Application_Exit"
>
Code behind
using System.Windows;
namespace MyApp
{
public partial class App : Application
{
private void Application_Exit(object sender, ExitEventArgs e)
{
//your code
}
}
}