1

私はコンソール アプリケーションをウィンドウ形式に変換する作業を行っています。それについてはほとんど知らないが、過去に既にウィンドウ形式で同様のアプリケーションを使用した経験があるので、それほど難しいことではないと考えました。

そこで、ログ情報を取得するためだけに、フォームを作成してテキストボックスを追加しました。

このコンソール アプリは以前は単一のスレッドで実行されていましたが、テスト用にコンソールと並行してフォームを実行できるように 2 つ目のスレッドを追加しました。(奇妙なことに、シングルスレッドでも問題なく動作します)。

これは、フォームに何も取得していないことを除いて、フォームにテキストを書き込むために使用しているコードです。

    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
    }
}
}
4

2 に答える 2

1

問題は、2 つの Form オブジェクトを作成していることです。Program.cs ファイルに作成されるもの: Application.Run(new Form1());

そして、ロガークラスで作成したもの

フォーム f = 新しい Form1();

Application.Run に渡されたものは、ユーザーが操作しているものです。Application.Run 呼び出しにより、表示され、ユーザーの操作に応答します。

ロガー クラスで作成したものは、メモリ内にそのまま残ります。その 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);
    }
}
于 2012-08-30T22:29:10.887 に答える
0
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);
            }
        }
    }

}
于 2012-08-30T20:05:21.927 に答える