Best way to keep ObservableCollection and ObjectContext in sync? - c#

I have window with a listbox bound to an ObservableCollection of People (a set of entity framework objects that I retrieve in response to a users query: a search box), i then have functions such as Edit, Delete and Add New. At the moment i am simply making sure that each time i Add or Remove something from the Database that i also work with the OC. Is there a better way of handling this?
Thanks,
Kohan.

I found that you may need to manage the OC youself when it comes to EF manipulations. For example, when you Add a new item to DB
private bool AddItems(Item item)
{
bool addSucceed = false;
// Do adding ...
if(addSucceed)
MyObservableCollection.Remove(item)
else
// Error notificaiton here.
}
Hope that helps.

Related

Proper way to refresh ObjectListView (TreeListView) after removing object from List

I'm using ObjectListView (http://objectlistview.sourceforge.net/) and trying to update/refresh GUI after removing an object in List. Simple code:
appropriateParent.Entity.Values.RemoveAll(x => x.Id == value.Id);
Now, what's the appropriate way to update the TreeListView?
treeListView.RebuildAll(false); or
treeListView.RefreshObject(parameterNodeParent);
returns "System.ArgumentOutOfRangeException"
Any Ideas?
Best regards,
According to the FAQ, the listView does not know when you make a change. Therefor you can do one of the following:
If you can simply reset the iEnumerable by calling listView.SetObjects(iEnumerable), wich will then update the listview.
If all you do is update part of the list you can call listview.UpdateObjects(iEnumerable). Note that this does not know when objects are removed!
If you know wich objects are removed you can remove them by calling listview.RemoveObjects(iEnumerable).

Update Single Item in the ObservableCollection without LINQ

I am trying to create a list of the Components running on the network. I am trying to get all the components in the ObservableCollection. ObservableCollection<ClsComponent> Now my question is if one of the component in the collection get changed / modified how would I be able to get it reflected to my ObservableCollection of Component
Is there a way to change the it directly in the collection itself?
What is the fast and efficient way doing it?
I have tried: to change it using the LINQ : Find the Component in the collection and change it?
var CompFound = Components.FirstOrDefault(x=>x.Id == myId);
Components.Remove(CompFound);
Components.Add(UpdatedComp);
I am very sure there should have been more optimized way of doing this. Please suggest.
Edit
I am trying to write the code in the function where I can get the parameters of Source Component and Destination Component. Function looks like this
public void UpdateComponent(ClsComponent SourceComp, ClsComponent DestComp)
{
//do something here
}
After the execution of the function I want to Replace Source Component with Destination Component.
I believe this might work for you. I am sure you might be looking for this
Components.Insert(Components.IndexOf(SourceComp), DestComp);
Components.Remove(SourceComp);
One of the most efficient way would be to use a dictionary. There are implementations of ObservableDictionary which will give you the Observable behavior while allowing a fast key-based access to the object.
Check this stackoverflow question. It includes Microsoft's
It should work like ObservableCollection, except it's also a dictionary. So you can Create ObservableDictionary<Int,ClsComponent>
To replace the value simply call
Components[myId] = destComp

Cascading databound comboboxes

I'm new here this is my first question and I beforehand apologize for any lack of information, search or tags in the post or anything at all.
I'm writing a pretty simple winforms program, and I'm having problems with cascading combo boxes, pretty much like country>Estate>City I'm new to this, I'm using Entity Framework and I'm getting by with something like this:
private void Form_CadAnimal_Load(object sender, EventArgs e)
{
using (DbClinvetEntities ctx = new DbClinvetEntities())
{
cmb_especie.DataSource = ctx.Especie;
cmb_especie.DisplayMember = "Nome";
cmb_especie.ValueMember = "EspecieID"
cmb_raca.DataSource = ctx.raca;
cmb_raca.DisplayMember = "Nome";
cmb_raca.ValueMember = "RacaID";
}
}
So far so good all is going ok, I get them to be populated, I've found countless posts on the matter, but perhaps for lack of knowledge I could not relate them to my situation.
now all I would like to do is filter cmb_Raca by the value selected in cmb_Especie, just to make it clearer Raca table has a foreign key on Especie table, pretty much like you would expect country>estate to be.
I've found posts where a new context is generated on SelectedIndexChanged and a whole new binding is done, but I wonder if there is a way to make this work without making further calls to the Db, any way to take the list of objects and work them offline after the first access?
Sorry if this is anyhow unclear, I'll glady edit the post to provide further information if necessary.
try using the SelectedIndex as your query select command.you can build a module for talking to the database that takes the SelectedIndex.ToString() as a parameter to build your Query and fill data to your form based on that. the Combobox doesn't necessarily have to be databound when it is used that way.

ComboBox not updating when object added to bound list

I have an object that represents a client, and that object has a list of the clients branches:
private List<Branch> _branches;
[System.Xml.Serialization.XmlArray("Branches"), System.Xml.Serialization.XmlArrayItem(typeof(Branch))]
public List<Branch> Branches
{
get { return _branches; }
set
{
_branches = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("Branches"));
}
}
}
In one form (WinForms) I have a ComboBox that I've bound to that list:
// creating a binding list for the branches
var bindingList = new BindingList<Branch>(Client.Branches);
// bind list to combo box
cmbBranches.DataSource = bindingList;
cmbBranches.DisplayMember = "Name";
cmbBranches.ValueMember = "Name";
In another function, I create a new Branch object and add it to the existing list: Client.Branches.Add(newBranch). I would expect this to update the ComboBox but it doesn't. Why not, and how do I make it update? (Edit: I'd also like this to update when removing an object from the list. The reason it doesn't work is, I assume, directly related to why the box isn't updating when Add is called.)
In doing research, I found this SO answer, which seems to imply that it will work. I feel like I'm missing something simple ...
difference between ObservableCollection and BindingList
Edit: Some further information about what I've tried and some additional goals.
I cannot use ObservableCollection<T> instead of List<T> as I need to use Exists in the code. Which the former doesn't have.
I need to update the original list when the new object is added, in addition to updating the drop down box.
To summarize my comments below, I attempted adding this:
var bindingList = (BindingList<Branch>) cmbBranches.DataSource;
bindingList.Add(frmAddBranch.NewBranch);
But that results in the object being added to the ComboBox twice. Somehow by calling bindingList.Add it's "resetting" the data source and doubling up. I cannot find any function that "refreshes" the data display once it's bound. Control.ResetBindings() did not work.
Well, it doesn't work that way. The inner List<T> has no change notification mechanism, so adding directly to inner List<T> will not generate any change notification that would eventually reach the combo box. Most convenient way to do what you want is adding the item through the BindingList<T> instead.
I believe you have to add the items directly to the BindingList (but not to the backing Branches list - the BindingList should take care of this for you).

Copying from EntityCollection to EntityCollection impossible?

How would you do this (pseudo code): product1.Orders.AddRange(product2.Orders);
However, the function "AddRange" does not exist, so how would you copy all items in the EntityCollection "Orders" from product2 to product1?
Should be simple, but it is not...
The problem is deeper than you think.
Your foreach attempt fails, because when you call product1.Orders.Add, the entity gets removed from product2.Orders, thus rendering the existing enumerator invalid, which causes the exception you see.
So why does entity get removed from produc2? Well, seems quite simple: because Order can only belong to one product at a time. The Entity Framework takes care of data integrity by enforcing rules like this.
If I understand correctly, your aim here is to actually copy the orders from one product to another, am I correct?
If so, then you have to explicitly create a copy of each order inside your foreach loop, and then add that copy to product1.
For some reason that is rather obscure to me, there is no automated way to create a copy of an entity. Therefore, you pretty much have to manually copy all Order's properties, one by one. You can make the code look somewhat more neat by incorporating this logic into the Order class itself - create a method named Clone() that would copy all properties. Be sure, though, not to copy the "owner product reference" property, because your whole point is to give it another owner product, isn't it?
Anyway, do not hesitate to ask more questions if something is unclear. And good luck.
Fyodor
Based on the previous two answers, I came up with the following working solution:
public static void AddRange<T>(this EntityCollection<T> destinationEntityCollection,
EntityCollection<T> sourceEntityCollection) where T : class
{
var array = new T[sourceEntityCollection.Count()];
sourceEntityCollection.CopyTo(array,0);
foreach (var entity in array)
{
destinationEntityCollection.Add(entity);
}
}
Yes, the usual collection related functions are not there.
But,
1. Did you check CopyTo method?
2. Do you find any problem with using the iterator? You know, GetEnumerator, go through the collection and copy the entities?
The above two can solve your problems. But, I'm sure in .NET 3.0+ there would be compact solutions.
My answers are related to .NET 2.0

Categories

Resources