WhiskerBiscuit
WhiskerBiscuit

Reputation: 5157

Why is my window not being updated from my thread?

In a console application, I have a class called MyPolling which when started, monitors an external resource until halted. Inside of the monitoring loop, I use an injected implementation of ILogger, which the service uses to write a message about the status of the polling class.

Sometimes I will want an implementation of ILogger to write to the console, other times I may want to show a window and also write the output to that window in addition to the console.

However when I run the following with showLog = true, the visualLog window is not being updated (spinning "wait" icon). For both showLog = {true,false} the console logger is being updated correctly.

Obviously I have some sort of thread issue, but I'm not sure where I went wrong.

    static void Main(string[] args)
    {
        bool showLog = true; //obviously will set this from args

        VisualLogger visualLogger = null;
        ILogger logger;
        if (showLog)
        {
            //create the visual logger, and use that to create the debug logger
            visualLogger = new VisualLogger();
            logger = new DebugLogger(visualLogger);
        }
        else
        {
            //create the "normal" debug logger
            logger = new DebugLogger();
        }

        //create the polling class and inject the logger and then start the thread
        var svc = new MyPolling(logger);           
        var pollThread = new Thread(new ThreadStart(svc.BeginPolling));
        pollThread.Start();

        //if the visualLogger wasnt created, don't show it.
        if (visualLogger!=null)
            visualLogger.Show(); 

        Console.ReadLine();
        svc.Dispose();
    }

    public interface ILogger
    {
        void Write(string message);
    }

    public class DebugLogger : ILogger
    {
        private ILogger _baseLogger;
        public DebugLogger(ILogger logger = null)
        {
            _baseLogger = logger;
        }

        public void Write(string message)
        {
            if (_baseLogger != null)
                _baseLogger.Write(message);

            Console.WriteLine(message);
        }
    }

And my implementation of VisualLogger:

public partial class VisualLogger : Form, ILogger
{
    public VisualLogger()
    {
        InitializeComponent();
        txtLog.Clear();
    }

    public void Write(string message)
    {
        txtLog.Text += message + Environment.NewLine;
    }
}

Upvotes: 1

Views: 55

Answers (2)

Reza Jooyandeh
Reza Jooyandeh

Reputation: 761

It comes from the fact that Form needs a message loop to process events. Form.ShowDialog performs its own message loop, whereas Show does not. If you call Show method from another form then there is a message loop for that but in your case which you call it from a console app, you need to use ShowDialog instead. Also you cannot edit UI controls from other threads, and you need the Invoke method. so you need these changes:

public partial class VisualLogger : Form, ILogger
{
    public VisualLogger()
    {
        InitializeComponent();
        txtLog.Clear();
    }

    private void WriteInternal(string message)
    {
        txtLog.Text += message + Environment.NewLine;
    }

    public void Write(string message)
    {
        txtLog.Invoke(new Action<string>(WriteInternal), message);
        // or simpler remove the WriteInternal function and use the next line:
        // txtLog.Invoke(new Action(() => txtLog.Text += message + Environment.NewLine));
    }
}

in Main:

    if (visualLogger != null)
        visualLogger.ShowDialog();

Or if you want to continue your main thread:

    Thread t = new Thread(new ThreadStart(
        () =>
        {
            if (visualLogger != null)
                visualLogger.ShowDialog();
        }));
    t.Start();

Upvotes: 2

Bill
Bill

Reputation: 1479

You have to update the form control from the UI thread. Something like this should do it:

txtLog.Invoke((sender, args) => (sender as TextBox).Text = "text");

Upvotes: 1

Related Questions