views:

118

answers:

3

first things first. I have the following classes:

class Employee
{
    private int employeeID;
    private string firstName;
    private string lastName;
    private bool eligibleOT;
    private int positionID;
    private string positionName;
    private ArrayList arrPhone;
    public IList<Sector> ArrSector {get; private set;}

    //the constructor method takes in all the information of the employee
    public Employee(int empID, string fname, string lname, bool elOT, int pos, string posname)
    {
        employeeID = empID;
        firstName = fname;
        lastName = lname;
        eligibleOT = elOT;
        positionID = pos;
        positionName = posname;
        arrPhone = new ArrayList();
        ArrSector = new List<Sector>();
    }

    //the constructor method takes in the employee id, the first name and the last name of the employee
    public Employee(int empid, string firstname,string lastname)
    {
        employeeID = empid;
        firstName = firstname;
        lastName = lastname;
    }

    //overtides the first name and the last name as a string.
    public override string ToString()
    {
        return firstName +" "+lastName;
    }



    public int EmployeeID
    {
        get { return employeeID; }
        set { employeeID = value; }
    }

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }

    public bool EligibleOT
    {
        get { return eligibleOT; }
        set { eligibleOT = value; }
    }

    public int PositionID
    {
        get { return positionID; }
        set { positionID = value; }
    }

    public string PositionName
    {
        get { return positionName; }
        set { positionName = value; }
    }

    public ArrayList ArrPhone
    {
        get { return arrPhone; }
        set { arrPhone = value; }
    }



    // The function assigns all the variables associated to the employee to a new object.
    public static object DeepClone(object obj)
    {
        object objResult = null;
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, obj);
            ms.Position = 0;
            objResult = bf.Deserialize(ms);
        }
        return objResult;
    }

   //Memento pattern is used to save the employee state.
   //The changes will be rolled back if the update button not clicked
    public class Memento : IMemento
    {
        private Employee originator = null;
        private int employeeID;
        private string firstName;
        private string lastName;
        private bool eligibleOT;
        private int positionID;
        private string positionName;
        private ArrayList arrPhone;
        private IList<Sector> arrSector;

        public Memento(Employee data)
        {
            this.employeeID = data.EmployeeID;
            this.firstName = data.FirstName;
            this.lastName = data.LastName;
            this.eligibleOT = data.EligibleOT;
            this.positionID = data.PositionID;
            this.positionName = data.PositionName;
            this.arrPhone = data.ArrPhone;

            this.originator = data;
            this.arrSector = Extensions.Clone<Sector>(data.ArrSector);
        }

}

I am using C sharp in winforms. the front end of my application has a listbox on the left end side which has the first name of the employee.on the left hand side, there are different textboxes which correspond to the employee selected in the list box. I have coded it in such a way that everytime i select an employee, its attributes, like the employee id, name, position, etc are displayed in these fields.

if the user changes any attribute of the employee, he has to click an update button to make the changes to the database. now the real problem, when the user changes any field of the selected employee, and selects another employee without clicking the update button, i want to show a pop up box to tell the user that if he selects another employee , all the changes will be lost.

for this reason i have created the momento class to hold the previous state of the employee. i have also tried overloading the == operator

        public static bool operator ==(Employee e, Memento m)
        {
            return ((e.employeeID == m.employeeID) &&
               (e.firstName == m.firstName) &&
               e.lastName == m.lastName &&
               e.eligibleOT == m.eligibleOT &&
               e.positionID == m.positionID &&
               e.positionName == m.positionName &&
               e.arrPhone == m.arrPhone &&
               e.ArrSector == m.arrSector);
        }

        public static bool operator !=(Employee e, Memento m)
        {
            return (e.employeeID != m.employeeID);
        }

my idea was to compare the two object... but m not successfull. how do i do it??how do i show the popup if changes are made.?where do i place the code to show the popup?

A: 

Have a look at the IComparable interface. It requires you to implement the method you need t make such a comparison. KB article, Hopefully it turn English for you, on my PC it turns always German.

-sa

Sascha
MSDN: The IComparable<(Of <(T>)>) interface defines the CompareTo method, which determines the sort order of instances of the implementing type. The IEquatable<(Of <(T>)>) interface defines the Equals method, which determines the equality of instances of the implementing type.
Andreas Niedermair
CompareTo results in a return value of 0 if the compared objects are equal. So you can use IComparable to test for equality. A side effect is comparison for sorting.Thanks for voting down for a functional answer.
Sascha
thanks for your suspicion! ... if it was only me ...
Andreas Niedermair
@Sascha: While I didn't downvote, the `IComparable` interface *is* designed for sorting and relative comparison, not specifically for equality checking. Prior to 2.0 it was the primary interface for equality checking, but 2.0 introduced the `IEquatable` interface (along with the `IEqualityComparer` interface to supplement `IComparer`) that didn't require that the implementation be able to determine which instance is "bigger", just whether or not two instances were equivalent.
Adam Robinson
A: 

you need to implement IEquatable<T>

If you implement IEquatable<(Of <(T>)>), you should also override the base class implementations of Object..::.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<(Of <(T>)>)..::.Equals method. If you do override Object..::.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals method return consistent results.

Andreas Niedermair
+2  A: 

One word of warning...it's generally not a good idea to have different logic in your == and != operators. It's somewhat unintuitive to be able to have both == and != be false at the same time.

if(!(a == b) && !(a != b))
{
    // head explodes
}

That aside, I'm guessing that you have your Employee class referenced as an object (or other parent class) in your comparison code. Maybe something like this:

if(listBox1.SelectedItem != currentMemento)
{
    ...
}

If this is the case, then the compiler isn't binding the != to your custom implementation. Cast listBox1.SelectedItem to Employee in order to force that.

if((Employee)listBox1.SelectedItem != currentMemento)
{
    ...
}

There are, however, many other approaches that you could take to solve this issue:

  • Make the implementation entirely on the GUI side, with a bool that gets set to true when the data in the text fields changes, then check that flag when changing employees
  • Implement the IComparable or IEquatable interfaces
  • Override the Equals method on the Employee and/or Memento class

(If you go with the second option, it's generally recommended that you complete the third as well)

Example

Here's an example of what you could do (I'm assuming you have a ListBox named listBox1 and you've attached to the SelectedIndexChanged event with the listBox1_SelectedIndexChanged function):

private Employee lastSelectedEmployee;
private Memento selectedMemento;

void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    Employee selectedEmployee = (Employee)listBox1.SelectedItem;

    if(lastSelectedEmployee != null && lastSelectedEmployee != selectedEmployee)
    {
        if(/*changes exist*/)
        {
            if(/*cancel changes*/)
            {
                listBox1.SelectedItem = lastSelectedEmployee;

                return;
            }
        }
    }

    lastSelectedEmployee = selectedEmployee;
    selectedMemento = //create the memento based on selectedEmployee;
}

You'll have to provide your own logic for the areas I've left comments, but the idea should be pretty straightforward.

Adam Robinson
Adam, your answer was really helpful. bt i have a doubt. where do i place the code for comparison before the user switches to another employee. I am a newbie, so please bear.
reggie
@reggie: There's no *completely* clean way to do this, since the `ListBox` doesn't provide you with a cancelable event for selection changing. What you'll probably have to do is place this code in the `SelectedItemChanged` event, then set it back to the last `Employee` (which you'll have to cache) if the user elects to cancel.
Adam Robinson
ohh...will try that....thanks adam..please lookin into the question after an hour or somethin for my comments...thanks again..
reggie
there is no selecteditemchanged event...but selectedvaluechanged...tried it...doesnt work
reggie
@reggie: In what way does it not work?
Adam Robinson
i cannot differentiate between the old value and new value...when i message box the employee name, it gives me the employee name of the selected employee.the problem i have now is to figure out how to put in the changed value into another object before the employee in the list is changed. and then compare the old object and the new object.
reggie
@reggie: See if my edit is more helpful.
Adam Robinson