0

I have a class for refreshing the text of a label:

class GUIDisplayer:IOutputter
    {
        Label label;
        public GUIDisplayer(Label label)
        {
            this.label = label;
        }

        public void display(string text)
        {
            label.Text = text;
            label.Refresh();
        }

    }

An instance of this class gets passed to another class in my Windows Forms app, where I use it for showing progress during a For loop:

public class BatchConverter
    {

        IOutputter outputter;

        public BatchConverter(IOutputter outputter)
        {
            this.outputter = outputter;
        }

        public bool convertFiles(List<FileTransferData> fileTransferList,bool overwrite=true)
        {

            for (int index = 0; index < fileTransferList.Count; index++)
            {
                FileTransferData file = fileTransferList[index];
                outputter.display(index + "/" + fileTransferList.Count + ": " + file.sourcePath);
                //do some file conversion operations
            }
            return true;

        }
    }

When convertFiles() is running, the label gets updated with the first call to outputter.display(), but then the app just freezes with the blue busy circle until it's finished with the For loop. The For loop successfully writes to the output device with the outputter.display() calls when I implement the IOutputter.display() method using Console.WriteLine(). I want the text in the label to refresh every time the For loop iterates; is there a way I can do that?

sigil
  • 9,370
  • 40
  • 119
  • 199
  • 2
    Perhaps use a threaded worker with events? - problem is without a separate thread, your worker thread and form thread are the same - meaning there is no time for it to reach refresh() while the worker method is so busy. – Mark Phillips Nov 03 '16 at 15:43
  • 2
    You're doing the work on the UI thread which is why it freezes because it's busy. Do the work on something other than the UI thread. If you're a beginner then [BackgroundWorker](https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx) is an easy way to do this. – Equalsk Nov 03 '16 at 15:44
  • 4
    And if someone suggests using `Application.DoEvents()` just don't... – Matthew Watson Nov 03 '16 at 15:49
  • Why not @MatthewWatson? It works and is easy :) – Pikoh Nov 03 '16 at 15:50
  • 3
    A kitten dies every time `DoEvents` is used, two kittens die when it's inside a `while` loop. – Equalsk Nov 03 '16 at 15:50
  • 1
    @Pikoh Plenty of things in life are easy, doesn't mean they're right. – Equalsk Nov 03 '16 at 15:51
  • Just tying to be sarcastic @Equalsk :) – Pikoh Nov 03 '16 at 15:53
  • You forgot your /s ;-) – Equalsk Nov 03 '16 at 15:55
  • @Equalsk, I'm not sure how to apply BackgroundWorker in this situation. It seems I need to call `BatchConverter.convertFiles()` inside `backgroundWorker_DoWork`, but then how do I call the `backgroundWorker_ReportProgress` event inside `convertFiles()`? If I put all the code from `convertFiles()` in the `DoWork` event handler, then it violates information hiding, and also makes that code unavailable for other UIs (say I want to run it from the console). Sorry if I'm missing something basic here. – sigil Nov 03 '16 at 16:34
  • 2
    The [accepted answer in this question](http://stackoverflow.com/questions/6481304/how-to-use-a-backgroundworker) should give you a fair idea. Make the background worker have a scope that `convertFiles` can see to call `ReportProgress`. – Equalsk Nov 03 '16 at 16:38

0 Answers0