Sunday, April 28, 2019

Passing Data Using Static Classes

Typically, when I see questions on the Forums about passing data between Forms, the questions are usually about passing data in, what I will call, the "classic" sense: two Forms are open, one is used for gathering data and the other is used for manipulating and/or displaying data. For those types of questions, I refer the person to my blog posts from many years ago:

http://geek-goddess-bonnie.blogspot.com/2011/01/passing-data-between-forms.html
http://geek-goddess-bonnie.blogspot.com/2012/12/passing-data-between-forms-redux_31.html

And this one is often relevant too:

https://geek-goddess-bonnie.blogspot.com/2010/06/program-to-interface.html

I came across a question yesterday that at first seemed like it was going to be about passing data in the "classic" sense. Until I thought some more about what the person was actually asking about:  the "data-gathering" Form was a Login Form and it would collect information from the user, an Account Number for example. They then wanted to display that information on all other Forms in the application.  Since Login Forms are displayed at application start-up and then they "go away", we no longer have the ability to pass the data in the "classic" sense (two Forms are not going to both be open). Some other mechanism is needed.

This particular scenario with a Login Form, in my opinion, only requires a static class with static properties. For this application, I think that a singleton class would be overkill (because the class is only ever going to be populated at application startup and nowhere else or at any other time).

So, let's start with a static Account class:

public static class AccountClass
{
public static string AccountNumber { get; set; }
// plus, any other static info you'd like to share with your other Forms
}

In your LoginForm, perhaps after the user had clicked OK to login, you'd want to set the static members of the AccountClass:


private void OKButton_Click(object sender, EventArgs e)
{
AccountClass.AccountNumber = this.txtAccountNumber.Text;
// plus, whatever else you need to do in this button click
}

Then, in any other Forms where you need this information, get it from the static class. For example, to display the AccountNumber in a label on your Form, take care of that in the Form's constructor:

public CustomerForm()
{
InitializeComponent();
this.lblAccountNumber.Text = AccountClass.AccountNumber;
}

Happy Coding! =0)

11 comments:

  1. Please don't do this, it's a terrible idea! You'll quickly end up with spaghetti code. Here are a few things you'll lose by doing this: thread safety, testability, maintainability. Also, good luck debugging situations where the static value was unexpectedly changed by unrelated code.

    ReplyDelete
    Replies
    1. This only really applies to this particular scenario … needing information from a Login Form. This is for a Windows Form application. I'm pretty sure that will not affect thread safety or any of the other things you mentioned.
      The values should not be changed anywhere else in the application, as they are supposed to be used only for display purposes. Perhaps I should have made that clearer in my post. Also, perhaps if I had made the static property's setter a bit more fool-proof so that it couldn't be set anywhere else in the application other than the Login Form.

      Delete
    2. It's still a bad practice. There are many other ways to achieve the same result, not necessarily more complex. For instance, the login form could expose an AccountNumber instance property, which you could get after displaying the login form.

      Delete
    3. Thomas,
      >>The login form could expose an AccountNumber instance property<<

      Yes, it could ... but let's think about that a bit:

      Whatever bit of code that called the LoginForm would then have to access the AccountNumber property from the LoginForm and save it. Actually, the property should be an instance of an AccountClass containing an AccountNumber property and whatever other info is needed (instead of a static AccountClass that I talked about).

      Assuming that the code that called the LoginForm is the MainForm of the application (which, might not always be the case), it would have to pass that AccountClass instance to every other Form it opened (a CustomerForm, an OrderForm, a BillingForm, etc), in those Form's constructor. Consequently every single Form in the application that needed access to the Account info, would have to have a second constructor taking AccountClass as its parameter.

      Now, OK, that's not that difficult, I agree. But also, how is that really any different than utilizing the same info in a static AccountClass with static properties? With a lot less work?

      Another alternative that I did mention was using a Singleton, which I thought was overkill in this situation (and still do think so), but it probably is better than passing the instance of the AccountClass around through a constructor parameter to every other Form.

      A lot of developers say static classes/properties are bad while other developers say that global properties are bad ... but, in my opinion, that is over-simplifying. A lot depends on the application being developed, whether it's a simple app or a complicated app makes a world of difference as to how its architected.

      Delete
    4. For a very simple application, it's fine to use static properties or singletons. But it can quickly become messy when your application grows up. The approach I'd recommend for a real-world, non-trivial application, would be to use dependency injection. A IAccountService could be injected into every class that needs it. That's testable, maintainable, and doesn't introduce strong coupling.

      Delete
    5. What if there are 5 forms open, and 1 of the forms that has the button event clicked. what happens? I don't think the other forms' UI will be updated. we might need to trigger an event not change static value directly.

      Delete
    6. Thomas,
      I agree with you for non-trivial applications, something more robust could be used. For this particular purpose and for the question on the Forums that I was talking about, the application seemed to be a simple application that would only require as simple process ... hence, the static class/property.

      I wrote a blog post close to 5 years ago that talks about Dependency Injection and Inversion of Control, so I'm no stranger to it (although I haven't had to use it years). If you're interested, here it is:
      https://geek-goddess-bonnie.blogspot.com/2014/10/intro-to-ioc.html

      Delete
    7. WhistlerHusky,
      In the scenario laid out in the blog post, we're talking about a LoginForm that only ever appears once, at application startup. The application (after a successful login) could then open those 5 other Forms and the static class/property would be available to those Forms. There would be no way for a user to update the static property, and the Forms themselves wouldn't do it either (if they did, then someone coded those Forms wrong).

      Delete
  2. Hi Bonnie,

    This is a great example that shows what they Static classes and how they are practial used on a simple case ;)

    Vojislav

    ReplyDelete