Skip to content

Instantly share code, notes, and snippets.

@mhabegger
Created February 11, 2015 15:10
Show Gist options
  • Save mhabegger/bb460e2521127020b615 to your computer and use it in GitHub Desktop.
Save mhabegger/bb460e2521127020b615 to your computer and use it in GitHub Desktop.
WPF Oberservable Utilities
/*
* The MIT License (MIT)
*
* Copyright (c) 2011 SwissMediaPartners AG, Mathieu Habegger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System.ComponentModel;
using System.Windows.Threading;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Threading;
using System;
namespace smpag.datastructures.Plain.Collections
{
public class DispatchedObservableCollection<Titem> : ObservableCollection<Titem>
{
DispatchEvent collectionChanged = new DispatchEvent();
DispatchEvent propertyChanged = new DispatchEvent();
public DispatchedObservableCollection()
{ }
public DispatchedObservableCollection(List<Titem> list)
: base(list)
{ }
public DispatchedObservableCollection(Dispatcher dispatcher)
{ }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
//base.OnCollectionChanged(e);
this.collectionChanged.Fire(this, e);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
//base.OnPropertyChanged(e);
this.propertyChanged.Fire(this, e);
}
public override event NotifyCollectionChangedEventHandler CollectionChanged
{
add { this.collectionChanged.Add(value); }
remove { this.collectionChanged.Remove(value); }
}
protected override event PropertyChangedEventHandler PropertyChanged
{
add { this.propertyChanged.Add(value); }
remove { this.propertyChanged.Remove(value); }
}
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2011 SwissMediaPartners AG, Mathieu Habegger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Threading;
using System.Threading;
using System.Reflection;
using System.Windows;
using System.Collections;
namespace smpag.datastructures.Plain.Collections
{
public class DispatchEvent
{
#region Data Member
private List<DispatchHandler> handlerList = new List<DispatchHandler>();
#endregion
#region Expose Methods
public void Add(Delegate handler)
{
this.Add(handler, Dispatcher.CurrentDispatcher);
}
public void Add(Delegate handler, Dispatcher dispatcher)
{
handlerList.Add(new DispatchHandler(handler, dispatcher));
}
public void Remove(Delegate handler)
{
var rmvHandlers = (from dispatchHandler in handlerList
where dispatchHandler.DelegateEquals(handler)
select dispatchHandler).ToArray();
if (rmvHandlers != null && rmvHandlers.Length > 0)
{
this.handlerList.Remove(rmvHandlers[0]);
rmvHandlers[0].Dispose();
}
}
public void Clear()
{
foreach (DispatchHandler handler in this.handlerList)
{
handler.Dispose();
}
this.handlerList.Clear();
}
public void Fire(object sender, EventArgs args)
{
var disposableHandler = from handler in handlerList
where handler.IsDisposable
select handler;
foreach (DispatchHandler rmvHandler in disposableHandler.ToArray())
{
this.handlerList.Remove(rmvHandler);
rmvHandler.Dispose();
}
foreach (DispatchHandler handler in handlerList)
handler.Invoke(sender, args);
}
#endregion
#region DispatchHandler Class
private class DispatchHandler : IDisposable
{
private MethodInfo handlerInfo;
private WeakReference targetRef;
private WeakReference dispatcherRef;
public DispatchHandler(Delegate handler, Dispatcher dispatcher)
{
this.handlerInfo = handler.Method;
this.targetRef = new WeakReference(handler.Target);
this.dispatcherRef = new WeakReference(dispatcher);
}
private Dispatcher Dispatcher
{
get { return (Dispatcher)this.dispatcherRef.Target; }
}
private object Target
{
get { return this.targetRef.Target; }
}
private bool IsDispatcherThreadAlive
{
get { return this.Dispatcher.Thread.IsAlive; }
}
public bool IsDisposable
{
get
{
object target = this.Target;
Dispatcher dispatcher = this.Dispatcher;
return (target == null
|| dispatcher == null
|| (target is DispatcherObject &&
(dispatcher.Thread.ThreadState & (ThreadState.Aborted
| ThreadState.Stopped
| ThreadState.StopRequested
| ThreadState.AbortRequested)) != 0));
}
}
public void Invoke(object arg, params object[] args)
{
try
{
object target = this.Target;
Dispatcher dispatcher = this.Dispatcher;
if (!this.IsDisposable)
{
if (this.IsDispatcherThreadAlive)
{
dispatcher.Invoke(DispatcherPriority.Send, new EventHandler(
delegate(object sender, EventArgs e)
{
this.handlerInfo.Invoke(target, new object[] { arg, e });
}), arg, args);
}
else if (target is DispatcherObject)
{
dispatcher.BeginInvoke(DispatcherPriority.Send, new EventHandler(
delegate(object sender, EventArgs e)
{
this.handlerInfo.Invoke(target, new object[] { arg, e });
}), arg, args);
}
else
{
ArrayList paramList = new ArrayList();
paramList.Add(arg);
paramList.AddRange(args);
this.handlerInfo.Invoke(target, paramList.ToArray());
}
}
}
catch (Exception) { }
}
public bool DelegateEquals(Delegate other)
{
object target = this.Target;
return (target != null
&& object.ReferenceEquals(target, other.Target)
&& this.handlerInfo.Name == other.Method.Name);
}
public void Dispose()
{
this.targetRef = null;
this.handlerInfo = null;
this.dispatcherRef = null;
}
}
#endregion
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2011 SwissMediaPartners AG, Mathieu Habegger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
namespace smpag.datastructures.Plain.Collections
{
public class ObservableLinkedList<T> : LinkedList<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
DispatchEvent collectionChanged = new DispatchEvent();
DispatchEvent propertyChanged = new DispatchEvent();
public ObservableLinkedList() { }
public ObservableLinkedList(IEnumerable<T> collection)
{
foreach (var item in collection)
base.AddLast(item);
}
#region
#endregion
public new virtual void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
base.AddAfter(node, newNode);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newNode));
}
public new virtual void AddAfter(LinkedListNode<T> node, T value)
{
base.AddAfter(node, value);
var newNode = node.Next;
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newNode));
}
public new virtual void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
base.AddBefore(node, newNode);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newNode));
}
public new virtual void AddBefore(LinkedListNode<T> node, T value)
{
base.AddBefore(node, value);
var newNode = node.Previous;
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newNode));
}
public new virtual void AddFirst(T value)
{
base.AddFirst(value);
var node = base.First;
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, node));
}
public new virtual void AddFirst(LinkedListNode<T> node)
{
base.AddFirst(node);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, node));
}
public new virtual void AddLast(T value)
{
base.AddLast(value);
var node = base.Last;
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, node));
}
public new virtual void AddLast(LinkedListNode<T> node)
{
base.AddLast(node);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, node));
}
public new virtual void Clear()
{
base.Clear();
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new virtual void Remove(T value)
{
var node = base.Find(value);
base.Remove(value);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, node));
}
public new virtual void Remove(LinkedListNode<T> node)
{
base.Remove(node);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, node));
}
public new virtual void RemoveFirst()
{
var node = base.First;
base.RemoveFirst();
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, node));
}
public new virtual void RemoveLast()
{
var node = base.Last;
base.RemoveLast();
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, node));
}
//public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
//protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
//{
// this.RaiseCollectionChanged(e);
//}
//protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
//{
// this.RaisePropertyChanged(e);
//}
//protected virtual event PropertyChangedEventHandler PropertyChanged;
//private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
//{
// if (this.CollectionChanged != null)
// this.CollectionChanged(this, e);
//}
//private void RaisePropertyChanged(PropertyChangedEventArgs e)
//{
// if (this.PropertyChanged != null)
// this.PropertyChanged(this, e);
//}
//event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
//{
// add { this.PropertyChanged += value; }
// remove { this.PropertyChanged -= value; }
//}
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
//base.OnCollectionChanged(e);
this.collectionChanged.Fire(this, e);
}
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
//base.OnPropertyChanged(e);
this.propertyChanged.Fire(this, e);
}
public event NotifyCollectionChangedEventHandler CollectionChanged
{
add { this.collectionChanged.Add(value); }
remove { this.collectionChanged.Remove(value); }
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { this.propertyChanged.Add(value); }
remove { this.propertyChanged.Remove(value); }
}
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2011 SwissMediaPartners AG, Mathieu Habegger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace smpag.datastructures.Plain.Collections
{
public class ObservableStack<T> : Stack<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
public ObservableStack() { }
public ObservableStack(IEnumerable<T> collection)
{
foreach (var item in collection)
base.Push(item);
}
public ObservableStack(List<T> list)
{
foreach (var item in list)
base.Push(item);
}
public new virtual void Clear()
{
base.Clear();
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new virtual T Pop()
{
var item = base.Pop();
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
return item;
}
public new virtual void Push(T item)
{
base.Push(item);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
this.RaiseCollectionChanged(e);
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
this.RaisePropertyChanged(e);
}
protected virtual event PropertyChangedEventHandler PropertyChanged;
private void RaiseCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
this.CollectionChanged(this, e);
}
private void RaisePropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, e);
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { this.PropertyChanged += value; }
remove { this.PropertyChanged -= value; }
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment