In my app, I store objects(of Class1) on two lists (of type List<Class1>).
The first list is used to store all the objects added in the app while the other list filters few of the objects based on a filtering function.
Both the lists are part of a class file(Class2) which I store in the app data using IsolatedStorage.ApplicationSettings .
When I access an object in the app, the object is extracted from the list and on changing any of its property, I click on a 'done' button.
done_event
{
remove the object from the first list;
remove it from the second list based on a simple condition (#2);
change its properties;
add the new object back to the first list;
run the filtering function to add the new object to the second list if necessary;
}
Everything works fine when I am using it after installing it on the emulator/device but once I exit the app and open it back again and change a property of an object, the new object is removed and added in the first list, however, it is not removed from the second list (the second list populates with two objects instead of one, I used breakpoints and figured out the object was not getting removed from the second list at step #2).
I am new to using IsolatedStorage, so don't know the drawbacks. Please help
I don't know how you load the objects of the two lists after a restart of the app, but maybe the ApplicationSettings deserializes your objects two times for the two lists so you have two different objects.
Try something like a proxy for the ApplicationSettings like the following example to keep only one valid list of all stored Class1-instances:
public List<Class1> Class1List
{
get
{
if(this.class1List == null)
{
if(this.applicationSettings.Contains("class1Key"))
this.class1List = (List<Class1>)this.applicationSettings["class1Key"];
}
return this.class1List;
}
set
{
this.applicationSettings["class1Key"] = value;
this.applicationSettings.Save();
}
}
Related
I am building a control in xamarin forms that binds to a list of objects. To get this binding to work I need to use observable collections (otherwise propertychanged methods don't fire).
I noticed a really frustrating interaction as a result of needing to use OC's as opposed to lists. Whenever the binded OC updates, the values in my controls are automatically updated, even if they are just references of the OC, Here is how i am copying the OC.
//Internal list of events
private List<EventItem> _events;
void OnEventsChanged(ObservableCollection<EventItem> eventsCollection)
{
//Error handle
List<EventItem> events = eventsCollection.ToList();
//Do something
_events = events;
}
The problem comes when the OC updates, I want to check for new/deleted AND altered objects. The issue is that when the OC updates, it is updating the internal list (_events) aswell. This means when I go to do comparisons between the old & new values, they are the same.
Honestly I don't really understand how c# handles copying references of objects around, I had a similar issue a while back with DateTime.Now being calculated as opposed to copying the value of the already initialised object.
var time = DateTime.Now;
await Task.Delay(1000);
var time2 = time; //This is 1 second later than time, not the value of time (which is what I wanted)
I have used Objective-C in the past and that has the concept of MutableCopy where you can assign a new list from an existing one, they have the same values but aren't linked.
How can I do this in C# so that my controls internal list is only updated by me and not the OC?
Thanks
That's perfectly normal. If I have enough time, I'll try to explain it to you.
In a nutshell, the observableList (or a List) is a list of reference to the objects and not a list of objects. The thing is that the objects are not copied inside a list but the list contains a reference to the different objects. That means that if you do something like ToList(), you get another list of references to the exact same objects.
Now to solve your problem. Just create a new list with new objects with something like
var newList = oldList.Select(x => new Model(x)).ToList();
And of course the Model class has a constructor that accept a Model as a parameter and copy the properties.
When you write _events = events;, you create not a new object, but a reference for the same object. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/index .
You should to clone (create a copy of object itself) as it mentioned in comment by #Matt.
How to get ObjectId of the recently modified object?
I add some polyline to the drawing. Each one is the same. When one modifies the other, they must also be adjusted to the changes. I need to exclude from the list of objects that need to be updated, the object I just modified. I can not find the answer.
Example:
I have some polyline. When creating them, an event handler is added (ObjectId of each object is added to NOD). At the moment of modifying one of them, the function assigned to the modification will loop through all objects stored in NOD. When the length is changed other objects must also do so. Initially I want to do that the rest will be removed and replaced with a modified copy of the object.
Here I need to access the last modified object to be able to skip it while modifying other polyline. At the moment, the program ends and I think this is a problem because I'm trying to convert the polylines to the same one.
If I understand your problem correctly, what you need is a dynamic exclusion list. A Hashset<ObjectID> instance will serve you well, as ObjectID is a struct (i.e. a value type). See this tutorial:
HashSet is an unordered collection that contains unique elements. We can apply various operations on a HashSet like, Add, Remove, Contains etc.
Once a polyline is modified by user, I am assuming an event triggers your process to go ahead and modify all other polylines in your NOD. To utilize your exclusion list, add a private field to the class that contains your Command Methods:
private static HashSet<ObjectId> exclusionList = new HashSet<ObjectId>();
Make sure to add the ObjectID of the polyline that the user modified to the exclusionList right away:
exclusionList.Add(modifiedObjectID);
The Add() method returns true if the list does not contain the objectID you tried to add, and adds it to the set. It will return false if the set already contains the ObjectID. This is the key to solving your issue. You add each entity to the exclusion set so that each one is only modified once per cycle. Also, since you already added your original polyline's ObjectID to the set, it will never be modified in the loop. After the loop ends, clear the list and wait for the next time the user modifies an entity.
In your loop that cycles through your MOD, do the following:
public void ProcessEntities()
{
foreach(DBDictionaryEntry obj in MyNOD)
{
//Add each objectID to your exclusion List
//if it's already there, everything inside the if statement is skipped!
if(exclusionList.Add(obj.Value))
{
//do your object modification here
}
}
//All entities have been processed now
//clear the list and wait for the next event
exclusionList.Clear();
}
I have a list of StockMultibuy items, and am building a list of those items. Some of the items in the list I want to have different properties than existing items, and so I tried to create a new instance of the item, changed the property that I wanted, and then added it to the list. I wasn't expecting this to update items that were already in the list. Is this expected behaviour? Is there anything I can do to overcome this?
Thanks
StockMultibuy aNewItem = StaticLists.GetStockMultibuyForBarcode(sBarcode);
// If we've got enough items to qualify, then add a free item
if (Reward.StockItemsTaken.Count % (Reward.FreeWhenQualified + Reward.QualifyingQty)
== Reward.QualifyingQty)
{
aNewItem.PromoPrice = 0;
}
// Save this for later so that we know we've added a regular item
else
{
aNewItem.PromoPrice = Convert.ToDecimal(aNewItem.Sell);
}
Reward.StockItemsTaken.Add(aNewItem);
You're not adding several different items to the list, you're adding the same exact item several times and modifying it each time.
Classes in C# are reference types; that means each variable doesn't hold the data for the object itself, it just hold onto a reference to where that object is. Assigning an object to another variable doesn't create a new object, it just copies the reference to that same object.
The issue is that you should be creating a new object (i.e. using the new keyword) each time you go to add a new item to the list.
From the looks of your code it would seem that StaticLists.GetStockMultibuyForBarcode(sBarcode) isn't returning a new item each time; it's just returning the same item, or at the very least one of the existing items. You should be creating a new item, copying some of the values of that item over (if that's your intention) and then adding that new item to the list.
It is expected, it will update because it is a reference. I would just make a copy of the object or clone it if you can.
I was hoping the new keyword, would not only create a new object, but also with unique memory references. If I do this, and after Clear the "tinyList", the bigList will also be cleared.
bigList.Add(new bigListObject(tinyList));
bigList is a List and Construcotr looks like
public Foo(List<SmallClass> in)
{
_test = new List<SmallClass>();
_test = in;
}
This works, but how can I clear the tinyList, fill it, and continue adding to bigList?
The whole idea is to have a big list and one small for adding.. Now I have two lists from two different classes, almost the same.
Thanks
You can copy the references to a new list:
public Foo(List<SmallClass> in)
{
_test = new List<SmallClass>(in);
}
now _test and in point to two different lists, so removing an object from one list does not affect the other.
However, they are the same references. So editing one of the SmallClass instances in list in will affect the corresponding instance in list _test because the references point to the same instances.
If you need copies of the SmallClass instances then you'll need to implement a copy method (or use object.MemberwiseClone)
I'm trying to create this:
Tag1 has the ordered list of objects: O1, O3, O2.
Tag2 has the ordered list of objects: O1, O4.
Every time I click a tag, I want to see the list of objects. So clicking Tag1 would show in a listbox:
O1
O3
O2
But I would like to keep the auto update so every time I edit or add/delete an object it auto updates (I suppose I need to implement something like the interfaces INotifyCollectionChanged and INotifyPropertyChanged?).
I could use a database and have the tables Tag, Object and TagObject, this last one with the TagID and ObjectID. But I also would like to avoid databases, since it's a desktop application.
I could also use objects like ObservableCollections, but I have the problem of having duplicate objects. I can use references to the objects but it gets messy.
Anyone has any suggestion on how to do this?
Thank you.
One option would be to create an object that contains a dataset (System.Data namespace). Inside the dataset it would have 3 tables that would be linked using defined foreign keys the same as if it was in a database. These can later be stored to XML if need be.
Your object would then have to expose a dataview which can be set as the datacontext and bound too.
Editing the dataset in code then updates the screen and editing the screen will update the dataset.
Move all the logic controlling the updated data out of the WPF page and into another class that pushes the new data into the WPF page, when it changes, rather than the WPF pulling the data out of the objects.
Here is some example code:
class WpfPage
{
public List OrderedListForTag1 { set { /* whatever GUI binding code you need to deal with the new list for tag 1 */ }
public List OrderedListForTag2 { set { /* whatever GUI binding code you need to deal with the new list for tag 2*/ }
}
class WpfPresenter
{
WpfPage thePage;
public void Tag1Selected()
{
//Calculate changes to 01, 02, 04 etcetce
//If changed, update the page
thePage.OrderedListForTag1 = //new list of objects
}
}
This is one of the model-view-controller pattern(s) which is very common in GUI construction. This series of articles covers the concepts.