How to access controls in another class

I am learning C # and what I need is form access control from another class (same namespace).

I know there are many posts on this topic, but no complete solution for "dumb" ones found, so I write here what I understood and please tell me - is this the right way?

Background: I have a "debug" form in my application, and I need all the other forms to be able to log my activity on that form. There is some ListBox control where all logs from other forms are written. When I (or one of my non-Visual Studio testers) are talking to an application and something bad happens, I can look at this debug form to see all the detailed logs that occurred shortly before this "error moment".

My application main form (frmMain):

namespace myNamespace {

public partial class frmMain : Form {

private frmDebug debug;  // frmDebug is declared in other class
                         // we will hold reference to frmDebug form in 'debug'

public frmMain() {         // constructor of the main form 'frmMain'
  InitializeComponent();
  debug = new frmDebug();  // we create new instance of frmDebug immediately when
}                          // our main form is created (app started) and whole time
                           // of running this app we can access frmDebug from
                           // within frmMain through 'debug' variable


// clicking button 'btnLoggingTest', the log is written 
// in the 'frmDebug' form even if it is closed (not visible)
private void btnLoggingTest_Click(object sender, EventArgs e) {
  debug.Log("log this text for me please");
}

// Click handler of the button 'btnShowDebug' :
private void btnShowDebug_Click(object sender, EventArgs e) {
  debug.ShowDialog();    // here we can show frmDebug (in 'modal' style)
}                        // just to see what log-information is written there


} // frmMain class

} // namespace

      



And here is the code for the frmDebug class : (there is only one Listbox in the form)

namespace myNamespace {
public partial class frmDebug : Form {

public frmDebug() {
  InitializeComponent();
}

public void Log(string txt) {    // this is the actual 'Log' function (or method)
  this.listBox1.Items.Add(txt);
  Application.DoEvents();        // if the logging takes place in some 
}                                // computing-intensive 'loop' or function,
                                 // (or in my case FTP login and upload process)
                                 // 'DoEvents' ensures every log appears immediately
                                 // after the 'Log()' was called. Otherwise all logs
                                 // would appear together at once, as soon as the 
                                 // computing-intensive 'loop' is finished

} // class frmDebug

} // namespace

      



I have a strange feeling in my stomach. I am doing it all wrong, so tell me how to do it right. :). If everything is ok, hope this helps someone like me.

Thank!

+3


source to share


3 answers


Your application probably has a class called Program. There you will find the code

var mainForm = new frmMain();
Application.Run(frmMain);

      

Create static property for debug form in this class

public static frmDebug DebuggingForm { get; private set; }

      



Change your startup code as follows

DebuggingForm = new frmDebug();
var mainForm = new frmMain();
Application.Run(frmMain);

      

From other classes, you can access this form like this

Program.DebuggingForm.Log("log this text for me please");         
Program.DebuggingForm.Show();

      

+3


source


I guess you don't need to keep the debug form in memory. You can write logs to any object. For example. static log:

public static Log
{
    private static List<string> _messages = new List<string>();

    public static Write(string message)
    {
        _messages.Add(message);
    }

    public static IEnumerable<string> Messages 
    { 
       get { return _messages; }
    }
}

      

You can add log messages from every point in your application via

Log.Write("log this text for me please");

      



If you need to view these messages, just create and show a debug form:

private void btnShowDebug_Click(object sender, EventArgs e) {
    using (frmDebug debug = new frmDebug())
                debug.ShowDialog();
}  

      

In debug form at boot, assign Log.Messages to your list.

+2


source


Another approach would be to have an event receiver that will act as the subscription publishing center for your debug information, this way you don't get the debug form dependency all over the place, e.g .:

public class EventSink
{
    private static readonly IList<Action<string>> _listeners = new List<Action<string>>();

    public static void RegisterListener(Action<string> listener)
    {
        _listeners.Add(listener);
    }

    public static void RaiseEvent(string message)
    {
        foreach (var l in _listeners)
            l(message);
    }
}

      

in the constructor for your frmDebug, you would do:

EventSink.RegisterListener(msg=>listBox1.Items.Add(msg));

      

and every time you need to add a message to the debug console you should:

EventSink.RaiseEvent("this is a debug message");

      

That way, you could register new listeners to do different things, like send you an email when a particular event occurs, etc., and you're not connected to your debug form (the decoupling is good :)

0


source







All Articles