Lithicas
Lithicas

Reputation: 4013

Manipulate form control properties from other classes?

I'm trying to manipulate the properties of a control in my main form via one of my classes.

Basically I'm trying to update a label, I've set it to public like so:

public Label DicerollLabel;

And I'm refering to my main form from my class like this:

 private Form1 _mainForm;

When I try to access the label and set a value to it like this:

_mainForm.DicerollLabel.Text = "Hello World!";

I get the following error: An unhandled exception of type 'System.NullReferenceException' occurred.

My entire code to the two files involed is below:

Main Form:

namespace BettingGame
{
    public partial class Form1 : Form
    {
        private Player _playerOne;
        private Player _playerTwo;
        private DiceRoller _diceRoller;
        private decimal _prizePool;
        private Random _random;

        public int ProgressBar
        {
            get {return progressBar1.Value;}
            set { progressBar1.Value = value; }
        }

        public Label DicerollLabel;

        public Form1()
        {
            InitializeComponent();
            _playerOne = new Player() {PlayerName = "x", PlayerFunds = 100};
            _playerTwo = new Player() {PlayerName = "x", PlayerFunds = 100};
            _diceRoller = new DiceRoller();
            _random = new Random();

            playerOneFundsLabel.Text = "Funds: " + _playerOne.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
            playerTwoFundsLabel.Text = "Funds: " + _playerTwo.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
            PrizeAmountLabel.Text = "";
            diceRollLabel.Text = "";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            _playerOne.PlayerBetAmount = (decimal) playerOneBet.Value;
            _playerTwo.PlayerBetAmount = (decimal) playerTwoBet.Value;

            if (!(_playerOne.PlayerBetAmount <= 0) || !(_playerTwo.PlayerBetAmount <= 0) 
                && (_playerOne.PlayerBetAmount > 0) && (_playerTwo.PlayerBetAmount > 0))
            {
                _prizePool = _playerOne.PlayerBet() + _playerTwo.PlayerBet();
                PrizeAmountLabel.Text = _prizePool.ToString(CultureInfo.CurrentCulture);
                FormUpdate();
            }
            else
            {
                MessageBox.Show("Invalid bets! Bet amount must be greater than 0!");
            }

        }

        private void FormUpdate()
        {
            playerOneFundsLabel.Text = "Funds: " + _playerOne.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
            playerTwoFundsLabel.Text = "Funds: " + _playerTwo.PlayerFunds.ToString(CultureInfo.CurrentCulture) + "$";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //for (int i = 0; i < 45; i++)
            //{
            //    int value = _random.Next(1, 50);
            //    diceRollLabel.Text = value.ToString();
            //    diceRollLabel.Update();
            //    Thread.Sleep(50);
            //}

            _diceRoller.RollDice();
        }
    }
}

And the DiceRoller class:

    namespace BettingGame
{
    class DiceRoller
    {
        private Random _random = new Random();
        private Form1 _mainForm;

        public void RollDice()
        {
            _mainForm.DicerollLabel.Text = "Hello World!";
        }
    }

What am I doing wrong? Note that I'm only in my second week of programming so I'm still learning!

Upvotes: 0

Views: 90

Answers (2)

Douglas Zare
Douglas Zare

Reputation: 3316

You need to have a reference to the Form1 created. This is not named Form1, but within the Form1 you can refer to it using the keyword "this" and you can pass that into a constructor for your DiceRoller class.

class DiceRoller
{
    private Random _random = new Random();
    private Form1 _mainForm;

    public DiceRoller(Form1 f)
    {
        _mainForm = f;
    }

    public void RollDice()
    {
        _mainForm.DicerollLabel.Text = "Hello World!";
    }
}

Then you call this within your constructor for Form1:

    public Form1()
    {
        InitializeComponent();
        _playerOne = new Player() {PlayerName = "x", PlayerFunds = 100};
        _playerTwo = new Player() {PlayerName = "x", PlayerFunds = 100};
        _diceRoller = new DiceRoller(this);
    ....

These are the minimal changes needed to make your code work. However, you might consider other changes such as passing in the label instead of the form.

Upvotes: 1

Sam Axe
Sam Axe

Reputation: 33738

change your DiceRoller class to define the following constructor:

public DiceRoller(Form1 host) {
  _mainForm = host;
}

Then in your Form1 where you create an instance of DiceRoller:

private DiceRoller _diceRoller = new DiceRoller(this);

This is a really terrible design long term. It's definitely code I would expect from a new programmer - so don't feel bad. You're doing fine.

In the future try to think about reusability. By making your DiceRoller dependent on Form1 (and the specific controls in Form1) you are faced with two challenges later on: 1. You can not use DiceRoller in another project (or possibly even in your same project) without modification. 2. If you change any of the controls that DiceRoller depends upon you must also change DiceRoller.

I'll let you think about how you might avoid these issues. I'm sure if you need help with them you'l post another question. :)

Upvotes: 1

Related Questions