In WPF app I have created WindowsFormsHost and wanted to insert in it a Form containing COM/Activex control. But then I get:
A first chance exception of type 'System.ArgumentException' occurred in WindowsFormsIntegration.dll
at System.Windows.Forms.Integration.WindowsFormsHost.set_Child(Control value)
at HomeSecurity.MainWindow..ctor() w c:\Users\R\Documents\Visual Studio 2013\Projects\HomeSecurity\HomeSecurity\MainWindow.xaml.cs:row 26
'HomeSecurity.vshost.exe' (CLR v4.0.30319: HomeSecurity.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll'. Symbols loaded.
This is the contstructor of MainWindow. Class VideoStream extends class Form
public MainWindow() {
InitializeComponent();
VideoStream VideoStream = new VideoStream();//creating a Form containing Activex control
WindowsFormsHost Host = new WindowsFormsHost();//creating a host
try {
Host.Child = VideoStream;//setting content of Host, CAUSES THE EXCEPTION PRINTED ABOVE
}catch(Exception e){
Console.WriteLine(e.StackTrace);//output above
}
}
I cannot deal with it for long time and I have no more time. How to fix this problem?
Well, You can't add a Form(TopLevelControl) inside it. You'll have to make it child control first. Setting TopLevel is set to false should make it work.
VideoStream.TopLevel = false;
Note: Not only with WindowsFormsHost, even with Winforms application also you can't add a Form inside a Form unless TopLevel is set to false.
Why not derive VideoStream from UserControl rather than from Form? IMO, that'd be more appropriate for re-using and hosting it inside a WPF app, and the problem would have been gone.
[EDITED] You should first add the WindowsFormsHost control to the WPF window, then add your UserControl-derived VideoStream control to the WindowsFormsHost control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
namespace WpfWinformsTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// add a grid first (optional)
var grid = new Grid();
this.Content = grid;
// create and add a WinForms host
WindowsFormsHost host = new WindowsFormsHost();
grid.Children.Add(host);
// add a WinForms user control
var videoStream = new VideoStream();
host.Child = videoStream;
}
}
}
You can do the same with XAML:
<Window x:Class="WpfWinformsTest.MainWindow"
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"
xmlns:local="clr-namespace:WpfWinformsTest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<WindowsFormsHost Name="wfHost" Focusable="True" Margin="10,10,10,10">
<local:VideoStream x:Name="videoStream" />
</WindowsFormsHost>
</Grid>
</Window>
Here's how VideoStream may look like (of course, you can use VS Designer to add controls like axVideoPlayer to it, rather than doing it manually):
using System.Windows.Forms;
namespace WpfWinformsTest
{
public partial class VideoStream : UserControl
{
AxWMPLib.AxWindowsMediaPlayer axVideoPlayer;
public VideoStream()
{
InitializeComponent();
this.axVideoPlayer = new AxWMPLib.AxWindowsMediaPlayer();
this.axVideoPlayer.Size = new System.Drawing.Size(200, 100);
this.Controls.Add(this.axVideoPlayer);
}
}
}
I suggest you read the following articles:
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting an ActiveX Control in WPF
Related
So I was reading a book "wpf4 unleashed by Adam Nathan" and saw an example about "Hosting the Terminal Services ActiveX control in a WPF Window". It has some code displayed and I figured out that I should do it.
using System;
using System.Windows;
using System.Windows.Forms.Integration;
namespace HostingActiveX
{
public partial class Window1 : Window
{
AxMSTSCLib.AxMsTscAxNotSafeForScripting termServ;
public Window1()
{
InitializeComponent();
// Create the host and the ActiveX control
WindowsFormsHost host = new WindowsFormsHost();
termServ = new AxMSTSCLib.AxMsTscAxNotSafeForScripting();
// Add the ActiveX control to the host, and the host to the WPF panel
host.Child = termServ;
panel.Children.Add(host);
}
void connectButton_Click(object sender, RoutedEventArgs e)
{
termServ.Server = serverBox.Text;
termServ.Connect();
}
}
}
and XAML:
<Window x:Class=”HostingActiveX.Window1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”Hosting the Terminal Services ActiveX Control”>
<DockPanel Name=”panel” Margin=”10”>
<StackPanel Margin=”0,0,0,10” DockPanel.Dock=”Top” Orientation=”Horizontal”>
<TextBox x:Name=”serverBox” Width=”180” Margin=”0,0,10,0”/>
<Button x:Name=”connectButton” Click=”connectButton_Click”>Connect</Button>
</StackPanel>
</DockPanel>
</Window>
But I can't find the reference for AxMSTSCLib. I added MSTSCLib, but It does not like it. Where can I find AxMSTSCLib?
Imagine next situation: I do have application window with several usercontrols inside. They was displayed side by side in past, but now I want to show one of them in popup window. Not in Popup control but new Window.
See example XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<wpfApplication3:UserControl1 Visibility="Hidden"
x:Name="UserControl1"/>
<Button Click="ButtonBase_OnClick"
Width="100"
Height="60">open window</Button>
</Grid>
In code behind I need to deattach usercontrol from current Window and assign to new one:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var parent = VisualTreeHelper.GetParent(UserControl1);
if (parent != null)
{
parent.RemoveChild(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}
And after calling w.Show() I always getting blank white window.
If in button click handler change
Content = UserControl1
to
Content = new UserControl1()
I will get right content as well.
But I can't use this way because I want to keep my usercontrol state during pop-out and pop-in events.
So how can I show in new window existing usercontrol without recreating it?
I am not sure how you are calling RemoveChild on a DependencyObject as that method doesn't seem to exist. Note that VisualTreeHelper.GetParent returns a DependencyObject so, the code you posted should not compile unless you have an Extension method somewhere defining RemoveChild.
In your case what you want to do is cast your parent object to type Grid or Panel and then remove the UserControl from the Children property, then set your UserControl as the Content of your window.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Grid parent = VisualTreeHelper.GetParent(UserControl1) as Grid;
if (parent != null)
{
parent.Children.Remove(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}
There was a similar question asked here
that gives a very detailed answer.
The quick answer is that you will have to remove the control from the main window and then add it to the popup window.
I am facing one problem with input command key binding.
Here i explain my situation...
I have binded the input command key binding like below,
<Window x:Class="DefaultBehavior_KeyBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding Key="F2" Command="{Binding TestCommand}"/>
</Window.InputBindings>
<Grid>
<Button Content="Add" Width="100" Height="35" Grid.Row="0" Name="EmptyButton" Click="EmptyButton_Click"/>
</Grid>
It works fine. Then i opened the new wpf child window in button click event like below,
public partial class MainWindow : Window
{
public ICommand TestCommand { get; private set; }
public MainWindow()
{
this.TestCommand = ........some command is attached here...
InitializeComponent();
this.DataContext = this;
}
private void EmptyTabButton_Click(object sender, RoutedEventArgs e)
{
Window childwindow = new Window() { Title = "ChildWindow", Width = 200, Height = 300 };
childwindow.Show();
}
}
After opening the child window, the key binding to main window not working when child window is focused. If i switch the focus to main window means, it fine.
I know, both the main window and child window are independent to each other.
But my question is, how can i make it as work my child window is focussed when i binded the keybinding to main window only. i don't want to set this binding to each child window because in my case i am using lot of child windows.
Any one please provide your suggestion to me?
The key bindings will only work if the Form is focused.
You could redirect every Command in your new Window to the Main Window
Change your Constructor to of the new Window to accept a Main Window and save this window:
MainWindow mainWindow;
public Window(MainWindow w)
{
mainWindow = w;
}
Whenever a Keybinding executes just do something like this:
mainWindow.TabPress();
And show the Window with
Window childwindow = new Window(this) { Title = "ChildWindow", Width = 200, Height = 300 };
childwindow.Show();
Can you try setting the Input Bindings in Window style (that should defined in App.xaml), so that it will apply to all Window objects.
This code is NOT TESTED! (but it should work anyways :D)
You could add the InputBindings from the MainWindow to the childwindows InputBindingCollection as follows:
private void EmptyTabButton_Click(object sender, RoutedEventArgs e)
{
Window childwindow = new Window() { Title = "ChildWindow", Width = 200, Height = 300 };
childWindow.InputBindings.AddRange(this.InputBindings);
childwindow.Show();
}
By doing so, the childwindow should react to your input and execute the commands from the MainWindow.
I am trying to add dynamic tabs to my application. Right now if I click a button, it will open a new page. What I want is to open this page in a new tab. But when I set up the tab content to a page , the code complains. I wanna do something like this
private void bttnGoToClientsOnClick(object sender, RoutedEventArgs e)
{
var content = new TextBlock();
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
tab.Content = sp;
tabControl.Items.Add(tab);
this.NavigationService.Navigate(sp);
}
is there any way I can convert my page to usercontrol or cast it as user control
Thank you!
But when I set up the tab content to a page , the code complains.
It wouldn't hurt if you were more specific here :)
What is SearchPage class? It doesn't seem to be the part of the WPF framework. I googled it up on the
http://www.intersoftpt.com/ website. Is that it?
TabItem.Content needs to be of ContentControl type, which SearchPage - apparently - is not. I'm sure you need to embed this SearchPage object in some control presenter, such as a panel, before you can assign it to TabItem.Content.
Update:
Try this, then:
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
this.NavigationService.Navigate(sp);
// ----------------------------------------------------
var frame = new Frame(); // !
frame.Navigate(sp); // !
tab.Content = frame; // !
// ----------------------------------------------------
tabControl.Items.Add(tab);
While I believe this should work, I haven't tested it. Please let me know if it doesn't do the trick.
You can always create your own UserControls, directly in the XAML definition (even if they are partial pages or windows).
In this example I assume that your SearchClass is defined in the [YourProject].Model namespace (where [YourProject] is the name of your project)
<UserControl x:Class="WpfApplication1.UserControl1"
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:search="clr-namespace:[YourProject].Model">
<search:SearchClass>
<!--<Grid>
...ANYTHING YOU WANT HERE ! ...
</Grid>-->
</search:SearchClass>
</UserControl>
Now you can create an instance of the UserControl, even in XAML or in code-behind (remember only to declare the namespaces correctly!):
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ctrls="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<UserControl1 />
</Grid>
</Window>
...and this my code-behind...
UserControl1 myControl = new UserControl1();
I have a very simple application where I'm trying to bind keyboard shortcuts to a WPF command that is bound to a menu item. The application itself consists of just a Menu and a WebBrowser control.
When I'm within the WebBrowser, the keyboard shortcuts are not routed up to the WPF Menu. For example, typing 'Ctrl+O' when focused in the web browser shows the IE open page. Additionally, in this application, unless I have the Menu focused (by typing in Alt) the input bindings don't fire. For example, I can't focus on the WPF window by clicking on the title bar and then type the shortcuts. The full code is replicated below:
MainWindow.xaml
<Window x:Class="TestInputBindingsOnMenu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu IsMainMenu="True" x:Name="_mainMenu" Grid.Row="0" />
<WebBrowser Source="http://google.com" Grid.Row="1" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TestInputBindingsOnMenu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
MenuItem fileMenu = new MenuItem();
MenuItem fileNew = new MenuItem();
MenuItem fileOpen = new MenuItem();
MenuItem fileExit = new MenuItem();
fileMenu.Header = "File";
fileNew.Header = "New";
fileOpen.Header = "Open";
fileExit.Header = "Exit";
fileMenu.Items.Add(fileNew);
fileMenu.Items.Add(fileOpen);
fileMenu.Items.Add(fileExit);
_mainMenu.Items.Add(fileMenu);
var fileNewCommand = CreateCommand("New");
var fileOpenCommand = CreateCommand("Open");
var fileExitCommand = CreateCommand("Exit");
_mainMenu.CommandBindings.Add(new CommandBinding(fileNewCommand, ExecuteNew));
_mainMenu.CommandBindings.Add(new CommandBinding(fileOpenCommand, ExecuteOpen));
_mainMenu.CommandBindings.Add(new CommandBinding(fileExitCommand, ExecuteExit));
fileNew.Command = fileNewCommand;
fileOpen.Command = fileOpenCommand;
fileExit.Command = fileExitCommand;
_mainMenu.InputBindings.Add(new InputBinding(fileNewCommand, new KeyGesture(Key.N, ModifierKeys.Control)));
_mainMenu.InputBindings.Add(new InputBinding(fileOpenCommand, new KeyGesture(Key.O, ModifierKeys.Control)));
_mainMenu.InputBindings.Add(new InputBinding(fileExitCommand, new KeyGesture(Key.F4, ModifierKeys.Alt)));
}
private void ExecuteNew(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("New!!");
}
private void ExecuteOpen(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Open!!");
}
private void ExecuteExit(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Exit!!");
}
private static RoutedCommand CreateCommand(string label)
{
return new RoutedCommand(label, typeof(MainWindow));
}
}
}
Easy Solution
Add the input bindings to the WebBrowser control as well as the main menu:
Browser.InputBindings.Add(new KeyBinding(ApplicationCommands.Open,
new KeyGesture(Key.O, ModifierKeys.Control)));
Hard Solution
What is happening here is that the UIElement is using the KeyDown event, while you want to use PreviewKeyDown event, or add a handler that also handles Handled routed events. Look up Tunnelling and Bubbling if you don't know about this.
Since this is handled in the UIElement class, I would advise using a different pattern in this situation. The MVVM Light framework provides an EventToCommand behavior. If you can route the PreviewKeyDown event of the window to the right commands instead of using KeyBinding with the InputBindings collection of the UIElement you will have your solution.
You will need some custom code to check which key was pressed and to which command the routing should be.