Listbox contains does not find item, cannot remove an item - c#

I add items to a list box like so:
foreach(myObject object in ListOfObjects)
{
mylistbox1.add(object);
}
foreach(myObject object in ListOfObjectsTwo)
{
mylistbox2.add(object);
}
Further on, I want to remove a couple of items given a specific condition. This is what I do:
foreach(myObject object in ListOfObjects3)
{
mylistbox1.items.remove(object);
mylistbox2.items.remove(object);
}
This only seems to work for mylistbox1 but not mylistbox2. When I debug, I can see that the item is there and that it has the exact same properties as the one I'm trying to remove. When I try to check if the listbox contains the item im trying to remove, it returns false.
I can't seem to make sense of it.

I c# all lists operation that are in some way required to compare objects use Equals or GetHashCode methods. In your case Equals and the default implementation wont check properties values it will only verify if the passed as argument object is in list so consider if you have the same instance in your list or just two different instances that happened to have the same properties. (the helpful VS option is make object id it will mark instance with a number)
If this is the case then you should consider overriding Equals method or find the instance that you want to delete with linq for example and pas that object to Remove method.

Related

Checking class types in a list box

I am building a GUI where I have two classes, Student and Graduate. Graduate is a child class of Student. The user will fill out forms to add the student to the list. In order to add said information to a view form I need to check what the selected item's type is. I have tried
if(view_list.selectedItem.GetType == Student)
but it doesn't work. How would I be able to check the type of the selected item?
In short, you'll need to compare XXX.GetType() with typeof(YOUR_TYPE).
As for the reason, if you have ever stared at the IntelliCode tips provided by Visual Studio, you should see that the function object.GetType() returns Type
However, Student or any other primitive types like int, string, etc. has type of class
You can't compare two values with different types (in this case the left hand side is of Type but the right hand side is of class)
What typeof() does is to get the Type of a class.
There are a couple of problems.
The GetType which you are trying to use is actually a method, not a property, so you need to call it as GetType().
The next is that you need to use typeof(Student) to compare.
And if view_list is a Winforms ListView, then SelectedItem should start with uppercase S
So then you code should be.
if (view_list.SelectedItem.GetType() == typeof(Student))
{
//Do your stuff
}

Comparing Items in two ObservableCollections

I have two ObservableCollections, one that contains a current list of employees and one that contains a new one. If the new one contains an employee that is not in the old list, I want to add it to the old list.
If the new list does not contain an employee in the old list, I want to remove it from the old list. (I hope that makes sense).
Here is what I have tried;
foreach (var employee in _currentUsers.ToList())
{
if (!newUsers.Contains(employee))
{
Dispatcher.Invoke(() =>
{
_currentUsers.Remove(employee);
CurrentUsageDataGrid.Items.Refresh();
});
}
}
foreach (var employee in newUsers)
{
if (!_currentUsers.Contains(employee))
{
Dispatcher.Invoke(() =>
{
_currentUsers.Add(employee);
CurrentUsageDataGrid.Items.Refresh();
});
}
}
This is not working as even when I know that the lists haven't changed the Dispatcher.Invoke() is still firing. Am I misunderstanding how Contains operates and/or is there a 'better' way of performing a check like this?
Does your employee class implement IEquatable<T> interface, the method Contains of ObservableCollection will use Equal in that interface to compare object.
Otherwise you may need to use Linq to check for existing employee instead of using Contains
More reference on MSDN, https://msdn.microsoft.com/en-us/library/ms132407(v=vs.100).aspx
As was mentioned above you need to implement/override an Equal method for the comparison. When you do a "Contains" check on 2 class objects, it checks if the 2 objects are equal (not if their properties are). You can do the equal using an id, or you could compute a hashvalue and compare those.

A change in one object changes the second one too

I'm creating two objects and assign them with a data from IsolatedStorage.
But when I change one object the second one changes too. ( I think the problem may be the pointers are the same, but I can't solve it. )
private ArrayOfClsSimpleData lstUsers;
private ArrayOfClsSimpleData tmpLstUsers;
in class' globals
tmpLstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("users");
The first status of the arrays:
Debug.Write(lstUsers.Count)
Output: 2
Debug.Write(tmpLstUsers.Count)
Output: 2
The counts are the same as expected. But, after I add an item to one list, the other list gets updated too and the counts are still same.
lstUsers.Add(new ArrayOfClsSimpleData());
Debug.Write(lstUsers.Count)
Output: 3
Debug.Write(tmpLstUsers.Count)
Output: 3
EDIT : IsolatedStorageHelper class is something to help to get objects, save object etc. that I do use for simplifying things, so just think it as getting objects from IsolatedStorage.
it is implemented like this:
public static T GetObject<T>(string key)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(key))
{
return (T)IsolatedStorageSettings.ApplicationSettings[key]; // return the object
}
return default(T); // if key doesn't exists , return default object
}
So it just gets it from IsolatedStorage.
If you don't know isolated storage you can see it from here
So, how can I fix the code so that I can change one without changing the other?
So, basically lstUsers and tmpLstUsers are references to the same object. All you have to do is to create a new one and copy content from the original. If you need a quick solution, then you can do it like this (code below). I just guess that ArrayOfClsSimpleData is some kind of array.
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey");
tmpLstUsers = new ArrayOfClsSimpleData();
foreach (object user in lstUsers) // I don't know the type of objects in ArrayOfClsSimpleData, so I wrote 'object', but you should use the actual type
tmpLstUsers.Add(user);
The problem is that IsolatedStorage is just returning two pointers to the same data. So unless you copy the data, all changes will ultimately be to the same underlying data.
Think of it as two copies of your home address. Anything you change on your home affects all copies of your address since it is just an address and not the home itself.
What you will want to do is clone your object. Built in collections have clone or copy methods built in to do shallow copies, or if you built something yourself you will need to implement it yourself
The easiest way is to implement the IClonable interface and to use the clone method to achieve your copying.
https://msdn.microsoft.com/en-us/library/System.ICloneable.aspx
This basically involves going through and calling member wise clone for each complex object (which will copy all value types for you)
https://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx
I don't think cloning is necessary. Just create a new list instead of operating on the same instance. You can do that by calling ToList() on the returned instance:
lstUsers = IsolatedStorageHelper.GetObject<ArrayOfClsSimpleData>("myKey").ToList();
Can't you use the Clone() method of IClonable while fetching the object? looks like both list objects are getting same reference objects.

list Remove method does not remove list item

I have an ASP.Net web app written in C# and it has a List<Employee> object called AffectedEmployees, where Employee is a class I've written. AffectedEmployees is also a property of another class I've written called LitHoldDetails, but I don't think that's pertinent; I just include the information in case I'm wrong, which has, of course, never happened. ;) Anyway, I need to remove a particular Employee object from AffectedEmployees. I first just did a Remove() (Add() works, BTW), but the Employee in question was not removed from AffectedEmployees. So I checked to make sure it was really there by doing a call to Contains(). Contains() doesn't find the Employee in AffectedEmployees, but if I examine the list and compare it to the Employee in the debugger, the Employee is indeed in Affected Employees. I've compared the two with a fine tooth comb and I see no difference in the data. What am I doing wrong? Here's my code:
Employee emp = new Employee().FindByLogin(item.Key.ToString());
if (CurrentLitHoldDetails.AffectedEmployees.Contains(emp))
CurrentLitHoldDetails.AffectedEmployees.Remove(emp);
Note: FindByLogin() initiates emp and fills it with data. item.Key.ToString() is coming from a Hashtable that contains all the Employees I need to remove
You're creating a new Employee object that couldn't possibly exist in the list yet, then trying to remove it. So it doesn't find that exact object (even if the contents of the new Employee object match some other Employee object in the list) and doesn't remove it. If you place a breakpoint on the line with Remove on it, you'll see it doesn't get hit.
Try using RemoveAll to remove all elements matching some condition. (I'm doing a bit of guessing here since I don't know what your classes look like exactly.)
CurrentLitHoldDetails.AffectedEmployees.RemoveAll(x => x.Login == item.Key.ToString());
Remove and Contains test for the presence of the exact object you're trying to remove, not just one with identical data. So when you create a new Employee object, it's looking for that exact object. It doesn't find it, because that exact object has never been added to AffectedEmployees.
This is called "reference equality" and is the default behavior. If you want Remove and Contains to determine equality based on property values, you will need to override the Equals and GetHashCode methods on your Employee object. (See here for Microsoft's documentation on Object.GetHashCode().)

Why in C# , in the control combobox , i can't change the property SelectedItem?

I have a simple class called Tuple. which looks like this :
class tuple
{
string name;
string code
}
i inserted few of these items into a combobox, now when i want to select through the code some item, i try to write
myComboBox.selectedItem = new tuple("Hello" , "5");
and of course it doesn't work at all and the selected item doesn't change.
let's assume the items list of the combobox contains an item that looks like this, how can he compare the items ?
i inherited iComparable and implemented it, but unfortunately he doesn't use it at all..
how can i set the selected item ? should i run an all the items with a loop and compare them by myself ?
thanks
You'll need to override the Equals method in order to provide a custom comparison that is able to assert if two tuple instance represent the same value.
You should also check the following MSDN entries about how to properly override the Equals method:
Implementing the Equals Method
Guidelines for Implementing Equals and the Equality Operator (==)
Microsoft Code Analysis Rule about overriding GetHashCode whenever you override Equals:
CA2218: Override GetHashCode on overriding Equals
The value assigned to SelectedItem must be one of the items that already exists in the combo box data source. From the MSDN documentation (emphasis mine):
When you set the SelectedItem property
to an object, the ComboBox attempts to
make that object the currently
selected one in the list. If the
object is found in the list, it is
displayed in the edit portion of the
ComboBox and the SelectedIndex
property is set to the corresponding
index. If the object does not exist in
the list, the SelectedIndex property
is left at its current value.
By using:
myComboBox.SelectedItem = new tuple("Hello" , "5");
you are attempting to assign it a new instance of a tuple, that can't possibly be in the associated data source.
The correct implementation would be to find the existing item in the data source (by whatever criteria is appropriate to define a match) and assign that to SelectedItem. LINQ can make this quite easy:
myComboBox.SelectedItem =
myComboBox.Items.OfType<tuple>()
.Where( t => t.name == "Hello" && t.code == 5 )
.FirstOrDefault();
Also, if you're using .NET 4.0, you don't have to implement your own tuple class, there's a new generic implementation Tuple<T1,T2> which already has structural equality semantics built into it.

Categories