【问题标题】:Logging information to a windowed textbox将信息记录到窗口文本框
【发布时间】:2012-08-30 19:53:57
【问题描述】:

我正在努力将控制台应用程序转换为窗口格式,作为一个对此知之甚少但过去曾使用过窗口格式的类似应用程序的人,我认为这不会太难。

所以我创建了一个表单并在其中添加了一个文本框,只是为了获取日志记录信息。

这个控制台应用程序曾经在单线程中运行,此后我添加了第二个线程以允许表单与控制台并行运行以进行测试。 (现在也奇怪地在单线程中运行良好)。

这是我用来向表单写入文本的代码,只是我在表单上什么都没有。

    static Form1 f = new Form1();
    delegate void SetTextCallback(string s);

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the 
        // calling thread to the thread ID of the creating thread. 
        // If these threads are different, it returns true. 
        if (f.textBox1.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            f.textBox1.Invoke(d, new object[] { text });
        }
        else
        {
            f.textBox1.AppendText(text);
        }
    }

我可以确认有文本输入“文本”变量,但它没有进入表单。

任何帮助将不胜感激。

这是完整的文件:

using System;
using System.Windows.Forms;
using Chraft.Properties;
using System.IO;
using Chraft.Plugins.Events.Args;
using Chraft.Plugins.Events;

namespace Chraft
{
public class Logger
{
    private StreamWriter WriteLog;
    private Server Server;

    internal Logger(Server server, string file)
    {
        Server = server;
        try
        {
            WriteLog = new StreamWriter(file, true);
            WriteLog.AutoFlush = true;
        }
        catch
        {
            WriteLog = null;
        }
    }

    ~Logger()
    {
        try
        {
            WriteLog.Close();
        }
        catch
        {
        }
    }

    public void Log(LogLevel level, string format, params object[] arguments)
    {
        Log(level, string.Format(format, arguments));
    }

    public void Log(LogLevel level, string message)
    {
        //Event
        LoggerEventArgs e = new LoggerEventArgs(this, level, message);
        Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
        if (e.EventCanceled) return;
        level = e.LogLevel;
        message = e.LogMessage;
        //End Event

        LogToConsole(level, message);
        LogToForm(level, message);
        LogToFile(level, message);
    }

    private void LogToConsole(LogLevel level, string message)
    {
        if ((int)level >= Settings.Default.LogConsoleLevel)
        {
            Console.WriteLine(Settings.Default.LogConsoleFormat, DateTime.Now, level.ToString().ToUpper(), message);
        }
    }
    static Form1 f = new Form1();
    delegate void SetTextCallback(string s);

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the 
        // calling thread to the thread ID of the creating thread. 
        // If these threads are different, it returns true. 
        if (f.textBox1.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            f.textBox1.Invoke(d, new object[] { text });
        }
        else
        {
            f.textBox1.AppendText(text);
        }
    }

    private void LogToForm(LogLevel level, string message)
    {
        if ((int)level >= Settings.Default.LogConsoleLevel)
        {
            SetText(DateTime.Now + level.ToString().ToUpper() + message);
        }
    }

    private void LogToFile(LogLevel level, string message)
    {
        if ((int)level >= Settings.Default.LogFileLevel && WriteLog != null)
            WriteLog.WriteLine(Settings.Default.LogFileFormat, DateTime.Now, level.ToString().ToUpper(), message);
    }

    public void Log(Exception ex)
    {
        //Event
        LoggerEventArgs e = new LoggerEventArgs(this, LogLevel.Debug, ex.ToString(), ex);
        Server.PluginManager.CallEvent(Event.LOGGER_LOG, e);
        if (e.EventCanceled) return;
        //End Event

        Log(LogLevel.Debug, ex.ToString());
    }


    public enum LogLevel : int
    {
        Trivial = -1,
        Debug = 0,
        Info = 1,
        Warning = 2,
        Caution = 3,
        Notice = 4,
        Error = 5,
        Fatal = 6
    }
}
}

【问题讨论】:

    标签: c# multithreading textbox window invoke


    【解决方案1】:

    问题是您正在创建两个 Form 对象。在您的 Program.cs 文件中创建的一个: Application.Run(new Form1());

    还有你在记录器类中创建的那个

    Form f = new Form1();

    传递给 Application.Run 的是用户正在与之交互的那个。由于 Application.Run 调用,它变得可见并响应用户交互。

    您在 logger 类中创建的那个只是在内存中。它的 TextBox 很乐意添加您要求它添加的文本,但该文本在任何地方都不可见。

    有很多方法可以处理这种情况。您可以通过 Application.OpenForms 访问正确的 Form 对象,但更合适的处理方法是在记录器上添加一个表单可以订阅的事件,它可以处理更新 TextBox 以响应该事件。

    更新

    class LoggerLogEventArgs : EventArgs
    {
        public LoggerLogEventArgs(string message)
        {
            this.message = message;
        }
        private string message;
        public string Message { get { return message; } }
    }
    
    class Logger
    {
        public event EventHandler<LoggerLogEventArgs> Logged;
    
        protected virtual void OnLogged(LoggerLogEventArgs e)
        {
            EventHandler<LoggerLogEventArgs> handler = Logged;
            if (handler != null)
                handler(this, e);
        }
    
        // I would change this method name to LogToEvent
        private void LogToForm(LogLevel level, string message)
        {
            if ((int)level >= Settings.Default.LogConsoleLevel)
            {
                OnLogged(new LoggerLogEventArgs(message));
            }
        }
    }
    
    class Form1 : Form
    {
        // Subscribe to the logger only when we are ready to display text
        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            GetLog().Logged += new EventHandler<LoggerLogEventArgs>(logger_Logged);
        }
    
        // Unsubscribe from the logger before we are no longer ready to display text
        protected override void OnHandleDestroyed(EventArgs e)
        {
            GetLog().Logged -= new EventHandler<LoggerLogEventArgs>(logger_Logged);
            base.OnHandleDestroyed(e);
        }
    
        private void logger_Logged(object sender, LoggerLogEventArgs e)
        {
            if (InvokeRequired)
                BeginInvoke(new EventHandler<LoggerLogEventArgs>(logger_Logged), e);
            else
                textBox1.AppendText(e.Message);
        }
    }
    

    【讨论】:

    • 我在实现一个工作版本时遇到了一些困难,你有一些示例代码可以用来重新编码吗?我相当肯定这会解决问题。
    • @Adsy2010 类似于我上面添加的内容
    • 我会看看能不能把它插入并尽快回复你
    • 我已经为该项目获得了一些更新的代码,并且正在尝试再次启动表单,所以一旦我这样做,我将在上面重新添加该代码。至少它清理了我添加的垃圾代码:)
    【解决方案2】:
    hello i try this it works ( I make a console application and I add a windows form)
    
        using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Security.Permissions;
    using System.Windows.Forms;
    
    namespace ConsoleApplication6
    {
        class Program
        {
    
             delegate void SetTextCallback(string s);
             static Form1 f;
    
            static void Main(string[] args)
            {      
                 f = new Form1();
                 f.Show();
                 SetText("test");
                Console.ReadLine();
            }
            private static void SetText(string text)
            {
                // InvokeRequired required compares the thread ID of the 
                // calling thread to the thread ID of the creating thread. 
                // If these threads are different, it returns true. 
                if (f.textBox1.InvokeRequired)
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    f.textBox1.Invoke(d, new object[] { text });
                }
                else
                {
                    f.textBox1.AppendText(text);
                }
            }
        }
    
    }
    

    【讨论】:

    • 我在与主程序文件不同的日志文件中运行代码。它目前登录到没有问题的控制台,我将在上面添加代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    • 2016-07-09
    • 1970-01-01
    • 1970-01-01
    • 2016-08-29
    • 1970-01-01
    • 2014-08-29
    相关资源
    最近更新 更多