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" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Editor\Features\ToolboxItem.cs" />
<Compile Include="Model\IProjectTemplate.cs" /> <Compile Include="Model\IProjectTemplate.cs" />
<Compile Include="RainmeterStudioPluginAttribute.cs" /> <Compile Include="RainmeterStudioPluginAttribute.cs" />
<Compile Include="PluginExportAttribute.cs" /> <Compile Include="PluginExportAttribute.cs" />
@ -70,9 +71,11 @@
<Compile Include="Utils\InputHelper.cs" /> <Compile Include="Utils\InputHelper.cs" />
<Compile Include="Utils\LinqExtension.cs" /> <Compile Include="Utils\LinqExtension.cs" />
<Compile Include="Utils\BitmapHelper.cs" /> <Compile Include="Utils\BitmapHelper.cs" />
<Compile Include="Utils\ObservableDictionary.cs" />
<Compile Include="Utils\PathHelper.cs" /> <Compile Include="Utils\PathHelper.cs" />
<Compile Include="Utils\Version.cs" /> <Compile Include="Utils\Version.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- 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. 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio", "RainmeterStudio\RainmeterStudio.csproj", "{438D0136-4A27-4E4D-A617-FFACE4554236}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{9A644478-2F1B-4145-8B31-6F8DBD42EC38} = {9A644478-2F1B-4145-8B31-6F8DBD42EC38} {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} {C641D7F8-DDDC-4EC6-8F5E-233520290642} = {C641D7F8-DDDC-4EC6-8F5E-233520290642}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.Tests", "RainmeterStudio.Tests\RainmeterStudio.Tests.csproj", "{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.Tests", "RainmeterStudio.Tests\RainmeterStudio.Tests.csproj", "{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}"
EndProject 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}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.Core", "RainmeterStudio.Core\RainmeterStudio.Core.csproj", "{1D2A4896-AF31-4E82-A84F-4E218067701F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainmeterStudio.TextEditorPlugin", "RainmeterStudio.TextEditor\RainmeterStudio.TextEditorPlugin.csproj", "{9A644478-2F1B-4145-8B31-6F8DBD42EC38}" 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|Mixed Platforms.Build.0 = Release|Any CPU
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A}.Release|Win32.ActiveCfg = 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 {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.ActiveCfg = Debug|Any CPU
{1D2A4896-AF31-4E82-A84F-4E218067701F}.Debug|Any CPU.Build.0 = 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 {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} {EE8EC522-8430-4B46-86A3-D943D77F9E4B} = {53D952E0-CFD2-4EFF-BAD4-5969E760EFA1}
{845F4BD4-6822-4D92-9DDB-15FD18A47E5A} = {8469BE7E-BCDB-4AA8-9541-719E8BFB19A7} {845F4BD4-6822-4D92-9DDB-15FD18A47E5A} = {8469BE7E-BCDB-4AA8-9541-719E8BFB19A7}
{9A644478-2F1B-4145-8B31-6F8DBD42EC38} = {4CCE6052-F43E-4360-B3E2-C046C6C0D86C} {9A644478-2F1B-4145-8B31-6F8DBD42EC38} = {4CCE6052-F43E-4360-B3E2-C046C6C0D86C}
{E8BD25E9-3055-4688-9E83-ECF684EF30C6} = {4CCE6052-F43E-4360-B3E2-C046C6C0D86C}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal