hi there maybe i have an idea for you... You can bind to a collection that is empty and then from a seperate thread you start pushing data in the collection, the collection (ObservableCollection) will notify the GUI with the new changes.
Now the only problem is that you cannot update an observable collection from a seperate thread other wise it will crash since the observable collection will try to notify the UI and BAMMM cross thread exception...
So the sollution is to make a ObservableCollection that support swithing of threads....
/// <summary>
/// ThreadableObservableCollection caters for notify the user interface with changes done in the collection (Item[])
/// This can be used when you have a multi threaded envirorment
/// </summary>
/// <typeparam name="T">The Type of objects that are going to be stored in this collection</typeparam>
public class ThreadableObservableCollection<T> :
System.Collections.ObjectModel.ObservableCollection<T>, INotifyPropertyChanged
{
private List<T> items = null;
/// <summary>
/// Returns the index of the item
/// </summary>
/// <param name="item">The item to find</param>
/// <returns>The index of the item found</returns>
public int BinarySearch(T item)
{
if(this.comparer == null)
return -1;
return this.items.BinarySearch(item, this.comparer);
}
private IComparer<T> comparer;
/// <summary>
/// Comparer used to sort the collection
/// </summary>
public IComparer<T> Comparer
{
get { return comparer; }
set { comparer = value; }
}
//Gets the syncronization object to lock
private object sync = null;
/// <summary>
/// Gets the syncronization object to lock
/// </summary>
public object SyncRoot
{
get
{
return sync;
}
}
private T defaultLastValue;
/// <summary>
/// Gets the last value of the collection
/// </summary>
public T LastValue
{
get
{
if (this.items.Count != 0)
return this.items[this.Count > 0 ? (this.Count - 1) : 0];
else
return defaultLastValue;
}
}
/// <summary>
/// controlDispatcher stored the dispatcher of the GUI control being daat bound
/// </summary>
private readonly Dispatcher controlDispatcher;
/// <summary>
/// ControlDispatcher returns the dispatcher of the GUI control being daat bound
/// </summary>
public Dispatcher ControlDispatcher
{
get {return controlDispatcher; }
}
/// <summary>
/// Full constructor
/// Sets the dispatcher for this view
/// </summary>
/// <param name="controlDispatcher">The dispatcher of the control being data bound</param>
/// <param name="comparer">Comparer to sort the collection</param>
/// <param name="defaultValue">The value to return from the LastValue property, if no data is present in the collection</param>
public ThreadableObservableCollection(Dispatcher controlDispatcher, IComparer<T> comparer, T defaultValue)
: this(controlDispatcher, comparer)
{
this.defaultLastValue = defaultValue;
}
/// <summary>
/// Full constructor
/// Sets the dispatcher for this view
/// </summary>
/// <param name="controlDispatcher">The dispatcher of the control being data bound</param>
/// <param name="comparer">Comparer to sort the collection</param>
public ThreadableObservableCollection(Dispatcher controlDispatcher, IComparer<T> comparer)
{
this.controlDispatcher = controlDispatcher;
this.comparer = comparer;
sync = new object();
this.items = this.Items as List<T>;
}
/// <summary>
/// Default constructor
/// Sets the dispatcher for this view
/// </summary>
/// <param name="controlDispatcher">The dispatcher of the control being data bound</param>
public ThreadableObservableCollection(Dispatcher controlDispatcher)
: this(controlDispatcher, null)
{}
//flag to signal if the collecion is being added with a chunk of data
bool busy = false;
/// <summary>
/// flag to signal if the collecion is being added with a chunk of data
/// </summary>
public bool Busy
{
get { return busy; }
}
/// <summary>
/// Add a collection to the list
/// </summary>
/// <param name="items">The collection of objects to add</param>
public void AddRange(IList<T> items)
{
this.AddRange(items, true);
}
/// <summary>
/// Add a collection to the list
/// </summary>
/// <param name="items">The collection of objects to add</param>
/// <param name="resetAction">Pass true to raise the collection action reset event argument</param>
public void AddRange(IList<T> items, bool resetAction)
{
//if only one item needs to be added call the add directly
if (items.Count == 1)
{
this.Add(items[0]);
return;
}
//set the collection as busy to turn OFF notifications
busy = true;
lock (sync) //lock here since the data is being added
{
//add all the values in the collection
foreach (T value in items)
this.Items.Insert(GetIndexForItem(value), value);
}
//set the collection as not busy to turn ON notifications
busy = false;
if (resetAction)
{
//raise the collection changed event
this.OnCollectionChanged(
new System.Collections.Specialized.NotifyCollectionChangedEventArgs(
System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
);
}
else
{
this.OnCollectionChanged(
new System.Collections.Specialized.NotifyCollectionChangedEventArgs(
System.Collections.Specialized.NotifyCollectionChangedAction.Add,
(System.Collections.IList)items));
}
}
/// <summary>
/// Removes a range of items from the list
/// </summary>
/// <param name="indexFrom">The index from where to begin removing</param>
/// <param name="indexTo">The index from where to end removing</param>
/// <param name="notifyUIOnce">Set to true if you want to only send one event to the UI when finished removing items</param>
public void RemoveRange(int indexFrom, int indexTo, bool notifyUIOnce)
{
if (!notifyUIOnce)
{
RemoveRange(indexFrom, indexTo, this);
return;
}
//set the collection as busy to turn OFF notifications
busy = true;
RemoveRange(indexFrom, indexTo, this.items);
//set the collection as not busy to turn ON notifications
busy = false;
//raise the collection changed event
this.OnCollectionChanged(
new System.Collections.Specialized.NotifyCollectionChangedEventArgs(
System.Collections.Specialized.NotifyCollectionChangedAction.Reset)
);
}
/// <summary>
/// Removes a range of items from the list
/// </summary>
/// <param name="indexFrom">The index from where to begin removing</param>
/// <param name="indexTo">The index from where to end removing</param>
/// <param name="collection">The collection to remove items from</param>
private static void RemoveRange(int indexFrom, int indexTo, IList<T> collection)
{
for (int i = 0; i <= indexTo - indexFrom; i++)
{
if (collection.Count != 0)
{
collection.RemoveAt(indexFrom);
}
}
}
/// <summary>
/// raises the collection changed method
/// </summary>
/// <param name="e">The event argument to pass in the event</param>
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (!busy)
{
if (InvokeRequired)
{
controlDispatcher.BeginInvoke(DispatcherPriority.Send, new OnCollectionChangedEventHandler(OnCollectionChanged), e);
}
else
{
base.OnCollectionChanged(e);
base.OnPropertyChanged(new PropertyChangedEventArgs("LastValue"));
}
}
}
#region Delegates for callbacks
/// <summary>
/// InvokeRequired check if there need current thread is the main thread
/// </summary>
/// <returns>Returns true if the current thread is not the main thread</returns>
private bool InvokeRequired
{
get
{
return controlDispatcher != null && controlDispatcher.Thread != System.Threading.Thread.CurrentThread;
}
}
/// <summary>
/// SetItemCallback is the delegate for when the SetItem method of the collection is invoked
/// </summary>
/// <param name="index">The index of the item</param>
/// <param name="item">The new item data to set</param>
private delegate void SetItemCallback(int index, T item);
/// <summary>
/// delegate to redirect to the correct thread
/// </summary>
/// <param name="e">The event argument to pass in when the event is raised</param>
private delegate void OnCollectionChangedEventHandler(System.Collections.Specialized.NotifyCollectionChangedEventArgs e);
/// <summary>
/// RemoveItemCallback is the delegate for when an item is removed from the Collection
/// </summary>
/// <param name="index">The index of the item to remove</param>
private delegate void RemoveItemCallback(int index);
/// <summary>
/// ClearItemsCallback is the delegate for when the clear method of the collection is called
/// </summary>
private delegate void ClearItemsCallback();
/// <summary>
/// InsertItemCallback is the delegate for when the InsertItem methdo of the collection is called
/// </summary>
/// <param name="index">The index where to insert the new item</param>
/// <param name="item">The new item to add</param>
private delegate void InsertItemCallback(int index, T item);
#endregion
#region Method To override
/// <summary>
/// InsertItem overrides the base InsertItem so to notify the GUI with the new data
/// </summary>
/// <param name="index">The index where the item was added</param>
/// <param name="item">The item object added</param>
protected override void InsertItem(int index, T item)
{
if (InvokeRequired)
controlDispatcher.Invoke(DispatcherPriority.Send, new InsertItemCallback(InsertItem), index, new object[] { item });
else
base.InsertItem(GetIndexForItem(item), item);
}
/// <summary>
/// Gets the index of where to insert the item in the list.
/// </summary>
/// <param name="item">The Item to search</param>
/// <returns>Return the index of the item</returns>
public int GetIndexForItem(T item)
{
if (this.items.Count == 0)
return 0;
//Compare with the last item.
if (this.comparer == null ||
Comparer.Compare(this.items[this.items.Count - 1], item) <= 0)
return this.items.Count;
int index = this.items.BinarySearch(item, this.comparer);
// Item was found. Insert new item after
if (index >= 0)
index++;
// Item was not found. Bitwise complement is where to put the new one.
if (index < 0)
index = ~index;
return index;
}
/// <summary>
/// SetItem modifies an item in the collection
/// </summary>
/// <param name="index">The index of the item to modify</param>
/// <param name="item">The new item instance</param>
protected override void SetItem(int index, T item)
{
if (InvokeRequired)
controlDispatcher.Invoke(DispatcherPriority.Send, new SetItemCallback(SetItem), index, new object[] { item });
else
base.SetItem(index, item);
}
/// <summary>
/// RemoveItem removes an item from a specific position
/// </summary>
/// <param name="index">The index of the item to remove</param>
protected override void RemoveItem(int index)
{
if (InvokeRequired)
controlDispatcher.Invoke(DispatcherPriority.Send, new RemoveItemCallback(RemoveItem), index);
else
base.RemoveItem(index);
}
/// <summary>
/// ClearItems will remove all the items from the collection
/// </summary>
protected override void ClearItems()
{
if (InvokeRequired)
ControlDispatcher.Invoke(DispatcherPriority.Send, new ClearItemsCallback(ClearItems));
else
base.ClearItems();
}
#endregion
#region UNIT_TEST
/// <summary>
/// Calls the InsertItem method to expose it for unit tests
/// </summary>
/// <param name="index">The index where the item was added</param>
/// <param name="item">The item object added</param>
public void InsertItemPublic(int index, T item)
{
this.InsertItem(index, item);
}
/// <summary>
/// Calls the SetItem method to expose it for unit tests
/// </summary>
/// <param name="index">The index of the item to modify</param>
/// <param name="item">The new item instance</param>
public void SetItemPublic(int index, T item)
{
this.SetItem(index, item);
}
/// <summary>
/// Calls the RemoveItem method to expose it for unit tests
/// </summary>
/// <param name="index">The index of the item to remove</param>
public void RemoveItemPublic(int index)
{
this.RemoveItem(index);
}
/// <summary>
/// Calls the ClearItems method to expose it for unit tests
/// </summary>
public void ClearItemsPublic()
{
this.ClearItems();
}
#endregion
}
Please note that this collection support InsertSort and a lot of other things just comment what you do not need....
hope it helps!!!!!!!!!
Regards