Implemented missing observable dictionary

This commit is contained in:
Tiberiu Chibici 2014-10-11 10:37:56 +03:00
parent db366ef396
commit 180e4bb9fd
3 changed files with 324 additions and 16 deletions

View File

@ -47,6 +47,7 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Editor\Features\ToolboxItem.cs" />
<Compile Include="Model\IProjectTemplate.cs" />
<Compile Include="RainmeterStudioPluginAttribute.cs" />
<Compile Include="PluginExportAttribute.cs" />
@ -70,9 +71,11 @@
<Compile Include="Utils\InputHelper.cs" />
<Compile Include="Utils\LinqExtension.cs" />
<Compile Include="Utils\BitmapHelper.cs" />
<Compile Include="Utils\ObservableDictionary.cs" />
<Compile Include="Utils\PathHelper.cs" />
<Compile Include="Utils\Version.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -0,0 +1,321 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace RainmeterStudio.Core.Utils
{
public class ObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
{
private Dictionary<TKey, TValue> _dict;
#region Events
/// <summary>
/// Triggered when the items of the collection change
/// </summary>
public event NotifyCollectionChangedEventHandler CollectionChanged;
/// <summary>
/// Triggered when a property changes
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that is empty, has the default initial capacity, and uses the default
/// equality comparer for the key type.
/// </summary>
public ObservableDictionary()
{
_dict = new Dictionary<TKey,TValue>();
}
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that contains elements copied from the specified System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;
/// and uses the default equality comparer for the key type.
/// </summary>
/// <param name="dictionary">
/// The System.Collections.Generic.IDictionary&lt;TKey,TValue&gt; whose elements are
/// copied to the new System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;.
/// </param>
/// <exception cref="System.ArgumentNullException">dictionary is null</exception>
/// <exception cref="System.ArgumentException">dictionary contains one or more duplicate keys</exception>
public ObservableDictionary(IDictionary<TKey, TValue> dictionary)
{
_dict = new Dictionary<TKey,TValue>(dictionary);
}
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that is empty, has the default initial capacity, and uses the specified
/// System.Collections.Generic.IEqualityComparer&lt;TKey&gt;.
/// </summary>
/// <param name="comparer">
/// The System.Collections.Generic.IEqualityComparer&lt;TKey&gt; implementation to use
/// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer&lt;TKey&gt;
/// for the type of the key
/// </param>
public ObservableDictionary(IEqualityComparer<TKey> comparer)
{
_dict = new Dictionary<TKey, TValue>(comparer);
}
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that is empty, has the specified initial capacity, and uses the default
/// equality comparer for the key type.
/// </summary>
/// <param name="capacity">
/// The initial number of elements that the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// can contain.
/// </param>
/// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0</exception>
public ObservableDictionary(int capacity)
{
_dict = new Dictionary<TKey, TValue>(capacity);
}
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that contains elements copied from the specified System.Collections.Generic.IDictionary&lt;TKey,TValue&gt;
/// and uses the specified System.Collections.Generic.IEqualityComparer&lt;TKey&gt;.
/// </summary>
/// <param name="dictionary">
/// The System.Collections.Generic.IDictionary&lt;TKey,TValue&gt; whose elements are
/// copied to the new System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;.
/// </param>
/// <param name="comparer">
/// The System.Collections.Generic.IEqualityComparer&lt;TKey&gt; implementation to use
/// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer&lt;TKey&gt;
/// for the type of the key.
/// </param>
/// <exception cref="System.ArgumentNullException">dictionary is null</exception>
/// <exception cref="System.ArgumentException">dictionary contains one or more duplicate keys</exception>
public ObservableDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
{
_dict = new Dictionary<TKey, TValue>(dictionary, comparer);
}
/// <summary>
/// Initializes a new instance of the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// class that is empty, has the specified initial capacity, and uses the specified
/// System.Collections.Generic.IEqualityComparer&lt;TKey&gt;.
/// </summary>
/// <param name="capacity">
/// The initial number of elements that the System.Collections.Generic.Dictionary&lt;TKey,TValue&gt;
/// can contain.
/// </param>
/// <param name="comparer">
/// The System.Collections.Generic.IEqualityComparer&lt;TKey&gt; implementation to use
/// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer&lt;TKey&gt;
/// for the type of the key.
/// </param>
/// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0</exception>
public ObservableDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
_dict = new Dictionary<TKey, TValue>(capacity, comparer);
}
#endregion
#region IDictionary<TKey, TValue>
/// <summary>
/// Gets the number of key/value pairs contained in the dictionary.
/// </summary>
public int Count
{
get { return _dict.Count; }
}
/// <summary>
/// Gets a collection containing the keys in the dictionary.
/// </summary>
public ICollection<TKey> Keys
{
get { return _dict.Keys; }
}
/// <summary>
/// Gets a collection containing the values in the dictionary.
/// </summary>
public ICollection<TValue> Values
{
get { return _dict.Values; }
}
/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
/// <param name="key">The key of the value to get or set</param>
/// <returns>
/// The value associated with the specified key. If the specified key is not
/// found, a get operation throws a <see cref="System.Collections.Generic.KeyNotFoundException"/>,
/// and a set operation creates a new element with the specified key.
/// </returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
public TValue this[TKey key]
{
get
{
return _dict[key];
}
set
{
TValue oldValue;
TryGetValue(key, out oldValue);
_dict[key] = value;
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Replace,
new KeyValuePair<TKey, TValue>(key, oldValue),
new KeyValuePair<TKey, TValue>(key, value)));
}
}
/// <summary>
/// Adds the specified key and value to the dictionary.
/// </summary>
/// <param name="key">The key of the element to add</param>
/// <param name="value">The value of the element to add. The value can be null for reference types.</param>
/// <exception cref="System.ArgumentNullException">key is null</exception>
/// <exception cref="System.ArgumentException">An element with the same key already exists in the dictionary.</exception>
public void Add(TKey key, TValue value)
{
_dict.Add(key, value);
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new KeyValuePair<TKey, TValue>(key, value), null));
}
/// <summary>
/// Removes all keys and values from the dictionary.
/// </summary>
public void Clear()
{
_dict.Clear();
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Determines whether the dictionary contains the specified key.
/// </summary>
/// <param name="key">The key to locate in the dictionary</param>
/// <returns>true if the dictionary contains an element with the specified key; otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
public bool ContainsKey(TKey key)
{
return _dict.ContainsKey(key);
}
/// <summary>
/// Removes the value with the specified key from the dictionary.
/// </summary>
/// <param name="key">The key of the element to remove</param>
/// <returns>
/// true if the element is successfully found and removed; otherwise, false.
/// This method returns false if key is not found in the dictionary.
/// </returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
public bool Remove(TKey key)
{
TValue oldValue;
_dict.TryGetValue(key, out oldValue);
bool res = _dict.Remove(key);
if (res && CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new KeyValuePair<TKey, TValue>(key, oldValue)));
return res;
}
/// <summary>
/// Gets the value associated with the specified key.
/// </summary>
/// <param name="key">The key of the value to get</param>
/// <param name="value">
/// When this method returns, contains the value associated with the specified
/// key, if the key is found; otherwise, the default value for the type of the
/// value parameter. This parameter is passed uninitialized.
/// </param>
/// <returns>
/// true if the dictionary contains an element with the specified key;
/// otherwise, false.
/// </returns>
/// <exception cref="System.ArgumentNullException">key is null</exception>
public bool TryGetValue(TKey key, out TValue value)
{
return _dict.TryGetValue(key, out value);
}
#endregion
#region ICollection<KeyValuePair<TKey, TValue>>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
((ICollection<KeyValuePair<TKey, TValue>>)_dict).Add(item);
if (CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, null));
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Contains(item);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
((ICollection<KeyValuePair<TKey, TValue>>)_dict).CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
{
get { return ((ICollection<KeyValuePair<TKey, TValue>>)_dict).IsReadOnly; }
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
bool res = ((ICollection<KeyValuePair<TKey, TValue>>)_dict).Remove(item);
if (res && CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
return res;
}
#endregion
#region IEnumerable
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_dict).GetEnumerator();
}
#endregion
}
}

View File

@ -72,14 +72,11 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio", "RainmeterStudio\RainmeterStudio.csproj", "{438D0136-4A27-4E4D-A617-FFACE4554236}"
ProjectSection(ProjectDependencies) = postProject
{9A644478-2F1B-4145-8B31-6F8DBD42EC38} = {9A644478-2F1B-4145-8B31-6F8DBD42EC38}
{E8BD25E9-3055-4688-9E83-ECF684EF30C6} = {E8BD25E9-3055-4688-9E83-ECF684EF30C6}
{C641D7F8-DDDC-4EC6-8F5E-233520290642} = {C641D7F8-DDDC-4EC6-8F5E-233520290642}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.Tests", "RainmeterStudio.Tests\RainmeterStudio.Tests.csproj", "{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.SkinDesignerPlugin", "RainmeterStudio.SkinDesigner\RainmeterStudio.SkinDesignerPlugin.csproj", "{E8BD25E9-3055-4688-9E83-ECF684EF30C6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.Core", "RainmeterStudio.Core\RainmeterStudio.Core.csproj", "{1D2A4896-AF31-4E82-A84F-4E218067701F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.TextEditorPlugin", "RainmeterStudio.TextEditor\RainmeterStudio.TextEditorPlugin.csproj", "{9A644478-2F1B-4145-8B31-6F8DBD42EC38}"
@ -532,18 +529,6 @@ Global
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}.Release|Win32.ActiveCfg = Release|Any CPU
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}.Release|x64.ActiveCfg = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|Win32.ActiveCfg = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Debug|x64.ActiveCfg = Debug|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|Any CPU.Build.0 = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|Win32.ActiveCfg = Release|Any CPU
{E8BD25E9-3055-4688-9E83-ECF684EF30C6}.Release|x64.ActiveCfg = Release|Any CPU
{1D2A4896-AF31-4E82-A84F-4E218067701F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D2A4896-AF31-4E82-A84F-4E218067701F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D2A4896-AF31-4E82-A84F-4E218067701F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -617,6 +602,5 @@ Global
{EE8EC522-8430-4B46-86A3-D943D77F9E4B} = {53D952E0-CFD2-4EFF-BAD4-5969E760EFA1}
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A} = {8469BE7E-BCDB-4AA8-9541-719E8BFB19A7}
{9A644478-2F1B-4145-8B31-6F8DBD42EC38} = {4CCE6052-F43E-4360-B3E2-C046C6C0D86C}
{E8BD25E9-3055-4688-9E83-ECF684EF30C6} = {4CCE6052-F43E-4360-B3E2-C046C6C0D86C}
EndGlobalSection
EndGlobal