0

I have a windows form (Form1) which when a button is clicked on it I want to open another windows form(form2) in a thread.

I want to open it in a thread because when it starts up I have it read and color syntax of 10k+ line long files which takes about 5 or 6 min.

My problems are I do not know the "proper" way to do it. I have found out how to do it and it works right, but I want to be able to have a progress bar telling me how far along Form2 is with its processing. (probably with a Background worker object)

Here is my layout

Form1 has a RichTextBoxes and one buton, click the button and it opens a form in another thread that colors the text in form1's rtb.

Form2 has a Rtb also, this rtb has a method ProcessAllLines which processes the lines and does the work that I want done in another thread.

This is why I think I am having difficulty. The textbox is doing the work while the form is waiting there to load.

Here is how I open the Form2:

    private void button1_Click(object sender, EventArgs e)
    {
        ColoringThread colorer = new ColoringThread(this.m_bruteView.Text);
        Thread theThread = new Thread(new ThreadStart(colorer.OpenColorWindow));
        theThread.Start();
    }

    public class ColoringThread
    {
        string text;
        public ColoringThread(string initText)
        {
            text = initText;
        }
        public void OpenColorWindow()
        {
            Form2 form2 = new Form2(text);
            form2.ShowDialog();
        }
    };

And here is how form2 does work:

    string initText;
    public Form2(string initTextInput)
    {
        initText = initTextInput;
        InitializeComponent();
    }


private void InitializeComponent()
    {
        this.m_ComplexSyntaxer = new ComplexSyntaxer.ComplexSyntaxer();
        this.SuspendLayout();
        // 
        // m_ComplexSyntaxer
        // 
        this.m_ComplexSyntaxer.Dock = System.Windows.Forms.DockStyle.Fill;
        this.m_ComplexSyntaxer.Location = new System.Drawing.Point(0, 0);
        this.m_ComplexSyntaxer.Name = "m_ComplexSyntaxer";
        this.m_ComplexSyntaxer.Size = new System.Drawing.Size(292, 273);
        this.m_ComplexSyntaxer.TabIndex = 0;
        this.m_ComplexSyntaxer.Text = initText;
        this.m_ComplexSyntaxer.WordWrap = false;

        // THIS LINE DOES THE WORK
        this.m_ComplexSyntaxer.ProcessAllLines();
        // 
        // Form2
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(292, 273);
        this.Controls.Add(this.m_ComplexSyntaxer);
        this.Name = "Form2";
        this.Text = "Form2";
        this.ResumeLayout(false);
    }

And here is where the work is done:

    public void ProcessAllLines()
    {
        int nStartPos = 0;
        int i = 0;
        int nOriginalPos = SelectionStart;
        while (i < Lines.Length)
        {
            m_strLine = Lines[i];
            m_nLineStart = nStartPos;
            m_nLineEnd = m_nLineStart + m_strLine.Length;
            m_nLineLength = m_nLineEnd - m_nLineStart;

            ProcessLine(); // This colors the current line!
            i++;

            nStartPos += m_strLine.Length + 1;
        }
        SelectionStart = nOriginalPos;
    }

Sooo, what is the "proper" way to open this form2 and have it report progress to Form1 to show to the user? (I ask because I was told this is not the right thing to do, I will get a "cross-thread" violation apparently?)

AnotherUser
  • 1,311
  • 1
  • 14
  • 35
  • "I want to open another windows form(form2) in a thread. " - just don't (try to) do that. – H H Aug 17 '12 at 19:28
  • Do What John Skeet has recommended, you can do all of this within a single form / thread.. no need for MDI Form – MethodMan Aug 17 '12 at 19:29
  • possible duplicate of [Threading, let one thread know the others progress](http://stackoverflow.com/questions/12011358/threading-let-one-thread-know-the-others-progress) – H H Aug 17 '12 at 19:29
  • here is a great link that will show you how to report on progress http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx – MethodMan Aug 17 '12 at 19:47

2 Answers2

2

I want to open it in a thread because when it starts up I have it read and color syntax of 10k+ line long files which takes about 5 or 6 min.

Why not read the data in a separate thread but then keep the UI itself on the same thread as the first form?

In my experience if you use just one thread for UI operations, it makes life significantly simpler.

As for how you should start a new thread to read the data, there are various options:

  • You could use BackgroundWorker; which would probably make the progress reporting simpler. See the MSDN article for more information.
  • Create a new Thread directly and start it
  • Use a thread-pool thread with ThreadPool.QueueUserWorkItem
  • If you're using .NET 4, use Task.Factory.StartNew
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • sorry, the data (text 10k+ lines) is not read in, just passed to the constructor of the Form2 object to be passed to its RichTextBox. .. I want the form1 to be responsive while Form2 is loading. I dont think this can be achieved without threading. – AnotherUser Aug 17 '12 at 19:30
  • @user1596244: So what do you need to do to the data? Is *all* the work in creating the RichTextBox, or are you performing more processing on it first? – Jon Skeet Aug 17 '12 at 19:32
  • All of the work is done in coloring the syntax of each line, I go through each line and look for specific patterns if one is found it is colored a certain way. I color the syntax before the form is displayed so that it doesn't just sit there as a unresponsive white window until it has finished processing each line. – AnotherUser Aug 20 '12 at 11:06
  • @user1596244: Then it sounds like that work should be done in a separate thread, not in a GUI thread at all. – Jon Skeet Aug 20 '12 at 11:25
  • So I should call form2 from form1 normally, "new form2; form2.show dialog;" ... Then in form2 have its coloring operation be performed in another thread and let it display text that says "this form will fill when coloring is done" and then when the coloring is done throw the text on the text area? – AnotherUser Aug 20 '12 at 11:43
  • @user1596244: No, I'd personally do the colouring in a different thread before you even create `Form2`. Use a progress bar in Form1 to show the progress, then create Form2 when it's ready. – Jon Skeet Aug 20 '12 at 11:49
  • I must first create a form2 before coloring, form2 holds a RichTextBox I wrote that does the coloring to itself; I can process/color all lines or just the current line as the user is typing. So I have to create form2, pass text from form1 to form2 to the text box, then tell the textbox to processalllines. Which is where the work is done. So I am not sure if I can do the work itself in a separate thread because I cannot pass a string to the textbox with the color formatting intact. It all kind of goes together? Does that make sense? – AnotherUser Aug 20 '12 at 12:25
  • @user1596244: The problem is that you *have* coupled the processing with the display. Separate those, perhaps building up all the relevant rich text in one lump or perhaps using a separate data structure. – Jon Skeet Aug 20 '12 at 13:11
1

The other form doesn't need to run in another explicit thread in my opinion.

Sure you want to have the long work done in another thread (or a background worker), but you just want to call another form, and that other form will perform the task in another thread (or background worker).

Pacane
  • 20,273
  • 18
  • 60
  • 97
  • If I call form2.showdialog, in a method that is called when a button is pressed on form1; my UI for form1 becomes unresponsive until form2 has loaded. But if I call form2 in another thread then the form1 UI is responsive while form2 is loading, which is what I want so the user had something to do while form2 is loading – AnotherUser Aug 20 '12 at 11:18