tags:

views:

330

answers:

2

I have a textbox on a Windows Forms UserControl that I am trying to update the contents of from elsewhere in my solution.

I am dynamically adding the UserControl to my form, and I have a static Instance property on the UserControl so that I can access it from a referencing library.

I have excluded double-lock checking here for brevity...

public partial class MyForm : Form {

   private MyControl ctl;

   public MyForm() {
      ctl = new MyControl();
      MyControl.Instance = ctl;
      Controls.Add(ctl);
   }

}


public partial class MyControl : UserControl {

   public static MyControl Instance;

   public void LogMessage(string msg) {

       if (MyInnerTextBox.InvokeRequired) {
           MyInnerTextBox.Invoke(LogMessage, msg);
           return;
       }

       MyInnerTextBox.AppendText(msg);
       MyInnerTextBox.Refresh();
       this.Refresh();
   }

}

When I call MyControl.Instance.LogMessage("blah") from another class, it appears that my text is added to another instance of the MyControl control... not the instance on the form.

What am I missing? Shouldn't the static instance reference allow me to reference the instance of MyControl on MyForm?

+2  A: 

The static Instance is shared by all instances of MyControl. If you have multiple instances of MyForm, each one will change were Instance references so all MyForm instances will point to the same instance of MyControl.

Update

As there is only one instance of MyForm, this is certainly unusual.

However, if what you want is a logging system, you should really decouple this system and have a class that performs the logging and fires events, then have the form listen to the MessageLogged event on that logging class and update the text box accordingly. Something like:

static class Logger
{
  public static event EventHandler<MessageLogEventArgs> MessageLogged;

  public static void LogMessage(object caller, string message)
  {
    if (MessageLogged != null)
    {
       MessageLogged(caller, new MessageLogEventArgs(message);
    }
  }
}

This way you don't need to worry about having static references to controls and trying to update them. Decoupling the system this way will make your code much easier to understand and debug.

Classes wishing to use the log call Logger.LogMessage and your form listens to the event.

public partial class MyForm : Form {

   private MyControl ctl;

   public MyForm() {
      ctl = new MyControl();
      Controls.Add(ctl);

      Logger.MessageLogged += MyMessageLogHandler;
   }

   private void MyMessageLogHandler(object sender, MessageLogEventArgs e)
   {
      this.ctl.LogMessage(e.Message);
   }
}

public partial class MyControl : UserControl {

   public void LogMessage(string msg) {

       if (MyInnerTextBox.InvokeRequired) {
           MyInnerTextBox.Invoke(LogMessage, msg);
           return;
       }

       MyInnerTextBox.AppendText(msg);
       MyInnerTextBox.Refresh();
       this.Refresh();
   }
}
Jeff Yates
Agreed... but MyForm is only instantiated once...
Jeff Fritz
NICE... I'll give this a whirl...
Jeff Fritz
Note for brevity that I excluded the MessageLogEventArgs class, which you'll need to create.
Jeff Yates
That did it... the extra level of indirection got me the logging that I was looking for. Thx!
Jeff Fritz
Excellent. I'm always glad to help rather than hinder. :)
Jeff Yates
A: 

No. There is only one instance of MyControl.Instance in your entire application (because it's static). Every time you set it, you overwrite the previous instance of it. Basically, the last one in wins.

You'll have to make a public getter in MyForm for the MyControl instance (or make it a public member variable). And set the text that way. i.e. myForm1.ctl.LogMessage("blah").

NascarEd