Question

clayman2 on Fri, 22 Aug 2014 17:29:52


Hello All,

I am a novice programmer and I assume this question has been asked many of times. I have a windows form, that calls on one class, which in essence that class calls another class. The last class, has a lot of processing to do, and is obvioulsy hanging the UI up. I know I need to do threading, but not very experienced, so not sure the easiest way for me to implement this.

The long running class, creates a bunch of Result objects and adds it to an internal list, I would like the text box on my UI thread to be update each time a new Result is added, how and what is the easiest way to accomplish this?

For simplisity sakes, this is what I have so far

Form Code:

public partial class FileManager : Form { public FileManager() { InitializeComponent(); } private void Button_Click(object sender, EventArgs e) { if (ResultsTextbox.Text.Length > 0) ResultsTextbox.Text = string.Empty; ResultsTextbox.SelectionColor = Color.Green; ResultsTextbox.SelectedText = "\t\t*************** PROCESSING PLEASE BE PATIENT ***************\r\r"; class1 = new Class1(Textbox1.Text); foreach (Result result in class1.GetResults()) { Textbox1.SelectionColor = result.MessageColor; Textbox1.SelectedText += result.Message; } }

}

Class1 Code

public class Class1
{
  private string _fileLocation;
  private IList<Result> _results;
  private IList<MyFiles> _myFiles;

  public Class1(string fileLocation)
  {
    _fileLocation = fileLocation;
  }

  public IList<Result> GetResults()
  {
    return _results;
  }

  private void Start()
  {
    foreach (MyFiles files in _myFiles)
    {
      _results = files.GetResults();
    }
  }
}

Class2 Code

public class MyFiles
{
  private IList<Result> _results = new List<Result>();
  public IList<Result> GetResults() { return _results };

  public void ParseFiles()
  {
    // Really long running process
    // Creates Result Objects and adds to internal list
    // Also calls another method which creates Result
    // Objects and adds to internal list
  }
}

I hope I included enough information, if not please let me know, and I also appreciate any help.

If you find that my post has answered your question, please mark it as the answer. If you find my post to be helpful in anyway, please click vote as helpful.

Don't Retire Technet





Sponsored



Replies

Nico Boey on Fri, 22 Aug 2014 17:40:44


hi,

the easiest way would be with a backgroundworker.

PrabathSL on Fri, 22 Aug 2014 18:12:48


If you working with WPF (C#/XAML) combination its is no matter just use MVVM pattern with INotification. If you working with the Win form you can use two ways.
1. Use background thread to handle those items (threading class) //easy to implement but consume resources
2. Best way is use background worker

regards , prabathsl

-------------------------------------------------------------------------
Hope that helps
Please don't forget to up vote answers you like or which help you and mark one(s) which answer your question.

Andy ONeill on Fri, 22 Aug 2014 18:15:30


Simplest I can think of would be:

            Task.Factory.StartNew(() => { ParseFiles(); });

When you want to change anything created on the UI thread such as the TextBox you mention in the title of the thread you have to use Control.Invoke or you will get cross thread errors

http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx

You could do that:

        private void ParseFiles()
        {
            // ...........
            SetText("whatever");
        }
        private void SetText(string s)
        {
            textBox1.Invoke((MethodInvoker)delegate { textBox1.Text = s; });
        }

clayman2 on Fri, 22 Aug 2014 18:52:59


Nico,

I was able to get it to work with the Backgroundworker, except for updating the progress part. Since you have to send ReportProgress an integer, how do you do so, when you have no idea how many files are being processed?

Andy,

I also tried your method and it is working good. The only problem I have, is with some logic of mine, as it seems to be the same whether I use your method or a Background process like Nico suggested. When I call on the following part to update the textbox

foreach(Result result in class1.GetResults())
I am getting a lot of repetative information, how would I be able to go about it, that only retrieve the latest list item after the list has been updated?

Andy ONeill on Fri, 22 Aug 2014 19:10:54


Only update the textbox when you've done your repetitive stuff.

string s = string.Empty()
foreach(Result result in class1.GetResults())
{

   s=whatever;
}
SetText(s);

Kareninstructor on Sat, 23 Aug 2014 05:49:53


Hello,

You might want to look at this example which uses Task-based Asynchronous Pattern (TAP). In the example code is started in a form and worked in a class library which updates the UI in the form that started the process. Bare in mind this is a database operation but the same principles apply for working any operation that is not data related. There are C# and VB.NET projects so ignore the VB.NET ones.

Nico Boey on Mon, 25 Aug 2014 07:38:37


Nico,

I was able to get it to work with the Backgroundworker, except for updating the progress part. Since you have to send ReportProgress an integer, how do you do so, when you have no idea how many files are being processed?


Most of the time, progress bars just give an educated guess; you could keep a variable with a count of how many has been processed, and at every progress report, you evaluate how many there is still to do; send back the ratio as a percentage. 

clayman2 on Tue, 26 Aug 2014 13:45:20


kevininstructor, thank you for your input, but I am unable to go that route as I do not have .NET 4.5

I had to put this on the back burner for now, as other things have come up, but thank you all for your input, it has led me to the right direction.