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?
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.
I'm trying to implement Drag & Drop with files on a ListBox which is contained in a Window of an Avalonia project.
As I couldn't get it working and I thought that ListBox perhaps is a special case, I tried to make a similar example like the one from ControlCatalogStandalone.
While the code in ControlCatalogStandalone works as expected, virtually the same code in my test application doesn't work properly.
The relevant code in ControlCatalogStandalone belongs to a UserControl, where in my application it belongs to the MainWindow. Could this be the cause for the misbehavior?
I created a new Avalonia MVVM Application based on the NuGet packages 0.9.11 in Visual Studio 2019.
I also tried version 0.10.0-preview2 in vain.
This is the XAML file:
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:DragAndDropTests.ViewModels;assembly=DragAndDropTests"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="400" Height="200"
x:Class="DragAndDropTests.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico"
Title="DragAndDropTests">
<Design.DataContext>
<vm:MainWindowViewModel/>
</Design.DataContext>
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Drag+Drop</TextBlock>
<TextBlock Classes="h2">Example of Drag+Drop capabilities</TextBlock>
<StackPanel Orientation="Horizontal"
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
<Border BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="2" Padding="16" Name="DragMe">
<TextBlock Name="DragState">Drag Me</TextBlock>
</Border>
<Border Background="{DynamicResource ThemeAccentBrush2}" Padding="16"
DragDrop.AllowDrop="True">
<TextBlock Name="DropState">Drop some text or files here</TextBlock>
</Border>
</StackPanel>
</StackPanel>
</Window>
And this is the Code Behind:
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using System;
using System.Diagnostics;
namespace DragAndDropTests.Views
{
public class MainWindow : Window
{
private TextBlock _DropState;
private TextBlock _DragState;
private Border _DragMe;
private int DragCount = 0;
public MainWindow()
{
Debug.WriteLine("MainWindow");
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
_DragMe.PointerPressed += DoDrag;
AddHandler(DragDrop.DropEvent, Drop);
AddHandler(DragDrop.DragOverEvent, DragOver);
}
private async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
{
Debug.WriteLine("DoDrag");
DataObject dragData = new DataObject();
dragData.Set(DataFormats.Text, $"You have dragged text {++DragCount} times");
var result = await DragDrop.DoDragDrop(e, dragData, DragDropEffects.Copy);
switch (result)
{
case DragDropEffects.Copy:
_DragState.Text = "The text was copied"; break;
case DragDropEffects.Link:
_DragState.Text = "The text was linked"; break;
case DragDropEffects.None:
_DragState.Text = "The drag operation was canceled"; break;
}
}
private void DragOver(object sender, DragEventArgs e)
{
Debug.WriteLine("DragOver");
// Only allow Copy or Link as Drop Operations.
e.DragEffects = e.DragEffects & (DragDropEffects.Copy | DragDropEffects.Link);
// Only allow if the dragged data contains text or filenames.
if (!e.Data.Contains(DataFormats.Text) && !e.Data.Contains(DataFormats.FileNames))
e.DragEffects = DragDropEffects.None;
}
private void Drop(object sender, DragEventArgs e)
{
Debug.WriteLine("Drop");
if (e.Data.Contains(DataFormats.Text))
_DropState.Text = e.Data.GetText();
else if (e.Data.Contains(DataFormats.FileNames))
_DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames());
}
private void InitializeComponent()
{
Debug.WriteLine("InitializeComponent");
AvaloniaXamlLoader.Load(this);
_DropState = this.Find<TextBlock>("DropState");
_DragState = this.Find<TextBlock>("DragState");
_DragMe = this.Find<Border>("DragMe");
}
}
}
Drag & Drop within the application works well in ControlCatalogStandalone and in my application.
The succession of events is DoDrag, DragOver, DragOver, …, Drop in this case.
Dragging a file from Windows Explorer to the ControlCatalogStandalone works well.
The succession of events is DragOver, DragOver, …, Drop
Dragging a file from Windows Explorer to my application doesn't work.
None of the expected events is called here.
What's wrong with my test application?
I need help from someone who work in C#. I'm trying to achieve WPF application that open internet explorer on URL that i supplement him as a parameter. So in perfect world i would like run something like this:
\\path\window.exe X x Y "URL" "Title"
Where X,Y is windows height and width, URL and Title is a title of that window. My knowledge of C# is nonexistent so after extensive use of google i manage to get this XAML:
<Window x:Class="WPFWebControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="My Web Browser" WindowState="Normal" Loaded="Window_Loaded" WindowStyle="ThreeDBorderWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="Auto" Width="Auto">
<Grid>
<WebBrowser Height="Auto" HorizontalAlignment="Left" Margin="0,28,0,0" Name="MyWebBrowser" VerticalAlignment="Top" Width="Auto" LoadCompleted="MyWebBrowser_LoadCompleted" />
<TextBox Height="23" Margin="40,5,0,0" Name="MyTextBox" VerticalAlignment="Top" HorizontalAlignment="Left" Width="708" />
<Button Content="Go" Margin="10,5,0,476" Name="MyGo" ToolTip="Go" Click="MyGo_Click" RenderTransformOrigin="-0.76,0.565" HorizontalAlignment="Left" Width="25" />
</Grid>
</Window>
and this C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WPFWebControl
{ /// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
MyWebBrowser.Source = new Uri("http://www.google.com");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void MyGo_Click(object sender, RoutedEventArgs e)
{
try
{
MyWebBrowser.Source = new Uri("http://" + MyTextBox.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void MyWebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{}
}
}
Now i need some advice how can i set window size, url and title via parameters so i can get rid of that address textbox and button.
You could open a new window and set a WebBrowser as its Content, e.g.:
WebBrowser browser = new WebBrowser();
Window win = new Window();
win.Content = browser;
win.Height = 100;
win.Width = 100;
win.Show();
win.Title = "title...";
browser.Navigate("http://google.com");
If you want your application to be able to accept command line arguments, you could remove the StartupUri attribute from your App.xaml and override the OnStartup method of your App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
double width = Convert.ToDouble(e.Args[0]);
double height = Convert.ToDouble(e.Args[1]);
string title = e.Args[2];
string url = e.Args[3];
WebBrowser browser = new WebBrowser();
Window win = new Window();
win.Content = browser;
win.Height = height;
win.Width = width;
win.Show();
win.Title = title;
browser.Navigate(new Uri(url, UriKind.Absolute));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Usage:
WpfApplication1.exe 100 100 "title..." "http://google.com"
You should be able to use
string[] args = Environment.GetCommandLineArgs();
Or, change teh startup uri in App.xaml (remove it) and instead create your own startup like
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
//Manually create and show your window, passing the arguments
}
}
etc
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
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.