【发布时间】:2019-02-21 15:56:07
【问题描述】:
出于多种目的,我想在我的 WPF 应用程序中包含控制台窗口功能,包括:
- 屏幕记录
- 显示应用程序执行的控制台命令的结果
- 诊断
我使用的两种技术是:
- 创建一个
TextBox并通过赋值或数据绑定设置其Text属性。这很好地将视图集成到应用程序中,但随着文本“缓冲区”变大,会出现性能问题。 - 对
AllocConsole进行互操作调用以创建控制台窗口。对于相对较大的文本“缓冲区”没有性能问题,但被创建为顶级窗口(在视觉上与应用程序分开,具有自己的标题栏等)。
理想情况下,我想创建一个控制台窗口(如 AllocConsole)作为我的 WPF 应用程序窗口的子窗口,类似于将窗体窗口托管为 WPF 应用程序的子窗口的方式,以便它可以住在标签等中。
据我所知,一旦创建窗口,就无法更改其父窗口,创建新控制台窗口的唯一方法是 AllocConsole,它不带任何参数,因此父窗口(例如 Forms主机)无法指定。我错过了什么吗?
我的问题不是使用 TextBox、ListBox 等来近似/模拟类似控制台的行为,而是将实际的控制台窗口作为 WPF 应用程序的 GUI 元素托管。
编辑
我目前所处的位置:
XAML 主窗口片段:
<TabControl>
<TabItem Header="Log">
<Grid>
<WindowsFormsHost x:Name="FormsHost">
</WindowsFormsHost>
</Grid>
</TabItem>
</TabControl>
主窗口代码隐藏:
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
public partial class MainWindow : Window
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
public MainWindow()
{
InitializeComponent();
AllocConsole();
var newOut = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true };
Console.SetOut(newOut);
Console.SetError(newOut);
var ptr = GetConsoleWindow();
FormsHost.Child = new Control();
SetWindowLong(ptr, -16, GetWindowLong(ptr, -16) | 0x40000000);
SetParent(ptr, FormsHost.Child.Handle);
SetWindowPos(ptr, IntPtr.Zero, 0, 0, 300, 300, 0);
Console.WriteLine("Hello, World");
}
}
上面确实将控制台窗口带入了 WPF 选项卡,但它仍然具有顶级窗口的外观,并且在其宿主中仍然是可移动的。另外,虽然我可以在控制台区域右键单击以获取文本选择的上下文菜单,但我不能使用鼠标来选择文本。
更新
我通过更改解决了窗口样式的问题
SetWindowLong(ptr, -16, GetWindowLong(ptr, -16) | 0x40000000)
到
SetWindowLong(ptr, -16, 0x50000000)
并解决了窗口大小调整问题,但鼠标交互仍然存在问题 - 鼠标右键可以激活上下文菜单,但鼠标左键无法进行选择。
【问题讨论】:
-
@eocron 我一直在使用 TextBox 和/或其他 GUI 控件来模拟控制台窗口;他们似乎都有这样或那样的问题。这个问题的目的是探索在 WPF 父级中托管实际控制台窗口的可能性。
-
我见过很多这样使用的控件,我自己也有一个。将控制台附加到您的 WPF 应用程序在许多方面都是不明智的。
-
@eocron 我想更好地理解这些问题。请看我的相关问题stackoverflow.com/questions/54830047/…