 |
.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
|
|
|

September 1st, 2008, 07:21 AM
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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
|

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

September 2nd, 2008, 09:02 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
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 -/
|

September 3rd, 2008, 07:37 AM
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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
|

September 3rd, 2008, 07:44 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
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 -/
|

September 3rd, 2008, 09:27 AM
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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
|

September 3rd, 2008, 09:32 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
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 -/
|

September 3rd, 2008, 11:38 AM
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
Thanks,
I will try to do that....
|

September 6th, 2008, 12:14 PM
|
Friend of Wrox
|
|
Join Date: Oct 2003
Posts: 290
Thanks: 24
Thanked 0 Times in 0 Posts
|
|
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;
}
}
}
|

September 7th, 2008, 05:32 AM
|
 |
Friend of Wrox
|
|
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
|
|
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 -/
|
|
 |