Wrox Programmer Forums
|
.NET Framework 2.0 For discussion of the Microsoft .NET Framework 2.0.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the .NET Framework 2.0 section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old September 1st, 2008, 07:21 AM
Friend of Wrox
 
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
Default HOW TO ADD AN EVENT HANDLER

Hi,

I am trying to improve my OO skills and as everyone else I am using a bank account class to learn some OO concepts such as encapsulation, usability etc...

Here is an extract of my Account class:

public class Account
{
    private decimal _balance;

        public Account(decimal initialAmount)
    {
       _balance = initialAmount;
    }

        public decimal Balance
    {
        get { return _balance; }
    }

        public void Withdraw(decimal amountToWithdraw)
    {... }

        public void Deposit(decimal amountToDeposit)
    {... }

}

This is how I call my class:

public partial class AccountForm : Form
{
   private const decimal _initialAmount = 300;
   private Account _account;

   public AccountForm()
   {
      _account = new Account(_initialAmount);
    DisplayBalance();
    statusLabel.Text = "Your account has been opened.";
   }

   private void DisplayBalance()
   {
    balanceValueLabel.Text = _account.Balance.ToString("C");
   }

   private void depositButton_Click(object sender, EventArgs e)
   {
       ....
    _account.Deposit(amountToDeposit);
    DisplayBalance();
    statusLabel.Text = "Amount has been deposited successfully.";
    }

    private void withdrawButton_Click(object sender, EventArgs e)
    {
    .......
        _account.Withdraw(amountToWithdraw);
    DisplayBalance();
    statusLabel.Text = "Amount has been withdrawn successfully.";
     }
}

This is all working fine. However, I would like to use an event handler as follows:

1- I would like to create an event to indicate changes in the Balance property.

2 - Then I would like to modify the form so that it uses this event to display the current balance (instead of using the DisplayBalance method after each button click).

I would appreciate very very much if someone could make changes to my sample code above and show me how to create an event and how to change the form to use the event.

Cheers

P
 
Old September 2nd, 2008, 01:01 AM
Friend of Wrox
 
Join Date: Sep 2005
Posts: 812
Thanks: 1
Thanked 53 Times in 49 Posts
Default

Hi

You can use Addhandler to handle .NET events (http://msdn.microsoft.com/en-us/libr...ka(VS.80).aspx)

http://dotnetdud.blogspot.com/2008/0...using-net.html

You can create your own events using (http://www.simple-talk.com/dotnet/.n...n-vb.net-2005/)

Cheers
Shasur

http://www.dotnetdud.blogspot.com

VBA Tips & Tricks (http://www.vbadud.blogspot.com)
 
Old September 2nd, 2008, 09:02 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

You can implement the INotifyPropertyChanged interface on custom classes, and then use Data Binding to link your controls to your custom class instance.

/- Sam Judson : Wrox Technical Editor -/
 
Old September 3rd, 2008, 07:37 AM
Friend of Wrox
 
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
Default

Hi Sam, Shasur,

Many thanks for your reply.

Sam, I was wondering if you could provide some sample code based on my Account class of how to implement the INotifyPropertyChanged interface.

I have the impression that the Balance property cannot be read only. Is my assupmtion right?

Cheers

P
 
Old September 3rd, 2008, 07:44 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

You can simply follow the guidelines presented on the INotifyPropertyChanged documentation. The Balance property can be read only - but you have to then remember to raise the event when you change the underlying value, and not when you set the property.

http://msdn.microsoft.com/en-us/libr...tychanged.aspx

N.B. In C# 3.0 you can set a Property setter to have a different access modifier to a getter, i.e. you could set the 'set' for Balance to be private.
Code:
public class Account : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyChanged(string propertyName)
    {
        if( PropertyChanged != null )
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private decimal _balance;

    public Account(decimal initialAmount)
    {
       _balance = initialAmount;
    }

    public decimal Balance
    {
        get { return _balance; }
    }

    public void Withdraw(decimal amountToWithdraw)
    {
        ...
        NotifyChanged("Balance");
    }

    public void Deposit(decimal amountToDeposit)
    {
        ... 
        NotifyChanged("Balance");
    }

}
/- Sam Judson : Wrox Technical Editor -/
 
Old September 3rd, 2008, 09:27 AM
Friend of Wrox
 
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
Default

Hi Sam,

I will have a look at the link you provided. Also thanks for the sample code.

I have one question about your sample code.

You are raising the event handler inside the Deposit and Withdraw methods, right? So this meaans the event will be raised only when the user clicks the deposit or withdraw button in the user interface.

I thought it was better to raise the event when the Balance property changed itself. This way if the balance has been modified by an agent other than the user i.e. a new class that adds interest to an account balance at the start of each month then the balance would always be up to date.

Am I right in assuming that other agents rather than the user can also change the balance property?

How do we take care of that?

Cheers

P
 
Old September 3rd, 2008, 09:32 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

No one else can modify the balance property because you have set it to read only - that's your decision, not mine. If you want others to modify it then add a setter, move the NotifyChange in there, and in the deposit and withdraw methods use "Balance" and NOT "_balance" to change the balance.

/- Sam Judson : Wrox Technical Editor -/
 
Old September 3rd, 2008, 11:38 AM
Friend of Wrox
 
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
Default

Thanks,

I will try to do that....
 
Old September 6th, 2008, 12:14 PM
Friend of Wrox
 
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
Default

Hi Sam,

I have tried the sample code you kindly provided to add an event handler to the Balance property but the PropertyChanged even is always evaluating to null and nothing happens when I try to make a deposit or withdraw.

Could you please have a look at my full code below (Account and AccountForm classes to see if you can spot where the problem is?

Cheers

ACCOUNT CLASS

using System;
using System.ComponentModel;

namespace Task
{
    public class Account: INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NofifyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
            }
        }


        private decimal _balance;

        public Account(decimal initialAmount)
        {
            // use initialAmount to set the _balance field
            _balance = initialAmount;
        }


        public decimal Balance
        {
            get { return _balance; }
        }

        public void Withdraw(decimal amountToWithdraw)
        {
            if (amountToWithdraw <= 0)
                throw new ArgumentOutOfRangeException();

            if (_balance < amountToWithdraw)
                throw new InvalidOperationException();

            _balance -= amountToWithdraw;
            NofifyChanged("Balance");

        }

        public void Deposit(decimal amountToDeposit)
        {
            if (amountToDeposit <= 0)
                throw new ArgumentOutOfRangeException();

            _balance += amountToDeposit;
            NofifyChanged("Balance");
        }

    }
}

ACCOUNTFORM CLASS


using System;
using System.Windows.Forms;

namespace Task
{
    public partial class AccountForm : Form
    {
        private const decimal _initialAmount = 300;

        private Account _account;

        public AccountForm()
        {
            InitializeComponent();

            _account = new Account(_initialAmount);


            EnableButtons(false);
            DisplayBalance();
            statusLabel.Text = "Your account has been opened.";
        }

        private void DisplayBalance()
        {

                     balanceValueLabel.Text = _account.Balance.ToString();

        }

        private void depositButton_Click(object sender, EventArgs e)
        {
            decimal amountToDeposit;
            if (ValidateAmountInput(out amountToDeposit) == false)
                return;

            try
            {


                                _account.Deposit(amountToDeposit);

                //DisplayBalance();
                statusLabel.Text = "Amount has been deposited successfully.";
            }
            catch (Exception ex)
            {
                statusLabel.Text = ex.Message;
            }
        }

        private void withdrawButton_Click(object sender, EventArgs e)
        {
            decimal amountToWithdraw;
            if (ValidateAmountInput(out amountToWithdraw) == false)
                return;

            try
            {

                               _account.Withdraw(amountToWithdraw);

                //DisplayBalance();
                statusLabel.Text = "Amount has been withdrawn successfully.";
            }
            catch (Exception ex)
            {
                statusLabel.Text = ex.Message;
            }
        }

        private void amountText_TextChanged(object sender, EventArgs e)
        {

            EnableButtons(amountText.Text.Trim().Length > 0);
        }

        private void EnableButtons(bool enable)
        {

            depositButton.Enabled = enable;
            withdrawButton.Enabled = enable;
        }

        private bool ValidateAmountInput(out decimal value)
        {

            if (decimal.TryParse(amountText.Text, out value) == false)
            {
                statusLabel.Text = "The entered amount is not of decimal type.";
                amountText.Text = String.Empty;
                return false;
            }

            amountText.Text = String.Empty;
            return true;
        }
    }
}
 
Old September 7th, 2008, 05:32 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

You have to actually then use data binding to hook the balance up with your textbox. The following should do that:

balanceValueLabel.DataBindings(new Binding("Text", _account, "Balance"));

/- Sam Judson : Wrox Technical Editor -/





Similar Threads
Thread Thread Starter Forum Replies Last Post
Chapter 19, p.970, Can't Add Event Handler Spasticus BOOK: Ivor Horton's Beginning Visual C++ 2005 0 January 6th, 2008 05:13 PM
Event handler samir_katore Pro VB 6 6 June 8th, 2006 01:22 PM
Event handler problem carro123 Javascript How-To 1 May 20th, 2005 03:30 PM
PreDefined Event Handler mark C# 1 June 7th, 2003 04:47 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.