【问题标题】:Embed a Console Window inside a WPF Window在 WPF 窗口中嵌入控制台窗口
【发布时间】:2011-03-18 02:29:18
【问题描述】:

是否可以在 WPF 窗口中嵌入控制台窗口?

作为一点背景知识,起初,我尝试在 WPF 中从头开始实现一个控制台窗口,除了一个巨大的问题外,它很成功——它非常慢。在此处查看问题:
VT100 Terminal Emulation in Windows WPF or Silverlight

由于这似乎不是一个选项,我转而考虑在我的 WPF 应用程序中托管一个实际的控制台窗口,我已经学会了如何按照此处所述进行操作:

No output to console from a WPF application?

这很好,但理想情况下,我希望该控制台窗口看起来像是 WPF 应用程序其余部分的一部分。我知道使用 WinForms 应用程序是可能的,正如我所看到的那样,涉及使用 SetParent Win32 API。您可以看到一个示例 .NET 项目,该项目使用将控制台窗口嵌入到 shell 中的 CommandBar 项目来执行此操作:

http://www.codeproject.com/KB/cs/commandbar.aspx

所以我希望它也可以用 WPF 来完成,但我不知道你会怎么做。非常感谢您的帮助(另外,如果您对我在 WPF 中从头开始创建终端窗口的原始问题有任何出色的解决方案,因为这也可以解决我的需求)。

更新:

在 Reed Copsey 的帮助下,我能够嵌入控制台窗口。但是,当然需要对其进行样式设置和移动,否则它看起来就像 WPF 窗口中的常规控制台窗口。我需要删除标题栏和大边框。做研究我想出了如何使用 Win32 API 来做到这一点:

uint style = GetWindowLong(ConsoleManager.ConsoleWindowHandle, GWL_STYLE);
style &= ~(uint)WindowStyles.WS_CAPTION;
style &= ~(uint)WindowStyles.WS_THICKFRAME;
style &= ~(uint)WindowStyles.WS_DLGFRAME;
style &= ~(uint)WindowStyles.WS_POPUP;
SetWindowLong(ConsoleManager.ConsoleWindowHandle, GWL_STYLE, style);
MoveWindow(ConsoleManager.ConsoleWindowHandle, 0, 0, (int)WindowsFormsHost.ActualWidth, (int)WindowsFormsHost.ActualHeight, true);

但是,有一个大问题。出于某种原因,控制台窗口有一个渲染工件。就好像它没有在左下角和右上角重绘自己。工件的宽度类似于标题栏和粗边框的宽度,实际上,如果我离开粗边框,工件的大小会下降。但简单地重新粉刷它不会有帮助,因为它会重新出现。例如,我可以将窗口从屏幕上移开并再次返回以修复它,但它很快就会自行重新出现:

rendering artifact http://img837.imageshack.us/img837/6241/renderissue.png

更新 2: 即使我没有将其作为 WindowsFormsHost 控件的父级,效果也会发生。重现它所需要做的就是启动控制台(使用 AllocConsole()),然后使用 SetWindowLong 删除其标题栏。这是win7机器。

更新 3: 似乎不支持像这样与其他窗口“混淆”。假设有标题,控制台窗口会计算其文本区域,所以没有办法解决这个问题。我认为在 WPF 中获得类似控制台行为的唯一选择是编写自定义 WinForms 控件,然后将其嵌入 WPF。

【问题讨论】:

  • 你成功完成了这件事吗?
  • @ShawnMclean 不......更新代表了整个故事:(
  • 您可能会查看 Console2(后来分叉为 ConsoleZ)程序。他们成功地在没有标题/标题的选项卡控件中托管了一系列命令提示符。
  • 你是如何将它嵌入到 WPF 中的?接受了 Reed Copsey 的建议并尝试使用 HwndHost,但我失败了。
  • @InfinitiesLoop 嘿,使用 UPDATE 中的代码,我的 cmd 控制台会正确调整大小,但在调用 WIN32API.SetParent(cmdProcess.MainWindowHandle, panel.Handle) 然后将面板分配到 WindowsFormsHost.Child = panel` 后,我的控制台不会出现在WindowsFormsHost 的面板。我需要做更多的事情吗?

标签: .net wpf console console-application


【解决方案1】:

除了Reed Copsey 关于在 WPF 应用程序中嵌入控制台窗口的出色建议之外,另一种非常容易实现的策略是简单地通过 Process 类发出命令并将两个流重定向到本机WPF 文本块。这是截图...

此 WPF 应用程序(连接到“exe”文件的 Windows 资源管理器上下文菜单)执行程序并将结果通过管道传输到相应的窗口。

它旨在帮助您在想要运行控制台实用程序时提供帮助,当您单击它时,该实用程序会在控制台窗口中快速运行,而您永远无法看到发生了什么。它还连接到“csproj”文件以从资源管理器对它们运行 MSBuild。

关键是有时自己做比尝试托管控制台窗口更容易且更具可扩展性...

这个应用程序的内部使用这个类...

public class ProcessPiper
{
    public string StdOut { get; private set; }
    public string StdErr { get; private set; }
    public string ExMessage { get; set; }
    public void Start(FileInfo exe, string args, Action<ProcessPiper>onComplete)
    {
        ProcessStartInfo psi = new ProcessStartInfo(exe.FullName, args);
        psi.RedirectStandardError = true;
        psi.RedirectStandardOutput = true;
        psi.UseShellExecute = false;
        psi.WorkingDirectory = Path.GetDirectoryName(exe.FullName);
        Task.Factory.StartNew(() =>
            {
                try
                {
                    ExMessage = string.Empty;
                    Process process = new Process();
                    process.StartInfo = psi;
                    process.Start();
                    process.WaitForExit();
                    StdOut = process.StandardOutput.ReadToEnd();
                    StdErr = process.StandardError.ReadToEnd();
                    onComplete(this);
                }
                catch (Exception ex)
                {
                    ExMessage = ex.Message;
                }
            });
    }
}

此类执行命名的“exe”文件并捕获输出,然后调用视图模型。整个编码练习大约需要一个小时左右...

Process 类的文档在这里:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx

【讨论】:

  • 这种方法不适用于交互式控制台应用程序或显示程序的实时输出。
【解决方案2】:

您应该能够使用与您展示的 Windows 窗体应用程序相同的技术,方法是重新设置为 HwndHost。您甚至可以只修改 Windows 窗体代码,并将其直接放入 WindowsFormsHost 控件中。

【讨论】:

  • 不可能那么容易吧? :) 我这样做了: SetParent(ConsoleManager.ConsoleWindowHandle, WindowsFormsHost.Handle);但是控制台窗口没有出现..一旦它被重新设置它就消失了。有什么想法吗?
  • 尝试在您的 WindowsFormsHost 控件中放置一个(Windows 窗体)面板,并将父级设置为面板的句柄(而不是控件本身)。
  • 你知道我认为它正在工作,只是窗口有时在父级中看不见。接下来我需要弄清楚如何将两者的大小绑定在一起并隐藏标题栏等。你帮了很多忙,谢谢:)
  • Reed -- 请参阅我对上述问题的更新。使用此技术的控制台窗口出现渲染问题:|
  • @InfinitiesLoop:尝试在您的 Windows 窗体控件上将 owner draw 设置为 true。这可能有助于它接收正确的消息...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 2010-10-03
  • 1970-01-01
相关资源
最近更新 更多