Search code examples
c#winformsclassframeworksglobal-variables

How do I access a variable from different classes?


I have a UserControl Class, a Main Form Class and a DbConn Class.

I want to access the DbConn-Class 'as Middleman' from both other classes. So the UserControl should set a string of the DbConn-Class and the Main Form Class should read the string from it again.

(Or it should do that for now. Later this DbConn-Class should have track of the connection cred and handle all the connection stuff to my database to get some clearence between the single parts. At the moment everything is within the Main Form class, but with the planned additions this code will be hard to maintain, if I don't divide the Class into diffent Classes, which should handle only one thing, e.g. DatabaseConnection, different Frontendparts, etc.)

This is the UserControl Class:

namespace mySQL_Project
{
    public partial class SettingsControl : UserControl
    {
        DbConn dbConn = new DbConn();

        public SettingsControl()
        {
            InitializeComponent();
        }
        private void Button_SetDB_Click(object sender, EventArgs e)
        {
            String connectString = tb_stringtext;
            dbConn.connParamNewSQLite(connectString);
        }
    }
}

This is the Main Class:

namespace mySQL_Project
{
    public partial class Main : Form
    {
        DbConn dbConn = new DbConn();

        public Main()
        {
            InitializeComponent();
        }
        private void textBox_getDBConn_Click(object sender, EventArgs e)
        {
           label_dbinfo.Text = dbConn.connParamGetSQLite(); //should get Text set in userControl
        }
    }
}

and this is the DbConn Class:


namespace mySQL_Project
{
    internal class DbConn
    {
        private string conn;
        public void connParamNewSQLite(string connectionString)
        {
            conn = connectionString;
        }

        public string connParamGetSQLite()
        {
            return conn;
        }

        public int DbGetSumApples(){
            cmd = new SQLiteCommand();
            cmd.CommandText = @"SELECT sum FROM inv WHERE ID=@AI";
            cmd.Parameters.AddWithValue("@AI", "3"); //Apple-ID
            cmd.Connection = conn;
            return cmd.ExecuteScalar().ToString();
        }
    }
}

But this doesn't give me the string I've set in the UserControl-Class.

The Idea is to have something like a global variable. Eg. the Class has passed in some connection variables from one class by the connParamNewSQLite() Function and another class will use at example the DbGetSumApples() Function within the same DbConn Class to establish a connection to the database. Then the DbGetSumApples() Function will need the connection-parameters passed earlier by the connParamNewSQLite() Function.
(The DbGetSumApples() Function wont work as is, but I hope to make clear, what the DbConn class should do in the end. Also the DbConn class is instantiated twice because otherwise I wasn't able to use the functions in the second class)

What should I change within the code, so that both classes know the DbConn class? Or is there even a better approach to handle this in form of 'good coding practice'? (e.g. in consideration of Multiple Threads, even if it's not planned for now.)


Solution

  • If You create only one DbConn class then you can implement it as a singleton.

    public sealed class DbConn
    {
        private static DbConninstance = null;
        private static readonly object padlock = new object();
        private string conn;
    
        public static DbConn Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new DbConn();
                    }
                    return instance;
                }
            }
        }
        public void connParamNewSQLite(string connectionString)
        {
            conn = connectionString;
        }
    
        public string connParamGetSQLite()
        {
            return conn;
        }
    
        public int DbGetSumApples(){
            cmd = new SQLiteCommand();
            cmd.CommandText = @"SELECT sum FROM inv WHERE ID=@AI";
            cmd.Parameters.AddWithValue("@AI", "3"); //Apple-ID
            cmd.Connection = conn;
            return cmd.ExecuteScalar().ToString();
        }
    }
    

    This way you do not need a global variable. Instead you can call it now from other class simply calling it like this DbConn.Instance.DbGetSumApples()

    For example:

    public partial class SettingsControl : UserControl
    {
    
        public SettingsControl()
        {
            InitializeComponent();
        }
        private void Button_SetDB_Click(object sender, EventArgs e)
        {
            String connectString = tb_stringtext;
            DbConn.Instance.connParamNewSQLite(connectString);
        }
    }
    

    Here is more material about singleton pattern. Implementing the Singleton Pattern in C#