Actions persistence working.
authorStephane Lenclud
Sun, 24 Jul 2016 13:30:08 +0200
changeset 2121a0791daa243
parent 211 96f8b4dc4300
child 213 77092f415c7c
Actions persistence working.
Server/ConsumerElectronicControl.cs
Server/DisplaySettings.cs
Server/FormEditAction.cs
Server/MainForm.cs
Server/Properties/Settings.Designer.cs
Server/Properties/Settings.settings
Server/SharpDisplayManager.csproj
SharpLibEar/Action.cs
SharpLibEar/ActionSleep.cs
SharpLibEar/Event.cs
SharpLibEar/EventActionManager.cs
SharpLibEar/ManagerEventAction.cs
SharpLibEar/SharpLibEar.csproj
SharpLibUtils/Reflection.cs
SharpLibUtils/SharpLibUtils.csproj
SharpLibUtils/TypeConverterJson.cs
     1.1 --- a/Server/ConsumerElectronicControl.cs	Sat Jul 23 19:22:56 2016 +0200
     1.2 +++ b/Server/ConsumerElectronicControl.cs	Sun Jul 24 13:30:08 2016 +0200
     1.3 @@ -93,7 +93,7 @@
     1.4  
     1.5          private void OnMonitorPowerOn()
     1.6          {
     1.7 -            EventActionManager.Current.GetEvent<EventMonitorPowerOn>().Trigger();
     1.8 +            ManagerEventAction.Current.GetEvent<EventMonitorPowerOn>().Trigger();
     1.9  
    1.10              Console.WriteLine("OnMonitorPowerOn");
    1.11  
    1.12 @@ -112,7 +112,7 @@
    1.13  
    1.14          private void OnMonitorPowerOff()
    1.15          {
    1.16 -            EventActionManager.Current.GetEvent<EventMonitorPowerOff>().Trigger();
    1.17 +            ManagerEventAction.Current.GetEvent<EventMonitorPowerOff>().Trigger();
    1.18  
    1.19              Console.WriteLine("OnMonitorPowerOff");
    1.20  
     2.1 --- a/Server/DisplaySettings.cs	Sat Jul 23 19:22:56 2016 +0200
     2.2 +++ b/Server/DisplaySettings.cs	Sun Jul 24 13:30:08 2016 +0200
     2.3 @@ -28,6 +28,7 @@
     2.4  using System.Runtime.Serialization.Json;
     2.5  using System.IO;
     2.6  using System.Drawing;
     2.7 +using SharpLib.Utils;
     2.8  
     2.9  namespace SharpDisplayManager
    2.10  {
    2.11 @@ -114,10 +115,12 @@
    2.12      /// <summary>
    2.13      /// Contain settings for each of our display type.
    2.14      /// </summary>
    2.15 -    [TypeConverter(typeof(DisplaySettingsConverter))]
    2.16 +    [TypeConverter(typeof(TypeConverterJson<DisplaysSettings>))]
    2.17      [DataContract]
    2.18      public class DisplaysSettings
    2.19      {
    2.20 +        private List<DisplaySettings> iDisplays;
    2.21 +
    2.22          public DisplaysSettings()
    2.23          {
    2.24              Init();
    2.25 @@ -125,9 +128,9 @@
    2.26  
    2.27          public void Init()
    2.28          {
    2.29 -            if (Displays == null)
    2.30 +            if (iDisplays == null)
    2.31              {
    2.32 -                Displays = new List<DisplaySettings>();
    2.33 +                iDisplays = new List<DisplaySettings>();
    2.34              }
    2.35          }
    2.36  
    2.37 @@ -135,50 +138,9 @@
    2.38          //public int CurrentSettingsIndex { get; set; }
    2.39  
    2.40          [DataMember]
    2.41 -        public List<DisplaySettings> Displays { get; set; }
    2.42 +        public List<DisplaySettings> Displays { get { Init(); return iDisplays; } private set { iDisplays = value; } }
    2.43  
    2.44 -        public override string ToString()
    2.45 -        {
    2.46 -            //Save settings into JSON string
    2.47 -            MemoryStream stream = new MemoryStream();
    2.48 -            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DisplaysSettings));
    2.49 -            ser.WriteObject(stream, this);
    2.50 -            // convert stream to string
    2.51 -            stream.Position = 0;
    2.52 -            StreamReader reader = new StreamReader(stream);
    2.53 -            string text = reader.ReadToEnd();
    2.54 -            return text;
    2.55 -        }
    2.56 +
    2.57      }
    2.58 -
    2.59 -    public class DisplaySettingsConverter : TypeConverter
    2.60 -    {
    2.61 -        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    2.62 -        {
    2.63 -            if (sourceType == typeof(string))
    2.64 -                return true;
    2.65 -            else
    2.66 -                return base.CanConvertFrom(context, sourceType);
    2.67 -        }
    2.68 -
    2.69 -        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    2.70 -        {
    2.71 -            string stringValue = value as string;
    2.72 -            if (stringValue != null)
    2.73 -            {
    2.74 -                //Load settings form JSON string
    2.75 -                byte[] byteArray = Encoding.UTF8.GetBytes(stringValue);
    2.76 -                MemoryStream stream = new MemoryStream(byteArray);
    2.77 -                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(DisplaysSettings));
    2.78 -                DisplaysSettings settings = (DisplaysSettings)ser.ReadObject(stream);
    2.79 -                settings.Init();
    2.80 -                return settings;
    2.81 -            }
    2.82 -            else
    2.83 -                return base.ConvertFrom(context, culture, value);
    2.84 -        }
    2.85 -    };
    2.86 -
    2.87 -
    2.88  }
    2.89  
     3.1 --- a/Server/FormEditAction.cs	Sat Jul 23 19:22:56 2016 +0200
     3.2 +++ b/Server/FormEditAction.cs	Sun Jul 24 13:30:08 2016 +0200
     3.3 @@ -23,9 +23,9 @@
     3.4          private void FormEditAction_Load(object sender, EventArgs e)
     3.5          {
     3.6              //Populate registered actions
     3.7 -            foreach (string key in EventActionManager.Current.ActionTypes.Keys)
     3.8 +            foreach (string key in ManagerEventAction.Current.ActionTypes.Keys)
     3.9              {
    3.10 -                Type t = EventActionManager.Current.ActionTypes[key];
    3.11 +                Type t = ManagerEventAction.Current.ActionTypes[key];
    3.12                  comboBoxActionType.Items.Add(t);                
    3.13              }
    3.14  
     4.1 --- a/Server/MainForm.cs	Sat Jul 23 19:22:56 2016 +0200
     4.2 +++ b/Server/MainForm.cs	Sun Jul 24 13:30:08 2016 +0200
     4.3 @@ -70,7 +70,7 @@
     4.4  	[System.ComponentModel.DesignerCategory("Form")]
     4.5  	public partial class MainForm : MainFormHid, IMMNotificationClient
     4.6      {
     4.7 -        public EventActionManager iManager = new EventActionManager();        
     4.8 +        //public ManagerEventAction iManager = new ManagerEventAction();        
     4.9          DateTime LastTickTime;
    4.10          Display iDisplay;
    4.11          System.Drawing.Bitmap iBmp;
    4.12 @@ -131,7 +131,19 @@
    4.13  
    4.14          public MainForm()
    4.15          {
    4.16 -            EventActionManager.Current = iManager;
    4.17 +            ManagerEventAction.Current = Properties.Settings.Default.Actions;
    4.18 +            if (ManagerEventAction.Current == null)
    4.19 +            {
    4.20 +                //No actions in our settings yet
    4.21 +                ManagerEventAction.Current = new ManagerEventAction();
    4.22 +                Properties.Settings.Default.Actions = ManagerEventAction.Current;
    4.23 +            }
    4.24 +            else
    4.25 +            {
    4.26 +                //We loaded actions from our settings
    4.27 +                //We need to hook them with corresponding events
    4.28 +                ManagerEventAction.Current.Init();
    4.29 +            }
    4.30              iSkipFrameRendering = false;
    4.31  			iClosing = false;
    4.32              iCurrentClientSessionId = "";
    4.33 @@ -295,9 +307,9 @@
    4.34              //Reset our tree
    4.35              iTreeViewEvents.Nodes.Clear();
    4.36              //Populate registered events
    4.37 -            foreach (string key in EventActionManager.Current.Events.Keys)
    4.38 +            foreach (string key in ManagerEventAction.Current.Events.Keys)
    4.39              {
    4.40 -                Event e = EventActionManager.Current.Events[key];
    4.41 +                Event e = ManagerEventAction.Current.Events[key];
    4.42                  TreeNode eventNode = iTreeViewEvents.Nodes.Add(key,e.Name);
    4.43                  eventNode.Tag = e;
    4.44                  eventNode.Nodes.Add(key + ".Description", e.Description);
    4.45 @@ -2654,8 +2666,13 @@
    4.46  
    4.47          private void buttonAddAction_Click(object sender, EventArgs e)
    4.48          {
    4.49 -            Event ear = (Event)iTreeViewEvents.SelectedNode.Tag;
    4.50 -            if (ear == null)
    4.51 +            if (iTreeViewEvents.SelectedNode==null)
    4.52 +            {
    4.53 +                return;
    4.54 +            }
    4.55 +
    4.56 +            Event earEvent = (Event)iTreeViewEvents.SelectedNode.Tag;
    4.57 +            if (earEvent == null)
    4.58              {
    4.59                  //Must select event node
    4.60                  return;
    4.61 @@ -2665,7 +2682,9 @@
    4.62              DialogResult res = CodeProject.Dialog.DlgBox.ShowDialog(ea);
    4.63              if (res == DialogResult.OK)
    4.64              {
    4.65 -                ear.Actions.Add(ea.Action);
    4.66 +                earEvent.Actions.Add(ea.Action);                
    4.67 +                Properties.Settings.Default.Actions = ManagerEventAction.Current;
    4.68 +                Properties.Settings.Default.Save();
    4.69                  SetupEvents();
    4.70              }
    4.71          }
     5.1 --- a/Server/Properties/Settings.Designer.cs	Sat Jul 23 19:22:56 2016 +0200
     5.2 +++ b/Server/Properties/Settings.Designer.cs	Sun Jul 24 13:30:08 2016 +0200
     5.3 @@ -189,5 +189,16 @@
     5.4                  this["CecReconnectToPowerTv"] = value;
     5.5              }
     5.6          }
     5.7 +        
     5.8 +        [global::System.Configuration.UserScopedSettingAttribute()]
     5.9 +        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    5.10 +        public global::SharpLib.Ear.ManagerEventAction Actions {
    5.11 +            get {
    5.12 +                return ((global::SharpLib.Ear.ManagerEventAction)(this["Actions"]));
    5.13 +            }
    5.14 +            set {
    5.15 +                this["Actions"] = value;
    5.16 +            }
    5.17 +        }
    5.18      }
    5.19  }
     6.1 --- a/Server/Properties/Settings.settings	Sat Jul 23 19:22:56 2016 +0200
     6.2 +++ b/Server/Properties/Settings.settings	Sun Jul 24 13:30:08 2016 +0200
     6.3 @@ -44,5 +44,8 @@
     6.4      <Setting Name="CecReconnectToPowerTv" Type="System.Boolean" Scope="User">
     6.5        <Value Profile="(Default)">False</Value>
     6.6      </Setting>
     6.7 +    <Setting Name="Actions" Type="SharpLib.Ear.ManagerEventAction" Scope="User">
     6.8 +      <Value Profile="(Default)" />
     6.9 +    </Setting>
    6.10    </Settings>
    6.11  </SettingsFile>
    6.12 \ No newline at end of file
     7.1 --- a/Server/SharpDisplayManager.csproj	Sat Jul 23 19:22:56 2016 +0200
     7.2 +++ b/Server/SharpDisplayManager.csproj	Sun Jul 24 13:30:08 2016 +0200
     7.3 @@ -34,7 +34,7 @@
     7.4      <WebPage>index.htm</WebPage>
     7.5      <OpenBrowserOnPublish>false</OpenBrowserOnPublish>
     7.6      <ApplicationRevision>0</ApplicationRevision>
     7.7 -    <ApplicationVersion>0.9.3.0</ApplicationVersion>
     7.8 +    <ApplicationVersion>0.9.4.0</ApplicationVersion>
     7.9      <UseApplicationTrust>false</UseApplicationTrust>
    7.10      <CreateDesktopShortcut>true</CreateDesktopShortcut>
    7.11      <PublishWizardCompleted>true</PublishWizardCompleted>
    7.12 @@ -221,7 +221,9 @@
    7.13        <DependentUpon>Resources.resx</DependentUpon>
    7.14        <DesignTime>True</DesignTime>
    7.15      </Compile>
    7.16 -    <None Include="App.config" />
    7.17 +    <None Include="App.config">
    7.18 +      <SubType>Designer</SubType>
    7.19 +    </None>
    7.20      <None Include="app.manifest" />
    7.21      <None Include="packages.config" />
    7.22      <None Include="Properties\Settings.settings">
     8.1 --- a/SharpLibEar/Action.cs	Sat Jul 23 19:22:56 2016 +0200
     8.2 +++ b/SharpLibEar/Action.cs	Sun Jul 24 13:30:08 2016 +0200
     8.3 @@ -2,12 +2,14 @@
     8.4  
     8.5  
     8.6  using System;
     8.7 +using System.Collections.Generic;
     8.8  using System.Runtime.Serialization;
     8.9  using System.Threading;
    8.10  
    8.11  namespace SharpLib.Ear
    8.12  {
    8.13      [DataContract]
    8.14 +    [KnownType("DerivedTypes")]
    8.15      public abstract class Action: IComparable
    8.16      {
    8.17          public abstract void Execute();
    8.18 @@ -23,6 +25,12 @@
    8.19              //Sort by action name
    8.20              return Utils.Reflection.GetAttribute<AttributeAction>(GetType()).Name.CompareTo(obj.GetType());            
    8.21          }
    8.22 +
    8.23 +        private static IEnumerable<Type> DerivedTypes()
    8.24 +        {
    8.25 +            return SharpLib.Utils.Reflection.GetDerivedTypes<Action>();
    8.26 +        }
    8.27 +
    8.28      }
    8.29  
    8.30  
     9.1 --- a/SharpLibEar/ActionSleep.cs	Sat Jul 23 19:22:56 2016 +0200
     9.2 +++ b/SharpLibEar/ActionSleep.cs	Sun Jul 24 13:30:08 2016 +0200
     9.3 @@ -13,6 +13,7 @@
     9.4      [AttributeAction(Id = "Thread.Sleep", Name = "Sleep", Description = "Have the current thread sleep for the specified amount of milliseconds.")]
     9.5      public class ActionSleep : Action
     9.6      {
     9.7 +        [DataMember]
     9.8          private readonly int iMillisecondsTimeout;
     9.9  
    9.10          public ActionSleep()
    10.1 --- a/SharpLibEar/Event.cs	Sat Jul 23 19:22:56 2016 +0200
    10.2 +++ b/SharpLibEar/Event.cs	Sun Jul 24 13:30:08 2016 +0200
    10.3 @@ -10,10 +10,7 @@
    10.4      [DataContract]
    10.5      public abstract class MEvent
    10.6      {
    10.7 -        [DataMember]
    10.8          public string Name { get; protected set; }
    10.9 -
   10.10 -        [DataMember]
   10.11          public string Description { get; protected set; }
   10.12  
   10.13          public abstract void Trigger();
   10.14 @@ -22,11 +19,12 @@
   10.15      [DataContract]
   10.16      public abstract class Event : MEvent
   10.17      {
   10.18 -        public List<Action> Actions;
   10.19 +        [DataMember]
   10.20 +        public List<Action> Actions = new List<Action>();
   10.21  
   10.22          protected Event()
   10.23          {
   10.24 -           Actions = new List<Action>();
   10.25 +           
   10.26          }
   10.27  
   10.28          public override void Trigger()
    11.1 --- a/SharpLibEar/EventActionManager.cs	Sat Jul 23 19:22:56 2016 +0200
    11.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.3 @@ -1,31 +0,0 @@
    11.4 -//
    11.5 -
    11.6 -
    11.7 -using System;
    11.8 -using System.Collections.Generic;
    11.9 -using System.Linq;
   11.10 -using System.Reflection;
   11.11 -using System.Runtime.Serialization;
   11.12 -
   11.13 -namespace SharpLib.Ear
   11.14 -{
   11.15 -    [DataContract]
   11.16 -    public class EventActionManager
   11.17 -    {
   11.18 -        public static EventActionManager Current = null;
   11.19 -        public IDictionary<string, Type> ActionTypes;
   11.20 -        public readonly IDictionary<string, Event> Events;
   11.21 -
   11.22 -        public EventActionManager()
   11.23 -        {
   11.24 -            ActionTypes = Utils.Reflection.GetConcreteClassesDerivedFromByName<Action>();
   11.25 -            Events = Utils.Reflection.GetConcreteClassesInstanceDerivedFromByName<Event>();
   11.26 -        }
   11.27 -
   11.28 -        public Event GetEvent<T>() where T : class
   11.29 -        {
   11.30 -            return Events[typeof(T).Name];
   11.31 -        }
   11.32 -
   11.33 -    }
   11.34 -}
   11.35 \ No newline at end of file
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/SharpLibEar/ManagerEventAction.cs	Sun Jul 24 13:30:08 2016 +0200
    12.3 @@ -0,0 +1,70 @@
    12.4 +//
    12.5 +
    12.6 +
    12.7 +using System;
    12.8 +using System.Collections.Generic;
    12.9 +using System.ComponentModel;
   12.10 +using System.Linq;
   12.11 +using System.Reflection;
   12.12 +using System.Runtime.Serialization;
   12.13 +using SharpLib.Utils;
   12.14 +
   12.15 +namespace SharpLib.Ear
   12.16 +{
   12.17 +    [TypeConverter(typeof(TypeConverterJson<ManagerEventAction>))]
   12.18 +    [DataContract]
   12.19 +    public class ManagerEventAction
   12.20 +    {
   12.21 +        public static ManagerEventAction Current = null;
   12.22 +        public IDictionary<string, Type> ActionTypes;
   12.23 +        public IDictionary<string, Event> Events;
   12.24 +        [DataMember]
   12.25 +        public Dictionary<string, List<Action>> ActionsByEvents = new Dictionary<string, List<Action>>();
   12.26 +
   12.27 +
   12.28 +        public ManagerEventAction()
   12.29 +        {
   12.30 +            Init();
   12.31 +        }
   12.32 +
   12.33 +        /// <summary>
   12.34 +        /// 
   12.35 +        /// </summary>
   12.36 +        public void Init()
   12.37 +        {
   12.38 +            //Create our list of supported actions
   12.39 +            ActionTypes = Utils.Reflection.GetConcreteClassesDerivedFromByName<Action>();
   12.40 +            //Create our list or support events
   12.41 +            Events = Utils.Reflection.GetConcreteClassesInstanceDerivedFromByName<Event>();
   12.42 +
   12.43 +            if (ActionsByEvents == null)
   12.44 +            {
   12.45 +                
   12.46 +                ActionsByEvents = new Dictionary<string, List<Action>>();
   12.47 +            }
   12.48 +
   12.49 +            //Hook in loaded actions with corresponding events
   12.50 +            foreach (string key in Events.Keys)
   12.51 +            {
   12.52 +                Event e = Events[key];
   12.53 +                if (ActionsByEvents.ContainsKey(key))
   12.54 +                {
   12.55 +                    //We have actions for that event, hook them in then
   12.56 +                    e.Actions = ActionsByEvents[key];
   12.57 +                }
   12.58 +                else
   12.59 +                {
   12.60 +                    //We do not have actions for that event yet, create empty action list
   12.61 +                    e.Actions = new List<Action>();
   12.62 +                    ActionsByEvents[key] = e.Actions;
   12.63 +                }
   12.64 +            }
   12.65 +        }
   12.66 +
   12.67 +        public Event GetEvent<T>() where T : class
   12.68 +        {
   12.69 +            return Events[typeof(T).Name];
   12.70 +        }
   12.71 +
   12.72 +    }
   12.73 +}
   12.74 \ No newline at end of file
    13.1 --- a/SharpLibEar/SharpLibEar.csproj	Sat Jul 23 19:22:56 2016 +0200
    13.2 +++ b/SharpLibEar/SharpLibEar.csproj	Sun Jul 24 13:30:08 2016 +0200
    13.3 @@ -7,7 +7,7 @@
    13.4      <ProjectGuid>{84A9ED37-E6EA-4CBD-B995-B713F46EAAB0}</ProjectGuid>
    13.5      <OutputType>Library</OutputType>
    13.6      <AppDesignerFolder>Properties</AppDesignerFolder>
    13.7 -    <RootNamespace>SharpLibEar</RootNamespace>
    13.8 +    <RootNamespace>SharpLib.Ear</RootNamespace>
    13.9      <AssemblyName>SharpLibEar</AssemblyName>
   13.10      <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
   13.11      <FileAlignment>512</FileAlignment>
   13.12 @@ -49,7 +49,7 @@
   13.13      <Compile Include="Event.cs" />
   13.14      <Compile Include="EventMonitorPowerOff.cs" />
   13.15      <Compile Include="EventMonitorPowerOn.cs" />
   13.16 -    <Compile Include="EventActionManager.cs" />
   13.17 +    <Compile Include="ManagerEventAction.cs" />
   13.18      <Compile Include="Properties\AssemblyInfo.cs" />
   13.19    </ItemGroup>
   13.20    <ItemGroup>
    14.1 --- a/SharpLibUtils/Reflection.cs	Sat Jul 23 19:22:56 2016 +0200
    14.2 +++ b/SharpLibUtils/Reflection.cs	Sun Jul 24 13:30:08 2016 +0200
    14.3 @@ -113,6 +113,21 @@
    14.4              return null;
    14.5          }
    14.6  
    14.7 +        /// <summary>
    14.8 +        /// 
    14.9 +        /// </summary>
   14.10 +        /// <param name="baseType"></param>
   14.11 +        /// <param name="assembly"></param>
   14.12 +        /// <returns></returns>
   14.13 +        public static IEnumerable<Type> GetDerivedTypes<T>() where T: class
   14.14 +        {            
   14.15 +            var types = from t in Assembly.GetAssembly(typeof(T)).GetTypes()
   14.16 +                        where t.IsSubclassOf(typeof(T))
   14.17 +                        select t;
   14.18 +
   14.19 +            return types;
   14.20 +        }
   14.21 +
   14.22      }
   14.23  
   14.24  }
    15.1 --- a/SharpLibUtils/SharpLibUtils.csproj	Sat Jul 23 19:22:56 2016 +0200
    15.2 +++ b/SharpLibUtils/SharpLibUtils.csproj	Sun Jul 24 13:30:08 2016 +0200
    15.3 @@ -7,7 +7,7 @@
    15.4      <ProjectGuid>{AE897704-461D-4018-8336-2517988BF7AD}</ProjectGuid>
    15.5      <OutputType>Library</OutputType>
    15.6      <AppDesignerFolder>Properties</AppDesignerFolder>
    15.7 -    <RootNamespace>SharpLibUtils</RootNamespace>
    15.8 +    <RootNamespace>SharpLib.Utils</RootNamespace>
    15.9      <AssemblyName>SharpLibUtils</AssemblyName>
   15.10      <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
   15.11      <FileAlignment>512</FileAlignment>
   15.12 @@ -32,6 +32,7 @@
   15.13    <ItemGroup>
   15.14      <Reference Include="System" />
   15.15      <Reference Include="System.Core" />
   15.16 +    <Reference Include="System.Runtime.Serialization" />
   15.17      <Reference Include="System.Xml.Linq" />
   15.18      <Reference Include="System.Data.DataSetExtensions" />
   15.19      <Reference Include="Microsoft.CSharp" />
   15.20 @@ -42,6 +43,7 @@
   15.21    <ItemGroup>
   15.22      <Compile Include="Properties\AssemblyInfo.cs" />
   15.23      <Compile Include="Reflection.cs" />
   15.24 +    <Compile Include="TypeConverterJson.cs" />
   15.25    </ItemGroup>
   15.26    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   15.27    <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/SharpLibUtils/TypeConverterJson.cs	Sun Jul 24 13:30:08 2016 +0200
    16.3 @@ -0,0 +1,92 @@
    16.4 +using System;
    16.5 +using System.Collections.Generic;
    16.6 +using System.ComponentModel;
    16.7 +using System.IO;
    16.8 +using System.Linq;
    16.9 +using System.Text;
   16.10 +using System.Threading.Tasks;
   16.11 +using System.Runtime.Serialization;
   16.12 +using System.Runtime.Serialization.Json;
   16.13 +using System.Globalization;
   16.14 +
   16.15 +namespace SharpLib.Utils
   16.16 +{
   16.17 +    /// <summary>
   16.18 +    /// Allow serialization into JSON.
   16.19 +    /// Most useful to be able to save complex settings for instance.
   16.20 +    /// Usage:
   16.21 +    /// ...
   16.22 +    /// [TypeConverter(typeof(TypeConverterJson<PersistantObject>))]
   16.23 +    /// [DataContract]
   16.24 +    /// public class PersistantObject
   16.25 +    /// ...
   16.26 +    /// </summary>
   16.27 +    /// <typeparam name="T"></typeparam>
   16.28 +    public class TypeConverterJson<T> : TypeConverter where T : class
   16.29 +    {
   16.30 +        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
   16.31 +        {
   16.32 +            if (sourceType == typeof(string))
   16.33 +                return true;
   16.34 +            else
   16.35 +                return base.CanConvertFrom(context, sourceType);
   16.36 +        }
   16.37 +
   16.38 +        /// <summary>
   16.39 +        /// 
   16.40 +        /// </summary>
   16.41 +        /// <param name="context"></param>
   16.42 +        /// <param name="culture"></param>
   16.43 +        /// <param name="value"></param>
   16.44 +        /// <returns></returns>
   16.45 +        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
   16.46 +        {
   16.47 +            string stringValue = value as string;
   16.48 +            if (stringValue != null)
   16.49 +            {
   16.50 +                //Load object form JSON string
   16.51 +                byte[] byteArray = Encoding.UTF8.GetBytes(stringValue);
   16.52 +                MemoryStream stream = new MemoryStream(byteArray);
   16.53 +                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T), new DataContractJsonSerializerSettings()
   16.54 +                {
   16.55 +                    UseSimpleDictionaryFormat = true
   16.56 +                });
   16.57 +                T settings = (T)ser.ReadObject(stream);
   16.58 +                return settings;
   16.59 +            }
   16.60 +            else
   16.61 +                return base.ConvertFrom(context, culture, value);
   16.62 +        }
   16.63 +
   16.64 +        /// <summary>
   16.65 +        /// 
   16.66 +        /// </summary>
   16.67 +        /// <param name="context"></param>
   16.68 +        /// <param name="culture"></param>
   16.69 +        /// <param name="value"></param>
   16.70 +        /// <param name="destinationType"></param>
   16.71 +        /// <returns></returns>
   16.72 +        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
   16.73 +        {
   16.74 +            if (destinationType == typeof(string))
   16.75 +            {
   16.76 +                //Save settings into JSON string
   16.77 +                MemoryStream stream = new MemoryStream();
   16.78 +                DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T), new DataContractJsonSerializerSettings()
   16.79 +                {
   16.80 +                    UseSimpleDictionaryFormat = true
   16.81 +                });
   16.82 +                ser.WriteObject(stream, value);
   16.83 +                // convert stream to string
   16.84 +                stream.Position = 0;
   16.85 +                StreamReader reader = new StreamReader(stream);
   16.86 +                string text = reader.ReadToEnd();
   16.87 +                return text;
   16.88 +            }
   16.89 +            else
   16.90 +            {
   16.91 +                return base.ConvertTo(context,culture,value,destinationType);
   16.92 +            }
   16.93 +        }
   16.94 +    }
   16.95 +}
   16.96 \ No newline at end of file