我正在尝试在程序主窗口内的面板中托管/运行Exe应用程序。主窗口有一个有3列的网格 - 两列用一个垂直网格分割器均匀分割,以分割左右列。左列有一个制表符控件,但是右列是我想要将exe应用程序放在其中的,并且基本上让应用程序根据右列内的dock调整大小。
我以与Hosting external app in WPF window类似的方式构建了程序。这个例子比我将用于exe和附加功能的例子简单得多,但这个例子应该解释我当前的问题。
我可以在窗口中启动exe,但不能在右侧列中的Dockpanel或任何其他控件内启动。 exe放置在窗口内部静态放置在窗口内部而不是放置在列内部。我可以进入并更改进程窗口的起始位置,使其实际打开在右列的顶部,并且看起来位于该列的停靠面板内,但同样它只是静态的。
我看到的所有示例都是在窗口内放置一个进程,而不是放在容器中。我已经尝试将WindowsInteropHelper设置为停靠面板,但它仍然只是将其发送到主窗口。
var helper = new WindowInteropHelper(GetWindow(this.ApplicationDock));
我也尝试了一些文章,包括下面的两篇,但仍然没有找到我正在寻找的解决方案。
How can I run another application within a panel of my C# program?
Docking Window inside another Window
我想到的一种可能性是,在窗口更改时更新过程窗口处理程序,使其位于右列开始位置的正确坐标处。对我而言,这似乎应该是最后的手段,而不是处理这个问题的正确方法。
我的主要申请
<Window x:Class="ProgramInProgram.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:local="clr-namespace:ProgramInProgram"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0">
<TabItem Header="Blue Tab">
<Grid Background="Blue"></Grid>
</TabItem>
<TabItem Header="Red Tab" >
<Grid Background="Red"></Grid>
</TabItem>
</TabControl>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<DockPanel Grid.Column="2" x:Name="ApplicationDock">
</DockPanel>
</Grid>
</Window>
背后的守则
public partial class MainWindow : Window
{
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int uFlags);
private Process process;
private const int SWP_ZOZORDER = 0x0004;
private const int SWP_NOACTIVATE = 0x0010;
private const int GWL_STYLE = (-16);
private const int WS_CAPTION = 0x00C00000;
private const int WS_VISIBLE = 0x10000000;
private const int WS_THICKFRAME = 0x00040000;
const string patran = "patran";
public MainWindow()
{
InitializeComponent();
Loaded += (s, e) => LaunchChildProcess();
}
private void LaunchChildProcess()
{
this.process = Process.Start("Notepad.exe");
this.process.WaitForInputIdle();
var helper = new WindowInteropHelper(GetWindow(this.ApplicationDock));
SetParent(this.process.MainWindowHandle, helper.Handle);
int style = GetWindowLong(this.process.MainWindowHandle, GWL_STYLE);
style = style & ~WS_CAPTION & ~WS_THICKFRAME;
SetWindowLong(this.process.MainWindowHandle, GWL_STYLE, style);
ResizeEmbeddedApp();
}
private void ResizeEmbeddedApp()
{
if (this.process == null)
{
return;
}
UIElement container = VisualTreeHelper.GetParent(this.ApplicationDock) as UIElement;
Point relativeLocation = this.ApplicationDock.TranslatePoint(new Point(0, 0), container);
}
protected override Size MeasureOverride(Size availableSize)
{
Size size = base.MeasureOverride(availableSize);
ResizeEmbeddedApp();
return size;
}
}
答案 0 :(得分:0)
我有同样的需求,因为我的客户想要一个运行4个wpf应用的仪表板。我相信这应该有所帮助,顺便说一句,如果有人知道更好的方法来构建一个Windows应用程序仪表板,我很乐意听到它。关键是使用windowsformhost。
string exeName = @"C:\Repos\OnSpot17\OnTheSpot\bin\Debug\OnTheSpot.exe";
var procInfo = new System.Diagnostics.ProcessStartInfo(exeName);
procInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(exeName);
procInfo.WindowStyle = ProcessWindowStyle.Minimized;
// Start the process
_childp = Process.Start(procInfo);
System.Windows.Forms.Panel _pnlSched = new System.Windows.Forms.Panel();
WindowsFormsHost windowsFormsHost1 = new WindowsFormsHost();
windowsFormsHost1.Child = _pnlSched;
test.Children.Add(windowsFormsHost1);
// Wait for process to be created and enter idle condition
// _childp.WaitForInputIdle();
// The main window handle may be unavailable for a while, just wait for it
while (_childp.MainWindowHandle == IntPtr.Zero)
{
Thread.Yield();
}
// Get the main handle
_appWin = _childp.MainWindowHandle;
// PR.WaitForInputIdle(); // true if the associated process has reached an idle state.
SetParent(_appWin, _pnlSched.Handle); // loading exe to the wpf window.