-1

I am working on the following program which deals with threads and thread priorities.

I have constructed a windows form containing a rich textbox (DisplayTextBox) and two buttons (StartButton for running app and ExitButton for closing app).

In the form, I am creating several threads and running them one after another. The method used by each thread is found in the Threading class. The method in question is PrintOnScreen().

In this method, I am appending the thread name as well as its priority to str of type StringBuilder. Then I want to display the contents of str in DisplayTextBox (which is in Form.cs).

However, I am getting a "NullReferenceException was unhandled: Object reference not set to an instance of an object" error. The line where the error crops up is the following:

DisplayTextBox.Text = Convert.ToString(str);

Can you please help me to solve this error? Thanks.

Edit

Thanks to all for your help. In order to solve the problem, I copied the PrintOnScreen method to the Form.cs class and discarded Threading.cs.

I later used the code given by Anand and placed it below t2.Join(). Now it works like a charm.

Joe
  • 21
  • 7
  • Do you know which object is null? There are only two possible answers to this question the first would be the **DisplayTextBox** the second would be **str** of course I don't see where you pass a reference to the DisplayTextBox on the form. Threading inherits Form1 that doesn't mean it has a reference to the controls on Form1. – Security Hound Dec 27 '11 at 12:21
  • Even if you do fix your code and pass a reference to the **DisplayTextBox** you would have to invoke changing the text since you cannot modify controls in a seperate thread other then the main UI thread. – Security Hound Dec 27 '11 at 12:23
  • You should really consider to synchronize the access to data that you access from multiple threads. For example are you writing with both threads to the same StringBuilder instance and iterating the Threads-collection. – Jan Dec 27 '11 at 12:26
  • Hi there :) It is DisplayTextBox which is set to null and not str apparently. I tested it by passing an actual string to DisplayTextBox instead of str but the error persists. – Joe Dec 27 '11 at 12:28
  • @Jan The method is being accessed by both threads, supposedly one thread after another. Each thread is writing to the stringbuilder. After writing to stringbuilder, the contents of it should be displayed in DisplayTextBox. But apparently, there is no instance of DisplayTextBox in Threading.cs. I can't figure out how to solve this – Joe Dec 27 '11 at 12:31
  • @Joe you are wrong: You can't be sure, that the threads run one after another - i mean when that would be the case, what is the sense of a thread then? A context switch can occur at any time in your code and the result will be undefined. For your NullRefEx, @Fischermaen gave you the correct answer: You have two instances of `DisplayTextBox`. You even have two instances of `Form1` (one uninitialized), because `Threading` inherits `Form1`. – Jan Dec 27 '11 at 13:00

5 Answers5

3

The problem occurs in the constructor of your form. You declare DisplayText again as local member, so that the field of your form isn't initialized. Change your constructor like this:

private void Form1_Load(object sender, EventArgs e)
{
    DescTextBox.Visible = false;
    DisplayTextBox = new RichTextBox();
    DisplayTextBox.Location = new Point(15, 31);
    DisplayTextBox.Height = 258;
    DisplayTextBox.Width = 303;
    panel1.Controls.Add(DisplayTextBox);
} 

and it should work like you expect.

Edit: But beware of the problems you will get, when you want to change UI elements from a background worker thread. In those cases you will have to use the invoke pattern.

Fischermaen
  • 12,238
  • 2
  • 39
  • 56
1

You cannot communicate with controls from any other thread than main application's thread. You need to use the dispather for this. Have a look here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx

EDIT
@Fischermaen - heh, didn't notice this but it still won't work because of the line, where he wrote it fails. He still needs to use dispatcher to set the Text property on the control from the non-main threads

EDIT 2
Related threads:
How to update the GUI from another thread in C#?
In WinForms, why can't you update UI controls from other threads?

Community
  • 1
  • 1
SOReader
  • 5,697
  • 5
  • 31
  • 53
  • Thanks for the suggestions about dispatcher. I will try it and let you know if it works. Thanks to everyone :) – Joe Dec 27 '11 at 12:33
1

I tried this in simple console application and it worked fine. The issue is with DisplayTextBox. If you want to interact with any control, then you have to use UI thread or Dispatcher. Use the following code in your Threading Class, instead of

 DisplayTextBox.Text = Convert.ToString(str);

use this one

Dispatcher.Invoke(DispatcherPriority.Normal, 
                    new Action(
            delegate()
            {
              DisplayTextBox.Text = Convert.ToString(str);
            }
        ));
Anand
  • 14,545
  • 8
  • 32
  • 44
  • Exactly. In console application, it works fine. The problems it is giving me is when I try to convert it to Windows app. – Joe Dec 27 '11 at 12:32
  • I pasted the code and it is giving me the error - The name 'Dispatcher' does not exist in the current context. – Joe Dec 27 '11 at 12:40
  • I think I have to create an instance of it – Joe Dec 27 '11 at 12:40
0

Um. Can't see from here, but part of the reason you are having difficulty is the lack of encapsulation and poor lifetime management in your code.

Instantiate str inside the PrintOnScreen method, give it a better name as well, no appranrent need to be a member variable, no need at all to make it public.

Instead of having a void result, have it return the string result

e.g.

SomeTextBox = PrintOnScreen(); // (GetThreadDetails might be a better name...)

As a tip don't mix presentation and logic. Keep you UI controls thoroughly inside whatever owns them.

And don't do

public SomeType SomeName;

make it a property and give it getter and a setter , even if it's the short form

public SomeType SomeName {get; set;}

Any other bit of code could do something really foolish like

Form1.SomeType = (SomeOtherType)someVar; // with appaling consequences.

Nothing should have more than one owner, any other path leads to ruin.

PS str.ToString() would be a better option than Convert.ToString(str);

Tony Hopkinson
  • 20,172
  • 3
  • 31
  • 39
0

Well, this is not very clear for me what you are trying to achieve, however the problem is that the base form Threading class inherits from not being loaded when you are trying to access control on it (window handle still not exists) Also this is the reason you see nothing on Form1 itself, because your threads outputs into hidden form, which is not shown.

I think that you are trying to solve thread access issue, raised by SOReader. This is not proper way to do this.

Tamir
  • 2,503
  • 16
  • 23