如何将类似控制台的元素添加到c#winforms程序中

时间:2022-08-31 20:34:56

I have a program that monitors debug messages and I have tried using a TextBox and appended the messages to it but it doesn't scale very well and slows way down when the number of messages gets large. I then tried a ListBox but the scrolling was snapping to the top when appending new messages. It also doesn't allow for cut and paste like the text box does.

我有一个程序来监视调试消息,我已经尝试使用TextBox并将消息附加到它但它不能很好地扩展,并在消息数量变大时减慢速度。然后我尝试了一个ListBox,但在添加新消息时,滚动正在捕捉到顶部。它也不允许像文本框那样剪切和粘贴。

What is a better way to implement a console like element embedded in a winforms window.

什么是实现类似控制台的更好方法,如winforms窗口中嵌入的元素。

Edit: I would still like to be able to embed a output window like visual studio but since I can't figure out an easy way here are the two solutions I use. In addition to using the RichTextBox which works but you have to clear it every now and then. I use a console that I pinvoke. Here is a little wrapper class that I wrote to handle this.

编辑:我仍然希望能够嵌入像visual studio这样的输出窗口,但由于我无法找到一个简单的方法,所以我使用的是两个解决方案。除了使用有效的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");


7 个解决方案

#1


10  

RichTextBox has an AppendText method that is fast. And it can handle large text well.
I believe it is the best for what you need.

RichTextBox有一个快速的AppendText方法。它可以很好地处理大文本。我相信这是你需要的最好的。

#2


5  

You can't just keep adding logging items to a WinForms control (ListBox or RichTextBox) -- it will eventually get clogged and start swapping to disk.

您不能只是继续将日志项添加到WinForms控件(ListBox或RichTextBox) - 它最终会被阻塞并开始交换到磁盘。

I had this exact bug at one point. The solution I had was to clip the list of displayed messages occasionally. In pseudocode, this is something like:

我曾经有过这个确切的错误。我的解决方案是偶尔剪辑显示的消息列表。在伪代码中,这类似于:

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
}

ListMaxSize should be substantially bigger than ListMinSize, so clipping does not happen too often. ListMinSize is the number of recent messages that you'd normally need to look through in your logging list.

ListMaxSize应该比ListMinSize大得多,因此剪切不会经常发生。 ListMinSize是您通常需要在日志记录列表中查看的最近消息的数量。

This is just pseudocode, there is actually no RemoveRange on ListBox item collection (but there is on List). You can figure out the exact code.

这只是伪代码,ListBox项目集合上实际上没有RemoveRange(但是List上有)。你可以找出确切的代码。

#3


4  

I do this in my C# window programs (WInforms or WPF) using a Win32 console window. I have a small class that wraps some basic Win32 APIs, thin I create a console when the program begins. This is just an example: in 'real life' you'd use a setting or some other thing to only enable the console when you needed it.

我在使用Win32控制台窗口的C#窗口程序(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

#4


2  

I've had this exact challenge. I've solved it two different ways, both work and perform will under heavy load. One way is with a ListView. Adding a line of text is like this:

我遇到了这个确切的挑战。我已经用两种不同的方式解决了这个问题,工作和执行都会在很重的情况下解决。一种方法是使用ListView。添加一行文字是这样的:

        ListViewItem itm = new ListViewItem();
        itm.Text = txt;
        this.listView1.Items.Add(itm);
        this.listView1.EnsureVisible(listView1.Items.Count - 1);

The other way is with a DataGridView in virtual mode. I don't have that code as handy. Virtual mode is your friend.

另一种方法是在虚拟模式下使用DataGridView。我没有那么方便的代码。虚拟模式是你的朋友。

EDIT: re-reading, I see you want copy/paste to work. Maybe the RichText control performs ok - don't know, but if you use the ListView or DataGrid, you'd have to do more coding to get Copy/Paste to work.

编辑:重新阅读,我看到你想复制/粘贴工作。也许RichText控件执行正常 - 不知道,但如果你使用ListView或DataGrid,你必须做更多的编码才能使复制/粘贴工作。

#5


1  

set the selectedindex of the listbox to the last element to make it scroll to the bottom

将列表框的selectedindex设置为最后一个元素,使其滚动到底部

also, limit the number of items in the listbox to something reasonable (delete from the top, keep the later items) so you don't chew up all of your memory

另外,将列表框中的项目数量限制在合理的范围内(从顶部删除,保留后面的项目),这样就不会扼杀所有的记忆

#6


1  

Ive previously used a textbox. Add it to your form, set Multipline property to true, Scrollbars to Vertical. And finally add this following code:

我以前用过一个文本框。将其添加到表单,将Multipline属性设置为true,将Scrollbars设置为Vertical。最后添加以下代码:

    private void AddConsoleComment(string comment)
    {
        textBoxConsole.Text += comment + System.Environment.NewLine;
        textBoxConsole.Select(textBoxConsole.Text.Length,0);
        textBoxConsole.ScrollToCaret();
    }

Essentially its adding your comment to the existing text, also appending a linefeed. And finally selecting last bit of text of length = 0. ScrollToCaret forces the textbox to scroll down to where the cursor is positioned (at the last line)

基本上它将您的评论添加到现有文本,也附加换行符。最后选择长度为0的文本的最后一位.ScrollToCaret强制文本框向下滚动到光标所在的位置(在最后一行)

Hope this helps.

希望这可以帮助。

#7


1  

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();
    }
}

#1


10  

RichTextBox has an AppendText method that is fast. And it can handle large text well.
I believe it is the best for what you need.

RichTextBox有一个快速的AppendText方法。它可以很好地处理大文本。我相信这是你需要的最好的。

#2


5  

You can't just keep adding logging items to a WinForms control (ListBox or RichTextBox) -- it will eventually get clogged and start swapping to disk.

您不能只是继续将日志项添加到WinForms控件(ListBox或RichTextBox) - 它最终会被阻塞并开始交换到磁盘。

I had this exact bug at one point. The solution I had was to clip the list of displayed messages occasionally. In pseudocode, this is something like:

我曾经有过这个确切的错误。我的解决方案是偶尔剪辑显示的消息列表。在伪代码中,这类似于:

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
}

ListMaxSize should be substantially bigger than ListMinSize, so clipping does not happen too often. ListMinSize is the number of recent messages that you'd normally need to look through in your logging list.

ListMaxSize应该比ListMinSize大得多,因此剪切不会经常发生。 ListMinSize是您通常需要在日志记录列表中查看的最近消息的数量。

This is just pseudocode, there is actually no RemoveRange on ListBox item collection (but there is on List). You can figure out the exact code.

这只是伪代码,ListBox项目集合上实际上没有RemoveRange(但是List上有)。你可以找出确切的代码。

#3


4  

I do this in my C# window programs (WInforms or WPF) using a Win32 console window. I have a small class that wraps some basic Win32 APIs, thin I create a console when the program begins. This is just an example: in 'real life' you'd use a setting or some other thing to only enable the console when you needed it.

我在使用Win32控制台窗口的C#窗口程序(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

#4


2  

I've had this exact challenge. I've solved it two different ways, both work and perform will under heavy load. One way is with a ListView. Adding a line of text is like this:

我遇到了这个确切的挑战。我已经用两种不同的方式解决了这个问题,工作和执行都会在很重的情况下解决。一种方法是使用ListView。添加一行文字是这样的:

        ListViewItem itm = new ListViewItem();
        itm.Text = txt;
        this.listView1.Items.Add(itm);
        this.listView1.EnsureVisible(listView1.Items.Count - 1);

The other way is with a DataGridView in virtual mode. I don't have that code as handy. Virtual mode is your friend.

另一种方法是在虚拟模式下使用DataGridView。我没有那么方便的代码。虚拟模式是你的朋友。

EDIT: re-reading, I see you want copy/paste to work. Maybe the RichText control performs ok - don't know, but if you use the ListView or DataGrid, you'd have to do more coding to get Copy/Paste to work.

编辑:重新阅读,我看到你想复制/粘贴工作。也许RichText控件执行正常 - 不知道,但如果你使用ListView或DataGrid,你必须做更多的编码才能使复制/粘贴工作。

#5


1  

set the selectedindex of the listbox to the last element to make it scroll to the bottom

将列表框的selectedindex设置为最后一个元素,使其滚动到底部

also, limit the number of items in the listbox to something reasonable (delete from the top, keep the later items) so you don't chew up all of your memory

另外,将列表框中的项目数量限制在合理的范围内(从顶部删除,保留后面的项目),这样就不会扼杀所有的记忆

#6


1  

Ive previously used a textbox. Add it to your form, set Multipline property to true, Scrollbars to Vertical. And finally add this following code:

我以前用过一个文本框。将其添加到表单,将Multipline属性设置为true,将Scrollbars设置为Vertical。最后添加以下代码:

    private void AddConsoleComment(string comment)
    {
        textBoxConsole.Text += comment + System.Environment.NewLine;
        textBoxConsole.Select(textBoxConsole.Text.Length,0);
        textBoxConsole.ScrollToCaret();
    }

Essentially its adding your comment to the existing text, also appending a linefeed. And finally selecting last bit of text of length = 0. ScrollToCaret forces the textbox to scroll down to where the cursor is positioned (at the last line)

基本上它将您的评论添加到现有文本,也附加换行符。最后选择长度为0的文本的最后一位.ScrollToCaret强制文本框向下滚动到光标所在的位置(在最后一行)

Hope this helps.

希望这可以帮助。

#7


1  

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();
    }
}