简体   繁体   中英

WPF and C#: Trouble with Classes and Interfaces

I'm working on a bank account program. I'm using a base class, an interface, and two derived classes in addition to my main window class. I am making a WPF application, and so far I am able to populate a ListBox with an ArrayList of class objects in that app just fine. However, when I go to modify any of the objects in the ArrayList, I'm running into difficulty repopulating the ListBox correctly. Any help will be greatly appreciated!

This is my MainWindow code:

 public partial class MainWindow : Window
 {
    ArrayList bankAccountList = new ArrayList();

    BankAccount savingsAccount = new SavingsAccount("New", "Account", "newaccount");
    BankAccount checkingAccount = new CheckingAccount("New", "Account", "newaccount");
    IAccount iAccount;
    string typeOfAccount = "";

    public MainWindow()
    {
        InitializeComponent();
    }

    //When the user pushes the "Add A Saving Account" button, a new savings account is added to the ArrayList and displayed in the app.
    private void btnAddAccount_Click(object sender, RoutedEventArgs e)
    {
        iAccount = (IAccount)savingsAccount;

        savingsAccount.Deposit(0.00m);

        bankAccountList.Add(savingsAccount);
        lbxExistingAccounts.Items.Add(iAccount.AccountInformation());
        typeOfAccount = "savings";
    }

    //When the user pushes the "Add A Checking Account" button, a new checking account is added to the ArrayList and displayed in the app.
    private void btnAddCheckingAccount_Click(object sender, RoutedEventArgs e)
    {
        iAccount = (IAccount)checkingAccount;

        checkingAccount.Deposit(0.00m);

        bankAccountList.Add(checkingAccount);
        lbxExistingAccounts.Items.Add(iAccount.AccountInformation());
        typeOfAccount = "checking";
    }

    //When the user pushes the "Delete Account" button, the account is removed, and this change is shown in the app.
    private void btnDeleteAccount_Click(object sender, RoutedEventArgs e)
    {
        lbxExistingAccounts.Items.RemoveAt(lbxExistingAccounts.Items.IndexOf(lbxExistingAccounts.SelectedItem));
    }

    //The user can push the "Submit Changes" button to submit his or her changes to the number and name of the account.
    private void btnSubmitChanges_Click(object sender, RoutedEventArgs e)
    {
        try
        {

            for (int index = 0; index < bankAccountList.Count; index++)
            {
                if (index == lbxExistingAccounts.SelectedIndex)
                {
                    if (typeOfAccount == "savings")
                    {
                        savingsAccount.AccountNumber = tbxAccountNumber.Text;
                        savingsAccount.AccountOwnerFirstName = tbxFirstName.Text;
                        savingsAccount.AccountOwnerLastName = tbxLastName.Text;
                    }

                    else if (typeOfAccount == "checking")
                    {
                        checkingAccount.AccountNumber = tbxAccountNumber.Text;
                        checkingAccount.AccountOwnerFirstName = tbxFirstName.Text;
                        checkingAccount.AccountOwnerLastName = tbxLastName.Text;
                    }
                }
            }
            lbxExistingAccounts.Items.Clear();
            foreach (object accountObject in bankAccountList)
            {
                lbxExistingAccounts.Items.Add(accountObject);
            }
        }
        catch (FormatException)
        {
            MessageBox.Show("You may enter changes as letters, numbers, or both.");
        }

    }

This is my Interface code:

interface IAccount
{
    void SetAccountBalance(decimal accountBalance);
    string AccountInformation();
}

This is my base class code:

    abstract class BankAccount
{
    public string AccountNumber { get; set; }
    public string AccountOwnerFirstName { get; set; }
    public string AccountOwnerLastName { get; set; }
    public decimal AccountBalance { get; set; }
    public decimal AnnualInteresetRate { get; set; }
    public string TypeOfAccount { get; set; }

    public BankAccount(string accountOwnerFirstName, string accountOwnerLastName, string accountNumber)
    {
        AccountOwnerFirstName = accountOwnerFirstName;
        AccountOwnerLastName = accountOwnerLastName;
        AccountNumber = accountNumber;
    }

    public abstract void Deposit(decimal amount);

    public abstract void Withdraw(decimal amount);

    public decimal CalculateInterest()
    {
        return (this.AccountBalance * this.AnnualInteresetRate) / 100;
    }
} 

This is one of my derived classes. I made both pretty much the same.

    class SavingsAccount : BankAccount, IAccount
{
    public SavingsAccount(string accountOwnerFirstName, string accountOwnerLastName, string accountNumber)
        : base(accountOwnerFirstName, accountOwnerLastName, accountNumber)
    {
        AnnualInteresetRate = 0.95m;
    }

    public override void Deposit(decimal amount)
    {
        AccountBalance = AccountBalance + amount;
    }

    public override void Withdraw(decimal amount)
    {
        AccountBalance = AccountBalance - amount;
    }

    public void SetAccountBalance(decimal accountBalance)
    {
        AccountBalance = accountBalance;
    }

    public string AccountInformation()
    {
        return "Savings Account \n  " + AccountOwnerFirstName + " " + AccountOwnerLastName + ", Account#: " + AccountNumber + ", Balance: $" + AccountBalance;
    }
}

It looks like you are just starting out, which is good, because you are going to want to rework some things.

  1. You don't need to cast your derived objects to their base types. This type of casting is called "upcasting" and automatically works without any casting whatsoever.

  2. The code you posted is highly "WinForms-ish" and this is not a good approach in WPF. Start with making your account list an ObservableCollection and binding your ListBox's ItemsSource to it.

The property would look like:

public ObservableCollection<BankAccount> Accounts {get; set;}

Which should actually use INotifyPropertyChanged omitted for brevity, and the binding:

<ListBox "ItemsSource={Binding Accounts}"/>

Of course, that should go in a view model class, but you could start with your code-behind by setting:

DataContext = this;

Once that is working all your text boxes should be bound to properties of the data objects or of the view itself.

Here is a great tutorial on using MVVM with WPF ( MSDN ). Trust me, using this design pattern will make your work with WPF immensely easier, more extensible, and you will find that WPF was basically designed to use it. Using a WinForms approach is just going to cause you pain.

Please let me know if I can assist further or clarify anything!

I would recommend using ObservableCollection for your collection, so that any changes made to the items would be reflected visually without any additional work. It wouldn't require any significant changes. All you would do is switch your ArrayList for an ObservableCollection .

http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx

I would also highly recommend implementation of INotiftyPropertyChanged interfrace for your objects, so that when account information is changed, appropriate subscribers are notified.

http://msdn.microsoft.com/en-us/library/vstudio/system.componentmodel.inotifypropertychanged

I've been using both of those extensively with my WPF applications.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM