如何将类似控制台的元素添加到c#winforms程序中
我有一个监控调试消息的程序,我曾尝试使用文本框并将消息附加到其中,但它的伸缩性不太好,当消息数量变大时,速度会减慢。然后,我尝试了一个列表框,但在添加新消息时,滚动条突然出现在顶部。它也不允许像文本框那样进行剪切和粘贴 实现winforms窗口中嵌入的类似控制台的元素的更好方法是什么 编辑: 我仍然希望能够嵌入一个像VisualStudio这样的输出窗口,但因为我不能找到一个简单的方法,这里有两个我使用的解决方案。 除了使用RichTextBox外,它还可以工作,但您必须时不时地清除它。我用一个我喜欢的控制台。下面是我编写的一个小包装器类来处理这个问题如何将类似控制台的元素添加到c#winforms程序中,c#,.net,winforms,C#,.net,Winforms,我有一个监控调试消息的程序,我曾尝试使用文本框并将消息附加到其中,但它的伸缩性不太好,当消息数量变大时,速度会减慢。然后,我尝试了一个列表框,但在添加新消息时,滚动条突然出现在顶部。它也不允许像文本框那样进行剪切和粘贴 实现winforms窗口中嵌入的类似控制台的元素的更好方法是什么 编辑: 我仍然希望能够嵌入一个像VisualStudio这样的输出窗口,但因为我不能找到一个简单的方法,这里有两个我使用的解决方案。 除了使用RichTextBox外,它还可以工作,但您必须时不时地清除它。我用一个
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Con
{
class Ext_Console
{
static bool console_on = false;
public static void Show(bool on,string title)
{
console_on = on;
if (console_on)
{
AllocConsole();
Console.Title = title;
// use to change color
Console.BackgroundColor = System.ConsoleColor.White;
Console.ForegroundColor = System.ConsoleColor.Black;
}
else
{
FreeConsole();
}
}
public static void Write(string output)
{
if (console_on)
{
Console.Write(output);
}
}
public static void WriteLine(string output)
{
if (console_on)
{
Console.WriteLine(output);
}
}
[DllImport("kernel32.dll")]
public static extern Boolean AllocConsole();
[DllImport("kernel32.dll")]
public static extern Boolean FreeConsole();
}
}
// example calls
Ext_Console.Write("console output ");
Ext_Console.WriteLine("console output");
Ext_Console.Show(true,"Title of console");
将列表框的selectedindex设置为最后一个元素,使其滚动到底部
另外,将列表框中的项目数量限制在合理的范围内(从顶部删除,保留后面的项目),这样您就不会占用所有的内存。 而且它可以很好地处理大文本。
我相信它最适合你的需要。我以前用过文本框。将其添加到表单中,将Multiline属性设置为true,将滚动条设置为垂直。 最后添加以下代码:
private void AddConsoleComment(string comment)
{
textBoxConsole.Text += comment + System.Environment.NewLine;
textBoxConsole.Select(textBoxConsole.Text.Length,0);
textBoxConsole.ScrollToCaret();
}
本质上,它是将您的注释添加到现有文本中,并附加一个换行符。最后选择长度为0的文本的最后一位。ScrollToCaret强制文本框向下滚动到光标所在的位置(最后一行)
希望这能有所帮助。我遇到了这个挑战。我用两种不同的方法解决了这个问题,一种是在重负荷下工作,另一种是在重负荷下工作。一种方法是使用ListView。添加一行文本如下所示:
ListViewItem itm = new ListViewItem();
itm.Text = txt;
this.listView1.Items.Add(itm);
this.listView1.EnsureVisible(listView1.Items.Count - 1);
另一种方法是在虚拟模式下使用DataGridView。我手头没有那个代码。虚拟模式是你的朋友
编辑:重新阅读,我看到您希望复制/粘贴工作。也许RichText控件的性能还可以-不知道,但是如果使用ListView或DataGrid,则必须进行更多的编码才能使复制/粘贴工作正常。我在使用Win32控制台窗口的C#window程序(WInforms或WPF)中执行此操作。我有一个小类,它封装了一些基本的Win32 API,当程序开始时,我会创建一个控制台。这只是一个例子:在“现实生活”中,您会使用一个设置或其他东西来仅在需要时启用控制台
using System;
using System.Windows.Forms;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using MWin32Api;
namespace WFConsole
{
static class Program
{
static private SafeFileHandle ConsoleHandle;
/// <summary>
/// Initialize the Win32 console for this process.
/// </summary>
static private void InitWin32Console()
{
if ( !K32.AllocConsole() ) {
MessageBox.Show( "Cannot allocate console",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
IntPtr handle = K32.CreateFile(
"CONOUT$", // name
K32.GENERIC_WRITE | K32.GENERIC_READ, // desired access
K32.FILE_SHARE_WRITE | K32.FILE_SHARE_READ, // share access
null, // no security attributes
K32.OPEN_EXISTING, // device already exists
0, // no flags or attributes
IntPtr.Zero ); // no template file.
ConsoleHandle = new SafeFileHandle( handle, true );
if ( ConsoleHandle.IsInvalid ) {
MessageBox.Show( "Cannot create diagnostic console",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
//
// Set the console screen buffer and window to a reasonable size
// 1) set the screen buffer sizse
// 2) Get the maximum window size (in terms of characters)
// 3) set the window to be this size
//
const UInt16 conWidth = 256;
const UInt16 conHeight = 5000;
K32.Coord dwSize = new K32.Coord( conWidth, conHeight );
if ( !K32.SetConsoleScreenBufferSize( ConsoleHandle.DangerousGetHandle(), dwSize ) ) {
MessageBox.Show( "Can't get console screen buffer information.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
K32.Console_Screen_Buffer_Info SBInfo = new K32.Console_Screen_Buffer_Info();
if ( !K32.GetConsoleScreenBufferInfo( ConsoleHandle.DangerousGetHandle(), out SBInfo ) ) {
MessageBox.Show( "Can't get console screen buffer information.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
return;
}
K32.Small_Rect sr; ;
sr.Left = 0;
sr.Top = 0;
sr.Right = 132 - 1;
sr.Bottom = 51 - 1;
if ( !K32.SetConsoleWindowInfo( ConsoleHandle.DangerousGetHandle(), true, ref sr ) ) {
MessageBox.Show( "Can't set console screen buffer information.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
IntPtr conHWND = K32.GetConsoleWindow();
if ( conHWND == IntPtr.Zero ) {
MessageBox.Show( "Can't get console window handle.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
if ( !U32.SetForegroundWindow( conHWND ) ) {
MessageBox.Show( "Can't set console window as foreground.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error );
return;
}
K32.SetConsoleTitle( "Test - Console" );
Trace.Listeners.Add( new ConsoleTraceListener() );
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
InitWin32Console();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
Application.Run( new Main() );
}
}
}
using System;
using System.Runtime.InteropServices;
namespace MWin32Api
{
#region Kernel32 Functions
//--------------------------------------------------------------------------
/// <summary>
/// Functions in Kernel32.dll
/// </summary>
public sealed class K32
{
#region Data Structures, Types and Constants
//----------------------------------------------------------------------
// Data Structures, Types and Constants
//
[StructLayout( LayoutKind.Sequential )]
public class SecurityAttributes
{
public UInt32 nLength;
public UIntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout( LayoutKind.Sequential, Pack = 1, Size = 4 )]
public struct Coord
{
public Coord( UInt16 tx, UInt16 ty )
{
x = tx;
y = ty;
}
public UInt16 x;
public UInt16 y;
}
[StructLayout( LayoutKind.Sequential, Pack = 1, Size = 8 )]
public struct Small_Rect
{
public Int16 Left;
public Int16 Top;
public Int16 Right;
public Int16 Bottom;
public Small_Rect( short tLeft, short tTop, short tRight, short tBottom )
{
Left = tLeft;
Top = tTop;
Right = tRight;
Bottom = tBottom;
}
}
[StructLayout( LayoutKind.Sequential, Pack = 1, Size = 24 )]
public struct Console_Screen_Buffer_Info
{
public Coord dwSize;
public Coord dwCursorPosition;
public UInt32 wAttributes;
public Small_Rect srWindow;
public Coord dwMaximumWindowSize;
}
public const int ZERO_HANDLE_VALUE = 0;
public const int INVALID_HANDLE_VALUE = -1;
#endregion
#region Console Functions
//----------------------------------------------------------------------
// Console Functions
//
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern bool AllocConsole();
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern bool SetConsoleScreenBufferSize(
IntPtr hConsoleOutput,
Coord dwSize );
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern bool GetConsoleScreenBufferInfo(
IntPtr hConsoleOutput,
out Console_Screen_Buffer_Info lpConsoleScreenBufferInfo );
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern bool SetConsoleWindowInfo(
IntPtr hConsoleOutput,
bool bAbsolute,
ref Small_Rect lpConsoleWindow );
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern IntPtr GetConsoleWindow();
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern bool SetConsoleTitle(
string Filename );
#endregion
#region Create File
//----------------------------------------------------------------------
// Create File
//
public const UInt32 CREATE_NEW = 1;
public const UInt32 CREATE_ALWAYS = 2;
public const UInt32 OPEN_EXISTING = 3;
public const UInt32 OPEN_ALWAYS = 4;
public const UInt32 TRUNCATE_EXISTING = 5;
public const UInt32 FILE_SHARE_READ = 1;
public const UInt32 FILE_SHARE_WRITE = 2;
public const UInt32 GENERIC_WRITE = 0x40000000;
public const UInt32 GENERIC_READ = 0x80000000;
[DllImport( "kernel32.dll", SetLastError = true )]
public static extern IntPtr CreateFile(
string Filename,
UInt32 DesiredAccess,
UInt32 ShareMode,
SecurityAttributes SecAttr,
UInt32 CreationDisposition,
UInt32 FlagsAndAttributes,
IntPtr TemplateFile );
#endregion
#region Win32 Miscelaneous
//----------------------------------------------------------------------
// Miscelaneous
//
[DllImport( "kernel32.dll" )]
public static extern bool CloseHandle( UIntPtr handle );
#endregion
//----------------------------------------------------------------------
private K32()
{
}
}
#endregion
//--------------------------------------------------------------------------
/// <summary>
/// Functions in User32.dll
/// </summary>
#region User32 Functions
public sealed class U32
{
[StructLayout( LayoutKind.Sequential )]
public struct Rect
{
public Int32 Left;
public Int32 Top;
public Int32 Right;
public Int32 Bottom;
public Rect( short tLeft, short tTop, short tRight, short tBottom )
{
Left = tLeft;
Top = tTop;
Right = tRight;
Bottom = tBottom;
}
}
[DllImport( "user32.dll" )]
public static extern bool GetWindowRect(
IntPtr hWnd,
[In][MarshalAs( UnmanagedType.LPStruct )]Rect lpRect );
[DllImport( "user32.dll", SetLastError = true )]
public static extern bool SetForegroundWindow(
IntPtr hWnd );
//----------------------------------------------------------------------
private U32()
{
}
} // U32 class
#endregion
} // MWin32Api namespace
使用系统;
使用System.Windows.Forms;
使用Microsoft.Win32.SafeHandles;
使用系统诊断;
使用MWin32Api;
命名空间控制台
{
静态类程序
{
静态私有安全文件句柄控制台句柄;
///
///为此进程初始化Win32控制台。
///
静态私有void InitWin32Console()
{
如果(!K32.alloconsole()){
MessageBox.Show(“无法分配控制台”,
“错误”,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
返回;
}
IntPtr handle=K32.CreateFile(
“CONOUT$”,//名称
K32.GENERIC_WRITE | K32.GENERIC_READ,//所需访问
K32.FILE_SHARE_WRITE | K32.FILE_SHARE_READ,//共享访问
null,//没有安全属性
K32.OPEN_EXISTING,//设备已存在
0,//没有标志或属性
IntPtr.Zero);//没有模板文件。
ConsoleHandle=新的SafeFileHandle(handle,true);
if(ConsoleHandle.IsInvalid){
MessageBox.Show(“无法创建诊断控制台”,
“错误”,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
返回;
}
//
//将控制台屏幕缓冲区和窗口设置为合理大小
//1)设置屏幕缓冲区大小
//2)获取最大窗口大小(以字符为单位)
//3)将窗口设置为此大小
//
const UInt16 conWidth=256;
const UInt16 conHeight=5000;
K32.Coord dwSize=新的K32.Coord(conWidth,conHeight);
如果(!K32.SetConsoleScreenBufferSize(ConsoleHandle.DangerousGetHandle(),dwSize)){
MessageBox.Show(“无法获取控制台屏幕缓冲区信息。”,
“错误”,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
返回;
}
K32.Console\u Screen\u Buffer\u Info SBInfo=新的K32.Console\u Screen\u Buffer\u Info();
如果(!K32.GetConsoleScreenBufferInfo(ConsoleHandle.DangerousGetHandle(),out SBInfo)){
MessageBox.Show(“无法获取控制台屏幕缓冲区信息。”,
“错误”,
MessageBoxButtons.OK,
MessageBoxIcon.感叹号);
返回;
}
K32.Small_Rect sr;
sr.Left=0;
sr.Top=0;
sr.Right=132-1;
sr.Bottom=51-1;
如果(!K32.SetConsoleWindowInfo(ConsoleHandle.DangerousGetHandle(),true,ref sr)){
MessageBox.Show(“无法设置控制台屏幕缓冲区信息”,
“错误”,
安魂曲
void AddLogMessage(String message)
{
list.Items.Add(message);
// DO: Append message to file as needed
// Clip the list
if (list.count > ListMaxSize)
{
list.Items.RemoveRange(0, list.Count - listMinSize);
}
// DO: Focus the last item on the list
}
public class ConsoleTextBox: TextBox
{
private List<string> contents = new List<string>();
private const int MAX = 50;
public void WriteLine(string input)
{
if (contents.Count == MAX)
contents.RemoveAt(MAX-1);
contents.Insert(0, input);
Rewrite();
}
private void Rewrite()
{
var sb = new StringBuilder();
foreach (var s in contents)
{
sb.Append(s);
sb.Append(Environment.NewLine);
}
this.Text = sb.ToString();
}
}