diff --git a/src/Engine/InstanceLocator.cs b/src/Engine/InstanceLocator.cs
new file mode 100644
index 00000000..c424d1b2
--- /dev/null
+++ b/src/Engine/InstanceLocator.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace WPFLocalizeExtension.Engine
+{
+ internal static class InstanceLocator
+ {
+ ///
+ /// Holds a SyncRoot to be thread safe
+ ///
+ private static readonly object SyncRoot = new object();
+
+ ///
+ /// Holds the threaded instances per type
+ ///
+ private static Dictionary> _instances = new Dictionary>();
+
+ ///
+ /// Get a singleton or per thread instance
+ ///
+ /// Type of the requested instance. Has to implement a public parameterless constructor.
+ /// instance of type
+ public static T Resolve() where T : class, new()
+ {
+ var instances = GetTypeInstances();
+ return GetInstance(instances);
+ }
+
+ ///
+ /// Get a singleton or per thread instance
+ ///
+ /// Type of the requested instance. Has to implement a public parameterless constructor.
+ /// instance of
+ public static object Resolve(Type type)
+ {
+ var instances = GetTypeInstances(type);
+ return GetInstance(instances, type);
+ }
+
+ ///
+ /// Get the instance dictionary for
+ ///
+ /// instance type
+ /// The new / existing instance collection for the requested type
+ public static Dictionary GetTypeInstances() where T : class
+ {
+ var type = typeof(T);
+ return GetTypeInstances(type);
+ }
+
+ ///
+ /// Get the instance dictionary for
+ ///
+ /// instance type
+ /// The new / existing instance collection for the requested type
+ public static Dictionary GetTypeInstances(Type type)
+ {
+ if (!_instances.ContainsKey(type))
+ {
+ lock (SyncRoot)
+ {
+ _instances.Add(type, new Dictionary());
+ }
+ }
+
+ return _instances[type];
+ }
+
+ ///
+ /// Get a instance of type
+ ///
+ /// instance type
+ /// instances dictionary
+ /// The new / existing instance of type
+ private static T GetInstance(Dictionary instances) where T : class, new()
+ {
+ return GetInstance(instances, typeof(T)) as T;
+ }
+
+ ///
+ /// Get a instance of
+ ///
+ /// instances dictionary
+ /// instance type
+ /// The new / existing instance of type
+ private static object GetInstance(Dictionary instances, Type type)
+ {
+ object result = null;
+ var threadId = Thread.CurrentThread.ManagedThreadId;
+
+ // when UseThreadInstances is activated the requested type has to implement the ILocalizeInstance interface
+ // otherwise we will use a singleton instance
+ if (LocalizeSettings.Instance.UseThreadInstances && typeof(ILocalizeInstance).IsAssignableFrom(type))
+ {
+ if (instances.ContainsKey(threadId))
+ result = instances[threadId];
+ }
+ else
+ result = instances.FirstOrDefault().Value;
+
+ if (result == null)
+ {
+ lock (SyncRoot)
+ {
+ result = Activator.CreateInstance(type);
+ CheckShutdownEvent(Thread.CurrentThread);
+ instances.Add(threadId, result);
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Check if the provided thread populates a dispatcher object, subsribe to the event and dissolve instances for this thread.
+ ///
+ ///
+ private static void CheckShutdownEvent(Thread thread)
+ {
+ var dis = Dispatcher.FromThread(thread);
+ if (dis != null && !_instances.Any(x => x.Value.Any(y => y.Key == thread.ManagedThreadId)))
+ {
+ dis.ShutdownStarted += (o, e) =>
+ {
+ foreach (var entry in _instances.SelectMany(x => x.Value.Where(y => y.Key == thread.ManagedThreadId)).ToList())
+ Dissolve(entry.Value);
+ };
+ }
+ }
+
+ ///
+ /// Remove a instance from the collection
+ ///
+ /// instance
+ internal static void Dissolve(object obj)
+ {
+ var instances = GetTypeInstances(obj.GetType());
+ if (instances.Any(x => x.Value == obj))
+ {
+ var entry = instances.Single(x => x.Value == obj);
+ lock (SyncRoot)
+ {
+ instances.Remove(entry.Key);
+ }
+ }
+ }
+ }
+
+ ///
+ /// A empty interface - just to indicate a class is useable for the thread / instance logic
+ ///
+ public interface ILocalizeInstance { }
+}
diff --git a/src/Engine/LocalizeDictionary.cs b/src/Engine/LocalizeDictionary.cs
index d1565598..15edf48c 100644
--- a/src/Engine/LocalizeDictionary.cs
+++ b/src/Engine/LocalizeDictionary.cs
@@ -41,7 +41,7 @@ namespace WPFLocalizeExtension.Engine
///
/// Represents the culture interface for localization
///
- public sealed class LocalizeDictionary : DependencyObject, INotifyPropertyChanged
+ public sealed class LocalizeDictionary : DependencyObject, INotifyPropertyChanged, ILocalizeInstance
{
#region INotifyPropertyChanged Implementation
///
@@ -102,7 +102,7 @@ internal void RaisePropertyChanged(string property)
"Separation",
typeof(string),
typeof(LocalizeDictionary),
- new PropertyMetadata(DefaultSeparation, SetSeparationFromDependencyProperty));
+ new PropertyMetadata(LocalizeSettings.Instance.Separation, SetSeparationFromDependencyProperty));
///
/// A flag indicating that the invariant culture should be included.
@@ -112,7 +112,7 @@ internal void RaisePropertyChanged(string property)
"IncludeInvariantCulture",
typeof(bool),
typeof(LocalizeDictionary),
- new PropertyMetadata(true, SetIncludeInvariantCultureFromDependencyProperty));
+ new PropertyMetadata(LocalizeSettings.Instance.IncludeInvariantCulture, SetIncludeInvariantCultureFromDependencyProperty));
///
/// A flag indicating that the cache is disabled.
@@ -122,7 +122,7 @@ internal void RaisePropertyChanged(string property)
"DisableCache",
typeof(bool),
typeof(LocalizeDictionary),
- new PropertyMetadata(false, SetDisableCacheFromDependencyProperty));
+ new PropertyMetadata(LocalizeSettings.Instance.DisableCache, SetDisableCacheFromDependencyProperty));
///
/// A flag indicating that missing keys should be output.
@@ -132,7 +132,7 @@ internal void RaisePropertyChanged(string property)
"OutputMissingKeys",
typeof(bool),
typeof(LocalizeDictionary),
- new PropertyMetadata(true, SetOutputMissingKeysFromDependencyProperty));
+ new PropertyMetadata(LocalizeSettings.Instance.OutputMissingKeys, SetOutputMissingKeysFromDependencyProperty));
#endregion
#region Dependency Property Callbacks
@@ -419,11 +419,6 @@ public static void SetDesignCulture(DependencyObject obj, string value)
///
private static readonly object SyncRoot = new object();
- ///
- /// Holds the instance of singleton
- ///
- private static LocalizeDictionary _instance;
-
///
/// Holds the current chosen
///
@@ -432,22 +427,22 @@ public static void SetDesignCulture(DependencyObject obj, string value)
///
/// Holds the separation char/string.
///
- private string _separation = DefaultSeparation;
+ private string _separation = LocalizeSettings.Instance.Separation;
///
/// Determines, if the contains the invariant culture.
///
- private bool _includeInvariantCulture = true;
+ private bool _includeInvariantCulture = LocalizeSettings.Instance.IncludeInvariantCulture;
///
/// Determines, if the cache is disabled.
///
- private bool _disableCache = true;
+ private bool _disableCache = LocalizeSettings.Instance.DisableCache;
///
/// Determines, if missing keys should be output.
///
- private bool _outputMissingKeys = true;
+ private bool _outputMissingKeys = LocalizeSettings.Instance.OutputMissingKeys;
///
/// A default provider.
@@ -457,7 +452,7 @@ public static void SetDesignCulture(DependencyObject obj, string value)
///
/// Determines, if the CurrentThread culture is set along with the Culture property.
///
- private bool _setCurrentThreadCulture = true;
+ private bool _setCurrentThreadCulture = LocalizeSettings.Instance.SetCurrentThreadCulture;
///
/// Determines if the code is run in DesignMode or not.
@@ -471,10 +466,10 @@ public static void SetDesignCulture(DependencyObject obj, string value)
/// Prevents a default instance of the class from being created.
/// Static Constructor
///
- private LocalizeDictionary()
+ public LocalizeDictionary()
{
- DefaultProvider = ResxLocalizationProvider.Instance;
- SetCultureCommand = new CultureInfoDelegateCommand(SetCulture);
+ DefaultProvider = InstanceLocator.Resolve(LocalizeSettings.Instance.LocalizationProviderType) as ILocalizationProvider;
+ SetCultureCommand = new CultureInfoDelegateCommand((c) => LocalizeSettings.Instance.Culture = c);
}
private void AvailableCulturesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
@@ -509,9 +504,14 @@ private void AvailableCulturesCollectionChanged(object sender, NotifyCollectionC
///
~LocalizeDictionary()
{
- LocExtension.ClearResourceBuffer();
- FELoc.ClearResourceBuffer();
- BLoc.ClearResourceBuffer();
+ // do not clear the resource buffer on multi threaded applications
+ if (!LocalizeSettings.Instance.UseThreadInstances)
+ {
+ LocExtension.ClearResourceBuffer();
+ FELoc.ClearResourceBuffer();
+ BLoc.ClearResourceBuffer();
+ }
+ InstanceLocator.Dissolve(this);
}
#endregion
@@ -521,11 +521,6 @@ private void AvailableCulturesCollectionChanged(object sender, NotifyCollectionC
///
public static CultureInfo DefaultCultureInfo => CultureInfo.InvariantCulture;
- ///
- /// Gets the default separation char/string.
- ///
- public static string DefaultSeparation => "_";
-
///
/// Gets the singleton.
/// If the underlying instance is null, a instance will be created.
@@ -534,26 +529,8 @@ public static LocalizeDictionary Instance
{
get
{
- // check if the underlying instance is null
- if (_instance == null)
- {
- // if it is null, lock the syncroot.
- // if another thread is accessing this too,
- // it have to wait until the syncroot is released
- lock (SyncRoot)
- {
- // check again, if the underlying instance is null
- if (_instance == null)
- {
- // create a new instance
- _instance = new LocalizeDictionary();
- }
- }
- }
-
- // return the existing/new instance
- return _instance;
- }
+ return InstanceLocator.Resolve();
+ }
}
///
@@ -972,13 +949,21 @@ internal MissingKeyEventArgs OnNewMissingKeyEvent(object sender, string key)
#endregion
#region DictionaryEvent (using weak references)
- internal static class DictionaryEvent
+ internal class DictionaryEvent : ILocalizeInstance
{
///
/// The list of listeners
///
- private static readonly List Listeners = new List();
- private static readonly object ListenersLock = new object();
+ private readonly List Listeners = new List();
+ private readonly object ListenersLock = new object();
+
+ private static DictionaryEvent Instance
+ {
+ get
+ {
+ return InstanceLocator.Resolve();
+ }
+ }
///
/// Fire the event.
@@ -988,16 +973,17 @@ internal static class DictionaryEvent
internal static void Invoke(DependencyObject sender, DictionaryEventArgs args)
{
var list = new List();
+ var instance = Instance;
- lock (ListenersLock)
+ lock (instance.ListenersLock)
{
- foreach (var wr in Listeners.ToList())
+ foreach (var wr in instance.Listeners.ToList())
{
var targetReference = wr.Target;
if (targetReference != null)
list.Add((IDictionaryEventListener)targetReference);
else
- Listeners.Remove(wr);
+ instance.Listeners.Remove(wr);
}
}
@@ -1014,23 +1000,25 @@ internal static void AddListener(IDictionaryEventListener listener)
if (listener == null)
return;
+ var instance = Instance;
+
// Check, if this listener already was added.
bool listenerExists = false;
- lock (ListenersLock)
+ lock (instance.ListenersLock)
{
- foreach (var wr in Listeners.ToList())
+ foreach (var wr in instance.Listeners.ToList())
{
var targetReference = wr.Target;
if (targetReference == null)
- Listeners.Remove(wr);
+ instance.Listeners.Remove(wr);
else if (targetReference == listener)
listenerExists = true;
}
// Add it now.
if (!listenerExists)
- Listeners.Add(new WeakReference(listener));
+ instance.Listeners.Add(new WeakReference(listener));
}
}
@@ -1043,15 +1031,17 @@ internal static void RemoveListener(IDictionaryEventListener listener)
if (listener == null)
return;
- lock (ListenersLock)
+ var instance = Instance;
+
+ lock (instance.ListenersLock)
{
- foreach (var wr in Listeners.ToList())
+ foreach (var wr in instance.Listeners.ToList())
{
var targetReference = wr.Target;
if (targetReference == null)
- Listeners.Remove(wr);
+ instance.Listeners.Remove(wr);
else if ((IDictionaryEventListener)targetReference == listener)
- Listeners.Remove(wr);
+ instance.Listeners.Remove(wr);
}
}
}
@@ -1063,14 +1053,15 @@ internal static void RemoveListener(IDictionaryEventListener listener)
/// An enumeration of listeners.
internal static IEnumerable EnumerateListeners()
{
- lock (ListenersLock)
+ var instance = Instance;
+ lock (instance.ListenersLock)
{
- foreach (var wr in Listeners.ToList())
+ foreach (var wr in instance.Listeners.ToList())
{
var targetReference = wr.Target;
if (targetReference == null)
- Listeners.Remove(wr);
+ instance.Listeners.Remove(wr);
else if (targetReference is T)
yield return (T)targetReference;
}
@@ -1080,11 +1071,6 @@ internal static IEnumerable EnumerateListeners()
#endregion
#region CultureInfoDelegateCommand
- private void SetCulture(CultureInfo c)
- {
- Culture = c;
- }
-
///
/// A class for culture commands.
///
diff --git a/src/Engine/LocalizeSettings.cs b/src/Engine/LocalizeSettings.cs
new file mode 100644
index 00000000..fc06b49c
--- /dev/null
+++ b/src/Engine/LocalizeSettings.cs
@@ -0,0 +1,485 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using WPFLocalizeExtension.Providers;
+
+namespace WPFLocalizeExtension.Engine
+{
+ ///
+ /// A class to hold all global settings
+ ///
+ public sealed class LocalizeSettings
+ {
+ #region Attached Dependency Properties
+ ///
+ /// A flag indicating to use singleton or per thread based instance
+ ///
+ public static readonly DependencyProperty UseThreadInstancesProperty =
+ DependencyProperty.RegisterAttached("UseThreadInstances", typeof(bool), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultUseThreadInstances, UseThreadInstancesChangedCallback));
+
+ ///
+ /// to set the localization Culture
+ ///
+ public static readonly DependencyProperty CultureProperty =
+ DependencyProperty.RegisterAttached("Culture", typeof(CultureInfo), typeof(LocalizeSettings), new PropertyMetadata(null, CultureChangedCallback));
+
+ ///
+ /// A flag indicating that the cache is disabled.
+ ///
+ public static readonly DependencyProperty DisableCacheProperty =
+ DependencyProperty.RegisterAttached("DisableCache", typeof(bool), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultDisableCache, DisableCacheChangedCallback));
+
+ ///
+ /// A flag indicating that the invariant culture should be included.
+ ///
+ public static readonly DependencyProperty IncludeInvariantCultureProperty =
+ DependencyProperty.RegisterAttached("IncludeInvariantCulture", typeof(bool), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultIncludeInvariantCulture, IncludeInvariantCultureChangedCallback));
+
+ ///
+ /// A flag indicating that missing keys should be output.
+ ///
+ public static readonly DependencyProperty OutputMissingKeysProperty =
+ DependencyProperty.RegisterAttached("OutputMissingKeys", typeof(bool), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultOutputMissingKeys, OutputMissingKeysChangedCallback));
+
+ ///
+ /// to set the separation character/string for resource name patterns.
+ ///
+ public static readonly DependencyProperty SeparationProperty =
+ DependencyProperty.RegisterAttached("Separation", typeof(string), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultSeparation, SeparationChangedCallback));
+
+ ///
+ /// to set the default type.
+ ///
+ public static readonly DependencyProperty LocalizationProviderTypeProperty =
+ DependencyProperty.RegisterAttached("LocalizationProviderType", typeof(Type), typeof(LocalizeSettings), new PropertyMetadata(Settings.DefaultLocalizatinProviderType, LocalizationProviderTypeChangedCallback));
+
+ #endregion
+
+ #region Attached Dependency Properties Management
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static bool GetUseThreadInstances(DependencyObject obj)
+ {
+ return Instance.UseThreadInstances;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetUseThreadInstances(DependencyObject obj, bool value)
+ {
+ Instance.UseThreadInstances = value;
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static CultureInfo GetCulture(DependencyObject obj)
+ {
+ return Instance.Culture;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetCulture(DependencyObject obj, CultureInfo value)
+ {
+ Instance.Culture = value;
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static bool GetDisableCache(DependencyObject obj)
+ {
+ return Instance.DisableCache;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetDisableCache(DependencyObject obj, bool value)
+ {
+ Instance.DisableCache = value;
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static bool GetIncludeInvariantCulture(DependencyObject obj)
+ {
+ return (bool)obj.GetValue(IncludeInvariantCultureProperty);
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetIncludeInvariantCulture(DependencyObject obj, bool value)
+ {
+ obj.SetValue(IncludeInvariantCultureProperty, value);
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static bool GetOutputMissingKeys(DependencyObject obj)
+ {
+ return Instance.OutputMissingKeys;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetOutputMissingKeys(DependencyObject obj, bool value)
+ {
+ Instance.OutputMissingKeys = value;
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static string GetSeparation(DependencyObject obj)
+ {
+ return Instance.Separation;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetSeparation(DependencyObject obj, string value)
+ {
+ Instance.Separation = value;
+ }
+
+ ///
+ /// Get
+ ///
+ ///
+ ///
+ public static Type GetLocalizationProviderType(DependencyObject obj)
+ {
+ return Instance.LocalizationProviderType;
+ }
+
+ ///
+ /// Set
+ ///
+ /// not used
+ ///
+ public static void SetLocalizationProviderType(DependencyObject obj, Type value)
+ {
+ Instance.LocalizationProviderType = value;
+ }
+ #endregion
+
+ #region Attached Dependency Properties Callback
+ private static void UseThreadInstancesChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is bool b)
+ Instance.UseThreadInstances = b;
+ }
+
+ private static void CultureChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is CultureInfo c)
+ Instance.Culture = c;
+ }
+
+ private static void DisableCacheChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is bool b)
+ Instance.DisableCache = b;
+ }
+
+ private static void IncludeInvariantCultureChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is bool b)
+ Instance.IncludeInvariantCulture = b;
+ }
+
+ private static void OutputMissingKeysChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is bool b)
+ Instance.OutputMissingKeys = b;
+ }
+
+ private static void SeparationChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is string s)
+ Instance.Separation = s;
+ }
+
+ private static void LocalizationProviderTypeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (e.NewValue is Type t)
+ Instance.LocalizationProviderType = t;
+ }
+ #endregion
+
+ #region Static Properties
+
+ private static Settings _instance;
+
+ ///
+ /// Singleton settings instance
+ ///
+ public static Settings Instance
+ {
+ get
+ {
+ return _instance ?? (_instance = new Settings());
+ }
+ }
+ #endregion
+
+ #region Settings Class
+ ///
+ /// Global settings class
+ ///
+ public class Settings
+ {
+ ///
+ /// protected constructor
+ ///
+ internal Settings() { }
+
+ #region Default values
+ ///
+ /// The default separation key for
+ ///
+ public const string DefaultSeparation = "_";
+
+ ///
+ /// Default value for
+ ///
+ public const bool DefaultUseThreadInstances = false;
+
+ ///
+ /// Default value for
+ ///
+ public const bool DefaultDisableCache = false;
+
+ ///
+ /// Default value for
+ ///
+ public const bool DefaultIncludeInvariantCulture = true;
+
+ ///
+ /// Default value for
+ ///
+ public const bool DefaultOutputMissingKeys = true;
+
+ ///
+ /// Default type for
+ ///
+ public static readonly Type DefaultLocalizatinProviderType = typeof(ResxLocalizationProvider);
+ #endregion
+
+ #region Private Properties
+ private CultureInfo _culture;
+ private bool _disableCache = DefaultDisableCache;
+ private bool _includeInvariantCulture = DefaultIncludeInvariantCulture;
+ private bool _outputMissingKeys = DefaultOutputMissingKeys;
+ private string _separation = DefaultSeparation;
+ private Type _LocalizationProviderType = DefaultLocalizatinProviderType;
+ private bool _setCurrentThreadCulture = true;
+
+ #endregion
+
+ #region Public Properties
+ ///
+ /// A flag to determine the behaivor of this application on multithreaded applications.
+ /// When set to false a singleton instances will be used
+ /// otherwise every thread get's his own instance.
+ ///
+ public bool UseThreadInstances { get; set; } = DefaultUseThreadInstances;
+
+ ///
+ /// Global culture
+ ///
+ public CultureInfo Culture
+ {
+ get
+ {
+ return _culture;
+ }
+ set
+ {
+ if(_culture != value)
+ {
+ _culture = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.Culture = _culture));
+ }
+ }
+ }
+
+ ///
+ /// A flag to disable the caching logic
+ ///
+ public bool DisableCache
+ {
+ get
+ {
+ return _disableCache;
+ }
+ set
+ {
+ if(_disableCache != value)
+ {
+ _disableCache = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.DisableCache = _disableCache));
+ }
+ }
+ }
+
+ ///
+ /// Determines, if the contains the invariant culture.
+ ///
+ public bool IncludeInvariantCulture
+ {
+ get
+ {
+ return _includeInvariantCulture;
+ }
+ set
+ {
+ if (_includeInvariantCulture != value)
+ {
+ _includeInvariantCulture = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.IncludeInvariantCulture = _includeInvariantCulture));
+ }
+ }
+ }
+
+ ///
+ /// Determines, if missing keys should be output.
+ ///
+ public bool OutputMissingKeys
+ {
+ get
+ {
+ return _outputMissingKeys;
+ }
+ set
+ {
+ if(_outputMissingKeys != value)
+ {
+ _outputMissingKeys = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.OutputMissingKeys = _outputMissingKeys));
+ }
+ }
+ }
+
+ ///
+ /// Holds the separation char/string.
+ ///
+ public string Separation
+ {
+ get
+ {
+ return _separation;
+ }
+ set
+ {
+ if(_separation != value)
+ {
+ _separation = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.Separation = _separation));
+ }
+ }
+ }
+
+ ///
+ /// Holds the default localization provider type
+ /// This type has to implementd
+ ///
+ public Type LocalizationProviderType
+ {
+ get
+ {
+ return _LocalizationProviderType;
+ }
+ set
+ {
+ if (value != null)
+ {
+ if (typeof(ILocalizationProvider).IsAssignableFrom(value))
+ _LocalizationProviderType = value;
+ else
+ throw new NotSupportedException($"The type {value} can't be used as {nameof(LocalizationProviderType)}, it has to implement the interface {nameof(ILocalizationProvider)}!");
+ }
+ else
+ _LocalizationProviderType = DefaultLocalizatinProviderType;
+ }
+ }
+
+ ///
+ /// Gets or sets a flag that determines, if the CurrentThread culture should be changed along with the Culture property.
+ ///
+ public bool SetCurrentThreadCulture
+ {
+ get
+ {
+ return _setCurrentThreadCulture;
+ }
+ set
+ {
+ if(value != _setCurrentThreadCulture)
+ {
+ _setCurrentThreadCulture = value;
+
+ foreach (var instance in GetDictionaries())
+ instance.Dispatcher.BeginInvoke(new Action(() => instance.SetCurrentThreadCulture = _setCurrentThreadCulture));
+ }
+ }
+ }
+ #endregion
+
+ #region Helper
+ private List GetDictionaries()
+ {
+ return InstanceLocator.GetTypeInstances().Select(x => x.Value as LocalizeDictionary).ToList();
+ }
+ #endregion
+ }
+ #endregion
+ }
+}
diff --git a/src/Providers/CSVEmbeddedLocalizationProvider.cs b/src/Providers/CSVEmbeddedLocalizationProvider.cs
index 0eb69fce..ad53b366 100644
--- a/src/Providers/CSVEmbeddedLocalizationProvider.cs
+++ b/src/Providers/CSVEmbeddedLocalizationProvider.cs
@@ -26,7 +26,7 @@ namespace WPFLocalizeExtension.Providers
///
/// A singleton CSV provider that uses attached properties and the Parent property to iterate through the visual tree.
///
- public class CSVEmbeddedLocalizationProvider : CSVLocalizationProviderBase
+ public class CSVEmbeddedLocalizationProvider : CSVLocalizationProviderBase, ILocalizeInstance
{
#region Dependency Properties
///
@@ -116,16 +116,6 @@ public static void SetDefaultAssembly(DependencyObject obj, string value)
#endregion
#region Singleton Variables, Properties & Constructor
- ///
- /// The instance of the singleton.
- ///
- private static CSVEmbeddedLocalizationProvider _instance;
-
- ///
- /// Lock object for the creation of the singleton instance.
- ///
- private static readonly object InstanceLock = new object();
-
///
/// Gets the singleton.
///
@@ -133,24 +123,14 @@ public static CSVEmbeddedLocalizationProvider Instance
{
get
{
- if (_instance == null)
- {
- lock (InstanceLock)
- {
- if (_instance == null)
- _instance = new CSVEmbeddedLocalizationProvider();
- }
- }
-
- // return the existing/new instance
- return _instance;
+ return InstanceLocator.Resolve();
}
}
///
- /// The singleton constructor.
+ /// The instance constructor.
///
- private CSVEmbeddedLocalizationProvider()
+ public CSVEmbeddedLocalizationProvider()
{
ResourceManagerList = new Dictionary();
AvailableCultures = new ObservableCollection { CultureInfo.InvariantCulture };
diff --git a/src/Providers/CSVLocalizationProvider.cs b/src/Providers/CSVLocalizationProvider.cs
index 0bfce66f..a3fd2fd1 100644
--- a/src/Providers/CSVLocalizationProvider.cs
+++ b/src/Providers/CSVLocalizationProvider.cs
@@ -21,7 +21,7 @@ namespace WPFLocalizeExtension.Providers
///
/// A singleton CSV provider that uses attached properties and the Parent property to iterate through the visual tree.
///
- public class CSVLocalizationProvider : CSVLocalizationProviderBase
+ public class CSVLocalizationProvider : CSVLocalizationProviderBase, ILocalizeInstance
{
#region Dependency Properties
///
@@ -81,16 +81,6 @@ public static void SetDefaultDictionary(DependencyObject obj, string value)
#endregion
#region Singleton Variables, Properties & Constructor
- ///
- /// The instance of the singleton.
- ///
- private static CSVLocalizationProvider _instance;
-
- ///
- /// Lock object for the creation of the singleton instance.
- ///
- private static readonly object InstanceLock = new object();
-
///
/// Gets the singleton.
///
@@ -98,24 +88,14 @@ public static CSVLocalizationProvider Instance
{
get
{
- if (_instance == null)
- {
- lock (InstanceLock)
- {
- if (_instance == null)
- _instance = new CSVLocalizationProvider();
- }
- }
-
- // return the existing/new instance
- return _instance;
+ return InstanceLocator.Resolve();
}
}
///
- /// The singleton constructor.
+ /// The instance constructor.
///
- private CSVLocalizationProvider()
+ public CSVLocalizationProvider()
{
AvailableCultures = new ObservableCollection { CultureInfo.InvariantCulture };
}
diff --git a/src/Providers/InheritingResxLocalizationProvider.cs b/src/Providers/InheritingResxLocalizationProvider.cs
index cc81474c..1c8beaf7 100644
--- a/src/Providers/InheritingResxLocalizationProvider.cs
+++ b/src/Providers/InheritingResxLocalizationProvider.cs
@@ -14,13 +14,14 @@ namespace WPFLocalizeExtension.Providers
using System.Globalization;
using System.Resources;
using System.Windows;
+ using WPFLocalizeExtension.Engine;
using XAMLMarkupExtensions.Base;
#endregion
///
/// A singleton RESX provider that uses inheriting attached properties.
///
- public class InheritingResxLocalizationProvider : ResxLocalizationProviderBase
+ public class InheritingResxLocalizationProvider : ResxLocalizationProviderBase, ILocalizeInstance
{
#region Dependency Properties
///
@@ -103,16 +104,6 @@ public static void SetDefaultAssembly(DependencyObject obj, string value)
#endregion
#region Singleton Variables, Properties & Constructor
- ///
- /// The instance of the singleton.
- ///
- private static InheritingResxLocalizationProvider _instance;
-
- ///
- /// Lock object for the creation of the singleton instance.
- ///
- private static readonly object InstanceLock = new object();
-
///
/// Gets the singleton.
///
@@ -120,24 +111,14 @@ public static InheritingResxLocalizationProvider Instance
{
get
{
- if (_instance == null)
- {
- lock (InstanceLock)
- {
- if (_instance == null)
- _instance = new InheritingResxLocalizationProvider();
- }
- }
-
- // return the existing/new instance
- return _instance;
+ return InstanceLocator.Resolve();
}
}
///
- /// The singleton constructor.
+ /// The instance constructor.
///
- private InheritingResxLocalizationProvider()
+ public InheritingResxLocalizationProvider()
{
ResourceManagerList = new Dictionary();
AvailableCultures = new ObservableCollection { CultureInfo.InvariantCulture };
diff --git a/src/Providers/ResxLocalizationProvider.cs b/src/Providers/ResxLocalizationProvider.cs
index f482c627..1e1be4da 100644
--- a/src/Providers/ResxLocalizationProvider.cs
+++ b/src/Providers/ResxLocalizationProvider.cs
@@ -21,7 +21,7 @@ namespace WPFLocalizeExtension.Providers
///
/// A singleton RESX provider that uses attached properties and the Parent property to iterate through the visual tree.
///
- public class ResxLocalizationProvider : ResxLocalizationProviderBase
+ public class ResxLocalizationProvider : ResxLocalizationProviderBase, ILocalizeInstance
{
#region Dependency Properties
///
@@ -175,16 +175,6 @@ public static void SetIgnoreCase(DependencyObject obj, bool value)
#endregion
#region Singleton Variables, Properties & Constructor
- ///
- /// The instance of the singleton.
- ///
- private static ResxLocalizationProvider _instance;
-
- ///
- /// Lock object for the creation of the singleton instance.
- ///
- private static readonly object InstanceLock = new object();
-
///
/// Gets the singleton.
///
@@ -192,25 +182,7 @@ public static ResxLocalizationProvider Instance
{
get
{
- if (_instance == null)
- {
- lock (InstanceLock)
- {
- if (_instance == null)
- _instance = new ResxLocalizationProvider();
- }
- }
-
- // return the existing/new instance
- return _instance;
- }
-
- set
- {
- lock (InstanceLock)
- {
- _instance = value;
- }
+ return InstanceLocator.Resolve();
}
}
@@ -219,17 +191,24 @@ public static ResxLocalizationProvider Instance
///
public static void Reset()
{
- Instance = null;
+ var instance = Instance;
+ InstanceLocator.Dissolve(instance);
+ instance = null;
}
///
- /// The singleton constructor.
+ /// The instance constructor.
///
- protected ResxLocalizationProvider()
+ public ResxLocalizationProvider()
{
ResourceManagerList = new Dictionary();
AvailableCultures = new ObservableCollection { CultureInfo.InvariantCulture };
}
+
+ ~ResxLocalizationProvider()
+ {
+ InstanceLocator.Dissolve(this);
+ }
#endregion
#region Abstract assembly & dictionary lookup