This article demonstrates a generic way of the collections synchronization. Why do we need that? Typically, in the programming we have one master collection and the slave collection.
The master collection usually represents the outcome of some process, whereas the slave collection is the graphical representation of the master collection.
Let us look at the simple example: our master collection is the set of the orders in the trading software. This set is always dynamic – the number and the content of the orders can change very quickly and we have to display these changes in the ListView.
There are a few ways of doing it; we clear the list and fill it with the items. Each update recreates a new list. Well, if you have only a few items, this will do. But even so you have to recreate the state of each item. If, for instance, the item was selected, you somehow have to select the item again. Which exactly item? We don’t know, we have to identify the item in the new collection.
The situation becomes even worse if the number of items exceeds hundreds and we have to recreate them from the scratch. Another more sensible approach implies the update of the individual items, if required adding new items and deleting the nonexistent ones.
The problem with the second approach is that the algorithm for doing this is not trivial with numerous iterations. It must be also fast.
The solution
We create the generic class for the synchronization and connect the target list with this object. The target can be anything – ListBox, ListView, TreeView, basically any class that holds the collection of items.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Collections; | |
using System.Drawing; | |
using System.Windows.Forms; | |
namespace vtx | |
{ | |
public abstract class BaseSynchronizer | |
{ | |
/// <summary> | |
/// There is a master collection of items | |
/// Slave collection is the representaion of master collection | |
/// For instance - we have collection of items and want to display them in the listview | |
/// so, SlaveCollection_in is the ListViewItems collecton | |
/// Synchronize means creating the licstview items that exist in the master collection and do not in Listvies | |
/// and removing Listview items that do not exist in the mastercollection | |
/// | |
/// </summary> | |
/// <param name="MasterCollection_in"></param> | |
/// <param name="SlaveCollection_in"></param> | |
public void Synchronize(IList MasterCollection_in, IList SlaveCollection_in) | |
{ | |
if (MasterCollection_in == null || SlaveCollection_in == null) | |
return; | |
try | |
{ | |
List<ICommonItem> MasterCollection = new List<ICommonItem>(); | |
List<ICommonItem> SlaveCollection = new List<ICommonItem>(); | |
foreach (var V in MasterCollection_in) | |
MasterCollection.Add((ICommonItem)V); | |
foreach (var V in SlaveCollection_in) | |
SlaveCollection.Add((ICommonItem)V); | |
var MasterIDs = from O in MasterCollection select (O.ItemID);// virtual | |
var SlaveIDs = from O in SlaveCollection select (O.ItemID); // real (Like ListViewItem) | |
var CommonInBoth = MasterIDs.Intersect(SlaveIDs); | |
var ItemsToAddToSlave = MasterIDs.Except(CommonInBoth); | |
var ItemsToRemoveFromSlave = SlaveIDs.Except(CommonInBoth); | |
var MasterItemsToCreateOnSlave = from MasterItem in MasterCollection where ItemsToAddToSlave.Contains(MasterItem.ItemID) select MasterItem; | |
var SlaveItemsToDelete = from SlaveItem in SlaveCollection where ItemsToRemoveFromSlave.Contains(SlaveItem.ItemID) select SlaveItem; | |
/// delete items that do not exist in MasterCollection | |
foreach (ICommonItem icc in SlaveItemsToDelete) | |
RemoveSlaveItem(SlaveCollection_in, icc); | |
// Add items that are in the MasterCollection and do not exist in the SlaveCollection | |
foreach (ICommonItem icc in MasterItemsToCreateOnSlave) | |
{ | |
ICommonItem item = CreateSlaveItem(icc); | |
SlaveCollection_in.Add(item); | |
} | |
} | |
catch (Exception ex) | |
{ | |
throw new Exception("BaseSynchronizer.Synchronize()" + this.GetType().Name + "," + ex.Message); | |
} | |
} | |
protected virtual void RemoveSlaveItem(IList SlaveCollection, ICommonItem icc) | |
{ | |
SlaveCollection.Remove(icc); | |
} | |
/// <summary> | |
/// create slave item out of master item | |
/// </summary> | |
/// <param name="MasterItem"></param> | |
/// <returns></returns> | |
protected abstract ICommonItem CreateSlaveItem(ICommonItem MasterItem); | |
} | |
public interface ICommonItem | |
{ | |
int ItemID { get; } | |
} | |
public interface ISlaveItem<T> | |
{ | |
T SlaveItemInstance { get; set; } | |
} | |
public interface ICombined<T> : ICommonItem, ISlaveItem<T> | |
{ | |
} | |
} |
Download Visual Studio Project that demonstrates BaseSyncronizer class.
No comments:
Post a Comment