在 WPF 視窗中嵌入控制台視窗
是否可以在 WPF 視窗中嵌入控制台視窗?
作為一點背景知識,起初,我嘗試在 WPF 中從頭開始實現一個控制台視窗,除了一個大問題外,它是成功的——它非常慢。請參閱此處的問題:
Windows WPF 或 Silverlight 中的 VT100 終端仿真
由於這似乎不是一個選項,我轉而考慮在我的 WPF 應用程序中託管一個實際的控制台視窗,我已經學會瞭如何按照此處所述進行操作:
這很好,但理想情況下,我希望該控制台視窗看起來像是 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);但是,有一個大問題。出於某種原因,控制台視窗有一個渲染工件。就好像它沒有在左下角和右上角重繪自己。工件的寬度類似於標題欄和粗邊框的寬度,實際上,如果我離開粗邊框,工件的大小會下降。但簡單地重新粉刷它不會有幫助,因為它會重新出現。例如,我可以將視窗從螢幕上移開並再次移回以修復它,但它很快就會自行重新出現:
渲染神器 http://img837.imageshack.us/img837/6241/renderissue.png
**更新 2:**即使我沒有將其作為 WindowsFormsHost 控制項的父級,效果也會發生。重現它所需要做的就是啟動控制台(使用 AllocConsole()),然後使用 SetWindowLong 刪除其標題欄。這是win7機器。
**更新 3:**似乎不支持像這樣與其他視窗“混淆”。假設有標題,控制台視窗會計算其文本區域,所以沒有辦法解決這個問題。我認為在 WPF 中獲得類似控制台行為的唯一選擇是編寫一個自定義 WinForms 控制項,然後將其嵌入到 WPF 中。
您應該能夠使用與您通過重新設置為HwndHost顯示的 Windows 窗體應用程序相同的技術。您甚至可以調整 Windows 窗體程式碼,並將其直接放入WindowsFormsHost控制項。
除了Reed Copsey關於在 WPF 應用程序中嵌入控制台視窗的出色建議之外,另一種非常容易實現的替代策略是簡單地通過 Process 類發出命令並將兩個流重定向到本機 WPF TextBlocks。這是螢幕截圖…
此 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
