Click here to Skip to main content
11,480,148 members (63,113 online)
Click here to Skip to main content
Add your own
alternative version

Magic Library Docking Manager Designer

, 16 May 2013 CPOL 293.1K 17.5K 154
Provides docking support without writing one line of code.
dockingmanagerextenderhelp.zip
DockingManagerExtender.chm
dockingmanagerextender_bin.zip
DockingManagerExtenderBin
DockingManagerExtender.dll
DockingManagerExtenderDemo.exe
DockingManagerExtenderDemo.exe.manifest
MagicLibrary.DLL
dockingmanagerextender_demo.zip
DockingManagerExtenderDemo
App.ico
bin
Debug
DockingManagerExtenderDemo.exe.manifest
Release
DockingManagerExtenderDemo.exe.manifest
DockingManagerExtender-Demo.csproj.user
DockingManagerExtenderSource
DockingManagerExtender.csproj.user
dockingmanagerextender_src.zip
DockingManagerExtender.csproj.user
using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using Crownwood.Magic.Docking;
using System.IO.IsolatedStorage;
using System.IO;

/*
 * Copyright � 2003 by Christoph Richner. All rights are reserved. If you like this 
  code then feel free to go ahead and use it. The only thing I ask is that 
  you don't remove or alter my copyright notice. Your use of this software 
  is entirely at your own risk. I make no claims or warrantees about the 
  reliability or fitness of this code for any particular purpose. If you 
  make changes or additions to this code please mark your code as being 
  yours. If you have questions or comments then please contact me at: 
  microweb@bluewin.ch
  */

namespace DockingManagerExtender
{	
	/// <summary>
	/// DockingManagerExtender enhances Crownwood.Magic.Docking.DockingManager for design time.
	/// 
	/// It extends the controls on your form with properties, which defines the docking behaviour at run time.
	/// </summary>
	[ProvideProperty("ADockingEnable", typeof(Control))]
	[ProvideProperty("DockingStyle", typeof(Control))]
	[ProvideProperty("TabbedMode", typeof(Control))]
	[ProvideProperty("CloseButton", typeof(Control))]
	[ProvideProperty("CloseOnHide", typeof(Control))]
	[ProvideProperty("Icon", typeof(Control))]
	[ProvideProperty("Title", typeof(Control))]
	[ProvideProperty("FullTitle", typeof(Control))]
	[DefaultProperty("DockingManager")]
	[Description("DockingManagerExtender enhances Crownwood.Magic.Docking.DockingManager for design time.")]
	[System.Drawing.ToolboxBitmap(typeof(StatusBar))]
	public class DockingManagerExtender : Component, System.ComponentModel.IExtenderProvider
	{
		#region members
		/// <summary>Docking Manager which handles docking contents.</summary>
		protected Crownwood.Magic.Docking.DockingManager dockingManager;
		/// <summary>List that contains the docked content data for each control that is docked enabled.</summary>
		protected Hashtable dockContents = new Hashtable();		
		/// <summary>Indicates if auto persistent feature is enabled</summary>
		protected bool autoPersistent = false;
		/// <summary>Distinct Flag, cause the attach process must run only once.</summary>
		protected bool attachedControls;
		/// <summary>Needed by the VS Designer</summary>
		private System.ComponentModel.IContainer components;
		/// <summary>VisualStyle used to draw content</summary>
		protected Crownwood.Magic.Common.VisualStyle visualStyle;
		/// <summary>The object to which the docking manager instance is attached</summary>
		protected ContainerControl containerControl;
		/// <summary>Flag used to disable save on closed event.</summary>
		protected bool resetIsolatedStoreage;
		/// <summary>Used to supress ParentChanged event calls for non form container controls</summary>
		private bool initUserControlEvents_= false;
		#endregion

		#region constructors
		public DockingManagerExtender(System.ComponentModel.IContainer container)
		{
			/// <summary>
			/// Required for Windows.Forms Class Composition Designer support
			/// </summary>
			container.Add(this);
			CommonConstructor();
		}

		public DockingManagerExtender()
		{
			CommonConstructor();
			
		}
		/// <summary>
		/// Used for common init's.
		/// </summary>
		/// <param name="containerControl">ContainerControl which Controls should be extended by this provider</param>
		private void CommonConstructor()
		{
			InitializeComponent();
			
		}
		#endregion

		#region public interface			
		// DockingManager Control Extender
		/// <summary>
		/// Sets the dock style for the control.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="dockState"></param>
		public void SetDockingStyle(Control control,  DockStyle dockState)
		{	
			DockingContent c = null;
			c = GetDockContent(control);
			if (c!=null)
			{
				c.DockStyle= dockState;
			}			
		}
		/// <summary>
		/// Gets the dock style for the control.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Dock style of the control")]
		public DockStyle GetDockingStyle(Control control)
		{
			DockingContent c = null;
			c = GetDockContent(control);
			if (c!=null)
			{
				return c.DockStyle;
			}		
			return  DockStyle.Left;			
		}
		/// <summary>
		/// Enables and disabled the docking for the control.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="enable"></param>
		public void SetADockingEnable(Control control, bool enable)
		{
			DockingContent content = null;
			//Crownwood.Magic.Docking.Content content = null;
			//
			if (enable)
			{				
				content = new DockingContent(this.dockingManager);
				//
				if(control.Text!="")
				{
					content.Title = control.Text;
					content.FullTitle = control.Text;
				} 
				else
				{
					content.Title = control.Name;
					content.FullTitle = control.Name;
				}
				//
				if (dockContents.Contains(control))
				{
					dockContents[control] =  content;
				}
				else
				{
					dockContents.Add(control, content);
				}
			}
			else
			{
				if (dockContents.Contains(control))
				{					
					dockContents.Remove(control);
				}
			}
		}
		/// <summary>
		/// Gets if control is in dock mode.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Enables dock support for this control.")]
		public bool GetADockingEnable(Control control)
		{
			return dockContents[control] != null;
		}
		/// <summary>
		/// Sets the mode for tabbed docking.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="value"></param>
		public void SetTabbedMode(Control control, bool value)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.TabbedMode = value;
			}
		}
		/// <summary>
		/// Gets the mode for tabbed docking.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Enables tabbed docking for this control.")]
		public bool GetTabbedMode(Control control)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.TabbedMode;
			}
			return true;
		}	
		/// <summary>
		/// Enable and disables the close button of the docking window.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="enable"></param>
		public void SetCloseButton(Control control, bool enable)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.CloseButton = enable;
			}
		}
		/// <summary>
		/// Gets the enable and disable state of the close button for this docking window.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("The enable and disable state of the close button for this docking window.")]
		public bool GetCloseButton(Control control)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.CloseButton;
			}
			return false;

		}		
		/// <summary>
		/// Sets the text displayed in tabbed/hide mode.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="title"></param>
		public void SetTitle(Control control, string title)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.Title= title;				
			}
		}
		/// <summary>
		/// Gets the text displayed in tabbed/hide mode.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Text displayed in tabbed/hide mode.")]
		public string GetTitle(Control control)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.Title;
			}
			return control.Name;

		}
		/// <summary>
		/// Sets the text displayed in docking control title. 
		/// </summary>
		/// <param name="control"></param>
		/// <param name="title"></param>
		public void SetFullTitle(Control control, string title)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.FullTitle= title;				
			}
		}
		/// <summary>
		/// Gets the text displayed in docking control title.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Text displayed in docking control title.")]
		public string GetFullTitle(Control control)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.FullTitle;
			}
			return control.Name;

		}
		public void SetCloseOnHide(Control control, bool enable)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.CloseOnHide = enable;
			}
		}
		[Category("Docking Manager"), Description("")]
		public bool GetCloseOnHide(Control control)
		{			
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.CloseOnHide;
			}
			return false;

		}
		/// <summary>
		/// Sets the icon displayed in tabbed/hide mode.
		/// </summary>
		/// <param name="control"></param>
		/// <param name="icon"></param>
		public void SetIcon(Control control, System.Drawing.Icon icon)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				c.Icon = icon;
			}
		}
		/// <summary>
		/// Gets the icon displayed in tabbed/hide mode.
		/// </summary>
		/// <param name="control"></param>
		/// <returns></returns>
		[Category("Docking Manager"), Description("Icon displayed in tabbed/hide mode.")]
		public System.Drawing.Icon GetIcon(Control control)
		{
			DockingContent c = GetDockContent(control);
			if (c!=null)
			{
				return c.Icon;
			}
			return null;
		}		
		// DockingManager Wrapper
		/// <summary>
		/// The wrapped Crownwood.Magic.Docking.DockingManager. Direct access to all properties.
		/// </summary>
		[TypeConverterAttribute(typeof(DockingManagerConverter))]
		[Browsable(true), Category("Docking Manager"),Description("The wrapped Crownwood.Magic.Docking.DockingManager. Direct access to all properties.")]
		public Crownwood.Magic.Docking.DockingManager DockingManager
		{
			get
			{
				return this.dockingManager;
			}
		}
		/// <summary>
		/// Gets or sets the VisualStyle which is used to draw content.
		/// </summary>
		[Browsable(true), Category("Docking Manager"),Description("Style used to draw content.")]
		public Crownwood.Magic.Common.VisualStyle VisualStyle
		{
			get
			{
				return visualStyle;
			}
			set
			{
				visualStyle = value;
			}
		}
		/// <summary>
		/// Gets or sets the object to which the docking manager instance is attached
		/// </summary>
		[Browsable(true), Category("Docking Manager"),Description("The object to which the docking manager instance is attached.")]
		public ContainerControl ContainerControl
		{
			get
			{
				return containerControl;
			}
			set
			{
				containerControl = value;
				//
				System.Diagnostics.Debug.Assert(value!=null,"ContainerControl cannot be null!");
				dockingManager = new Crownwood.Magic.Docking.DockingManager(containerControl, visualStyle);
				//
				if(containerControl is Form)
				{
					Form f = (Form) containerControl;
					f.Load +=new EventHandler(ContainerOnLoad);
					f.Closed += new EventHandler(ContainerOnClosed);
				} 
				else
				{
					containerControl.ParentChanged+=new EventHandler(containerControl_ParentChanged);			
				}
			}
		}
		/// <summary>
		/// Sets or gets the Control for which the docking windows will not be allowed to dock inside of the specified control.
		/// </summary>
		[Browsable(true), Category("Docking Manager"),Description("Docking windows will not be allowed to dock inside of the specified control.")]
		public Control InnerControl
		{
			get
			{
				return this.dockingManager.InnerControl;
			}
			set
			{
				dockingManager.InnerControl = value;
			}
		}
		/// <summary>
		/// Sets or gets the Control for which docking windows will not be allowed to dock outside of the specified control.
		/// </summary>
		[Browsable(true), Category("Docking Manager"), Description("Docking windows will not be allowed to dock outside of the specified control.")]
		public Control OuterControl
		{
			get
			{
				return this.dockingManager.OuterControl;
			}
			set
			{
				dockingManager.OuterControl = value;
			}
		}
		/// <summary>
		/// Enable or disable the Automatic State Persistence feature. If enabled the customized docking settings made by the user are persistent by User/Domain/WorkingArea
		/// </summary>
		[Browsable(true), Category("Docking Manager"),Description("If enabled the customized docking settings made by the user are persistent.")]
		public bool AutomaticStatePersistence
		{
			get
			{
				return this.autoPersistent;
			}
			set
			{
				this.autoPersistent = value;
			}
		}
		/// <summary>
		/// Gets or sets the flag indicating that the appearance is defined as VisualStyle.Plain and this PlainTabBorder property is defined then a full dumped border is drawn around the docking window content.
		/// </summary>
		[Browsable(true), Category("Docking Manager"),Description("If the appearance is defined as VisualStyle.Plain and this PlainTabBorder property is defined then a full dumped border is drawn around the docking window content.")]
		public bool PlainTabBorder
		{
			get
			{
				return this.dockingManager.PlainTabBorder;
			}
			set
			{
				dockingManager.PlainTabBorder = value;
			}
		}
		/// <summary>
		/// Reset Automatic State Persistence
		/// </summary>
		public void ResetAutoPersistent(bool currentWorkingArea)
		{
			resetIsolatedStoreage = true;
			string[] fileNames = null;
			try
			{
				if (currentWorkingArea)
				{
					fileNames = new String[] { GetIsolatedStorageFileNameWorkingArea};
				}
				else
				{
					fileNames = IsolatedStorageFile.GetUserStoreForDomain().GetFileNames(GetIsolatedStorageFileNameBase+"*");
				}
				foreach(string file in fileNames)
				{
					IsolatedStorageFile.GetUserStoreForDomain().DeleteFile(file);
				}
			}
			catch(System.Exception e)
			{
				resetIsolatedStoreage = false;
				throw e;
			}
			finally
			{
			}
		}
		/// <summary>
		/// Restores the docking configuration.
		/// </summary>
		/// <param name="stream">Valid stream</param>
		public void LoadConfigFromStream(System.IO.Stream stream)
		{			
			dockingManager.LoadConfigFromStream(stream);			
		}
		/// <summary>
		/// Stores the docking configuration.
		/// </summary>
		/// <param name="stream">Valid stream</param>
		public void SaveConfigToStream(System.IO.Stream stream)
		{			
			dockingManager.SaveConfigToStream(stream, System.Text.Encoding.Default);
		}
		#endregion

		#region private implementation
		protected string GetIsolatedStorageFileNameBase
		{
			get
			{
				return dockingManager.Container.Name+"_dock";
			}
		}
		protected string GetIsolatedStorageFileNameWorkingArea
		{
			get
			{
				string name = GetIsolatedStorageFileNameBase+"_"+Screen.PrimaryScreen.WorkingArea.Size.ToString();
				// check lengths of current name
				if (name.Length > 250)
				{
					name = name.Substring(0,250);
				}
				return name;
			}
		}
		/// <summary>
		/// Utility method to get DockingContent via Control.
		/// </summary>
		/// <param name="control">Control for which the dockingContent should be returned.</param>
		/// <returns>DockingContent for the control</returns>
		protected virtual DockingContent GetDockContent(Control control)
		{
			DockingContent c = null;
			//
			if (this.dockContents.Contains(control))
			{
				c = dockContents[control] as DockingContent;
			}
			return c;

		}
		/// <summary>
		/// Handles the dockingContents settings and attach the controls at runtime.
		/// This method handle all the dirty work ,)
		/// </summary>
		protected virtual void AttachControls()
		{			
			if (this.DesignMode) return;
			//
			System.Collections.Hashtable stateCache = new System.Collections.Hashtable();
			//
			if (attachedControls) return;
			//
			foreach(DictionaryEntry entry in dockContents)
			{
				Control c = entry.Key as Control;
				DockingContent content = entry.Value as DockingContent;
				//
				Crownwood.Magic.Docking.State dockStyle= content.DockState;	
				content.Control = c;									
				dockingManager.Contents.Add(content);
				// if there is a existing control in this docking region, try to tabb it or add it to zone
				if (stateCache.ContainsKey(dockStyle))
				{	
					// get window content from existing dockingContent
					Crownwood.Magic.Docking.WindowContent wc = stateCache[dockStyle] as Crownwood.Magic.Docking.WindowContent;
					// if current control would like to dock in tabbed mode, check parent control if this is allowed
					if ((content.TabbedMode) & (((DockingContent)wc.Contents[0]).TabbedMode))
					{
						dockingManager.AddContentToWindowContent(content, wc);
					} 
						// dock control to zone, not tabbed
					else
					{
						dockingManager.AddContentToZone(content,wc.ParentZone,0);
					}
				}
					// first control of docking region, just docking ,)
				else
				{					
					stateCache.Add(dockStyle, dockingManager.AddContentWithState(content, dockStyle) as Crownwood.Magic.Docking.WindowContent);
				}
			}
			//
			attachedControls = true;
		}
		#endregion

		#region events
		/// <summary>
		/// Load event fired by the ContainerControl
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ContainerOnLoad(object sender, EventArgs e)
		{
			this.OnLoad(e);
		}
		/// <summary>
		/// Closed event fired by the ContainerControl
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void ContainerOnClosed(object sender, EventArgs e)
		{
			this.OnClosed(e);
		}
		/// <summary>
		/// Virtual OnLoad Event
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnLoad(EventArgs e)
		{
			AttachControls();
			//
			if (autoPersistent)
			{
				IsolatedStorageFileStream stream  = null;
				// try to load persistent state
				try
				{
					stream = new IsolatedStorageFileStream(GetIsolatedStorageFileNameWorkingArea,FileMode.Open) ;
					this.LoadConfigFromStream(stream);									
				} 
				catch{}
				finally
				{
					// if there was a stream, close it
					if (stream!=null)
					{
						stream.Close();
					}
				}
			}
		}
		/// <summary>
		/// Virtual OnClosed Event
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnClosed(EventArgs e)
		{
			// if auto persistent feature is enabled, and the user not reset the customized data, save it
			if ((autoPersistent) & (!resetIsolatedStoreage))
			{
				IsolatedStorageFileStream stream  = null;
				//
				try
				{
					stream = new IsolatedStorageFileStream(GetIsolatedStorageFileNameWorkingArea,FileMode.Create);
					this.SaveConfigToStream(stream);								
				} 
				catch(System.Exception ex)
				{
					throw ex;
				}
				finally
				{
					// if there was a stream, close it
					if(stream!=null)
					{
						stream.Close();
					}
				}
			}
		}
		
		/// <summary>
		/// Used to attach Closed event if container control is not a form type.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void containerControl_ParentChanged(object sender, EventArgs e)
		{			
			if(initUserControlEvents_) return;
			//
			Form f =  containerControl.FindForm();
			f.Load +=new EventHandler(ContainerOnLoad);
			f.Closed += new EventHandler(ContainerOnClosed);
			initUserControlEvents_ = true;
		}
		#endregion

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{

		}
		#endregion

		#region Implementation of IExtenderProvider
		/// <summary>
		/// This IExtender does not extend the following control types
		/// <list type="bullet">
		/// <item>Form</item>
		/// <item>GroupBox</item>
		/// <item>ProgressBar</item>
		/// <item>Label</item>
		/// <item>TextBox</item>
		/// <item>ButtonBase</item>
		/// <item>StatusBar</item>
		/// <item>ToolBar</item>
		/// </list>
		/// </summary>
		/// <remarks>You cannot dock any control type that is listed here.</remarks>
		/// <param name="extendee">The control instance to check against Extender</param>
		/// <returns></returns>
		public bool CanExtend(object extendee)
		{
			if (extendee is Form) return false;
			if (extendee is GroupBox) return false;
			if (extendee is ProgressBar) return false;
			if (extendee is Label) return false;
			if (extendee is TextBox) return false;
			if (extendee is ButtonBase) return false;
			if (extendee is StatusBar) return false;
			if (extendee is ToolBar) return false;
			//
			return true;
		}
		#endregion
	}
	/// <summary>
	/// Wrappes Crownwood.Magic.Docking.Content and extend it with needed properties.
	/// </summary>
	public class DockingContent : Crownwood.Magic.Docking.Content
	{
		#region members
		/// <summary>Specify if this docking Control permit tabbed Docking</summary>
		private bool tabbedMode;
		/// <summary>Specify DockStyle used for docking</summary>
		private DockStyle dockStyle;		
		#endregion

		#region constructor
		public DockingContent(Crownwood.Magic.Docking.DockingManager dockingManager) : base(dockingManager)
		{
			CommonConstructor();
		}
		public DockingContent(Crownwood.Magic.Docking.DockingManager dockingManager,Control control) : base(dockingManager, control)
		{
			CommonConstructor();
		}
		private void CommonConstructor()
		{
			this.dockStyle = DockStyle.Left;			
		}
		#endregion

		#region public interface
		/// <summary>
		/// Gets the Crownwood.Magic.Docking.State evaluated from System.Windows.Forms.DockStyle.
		/// </summary>
		internal Crownwood.Magic.Docking.State DockState
		{
			get
			{
				switch(this.dockStyle)
				{
					case DockStyle.Left:
						return Crownwood.Magic.Docking.State.DockLeft;
					case DockStyle.Right:
						return Crownwood.Magic.Docking.State.DockRight;
					case DockStyle.Top:
						return Crownwood.Magic.Docking.State.DockTop;
					case DockStyle.Bottom:
						return Crownwood.Magic.Docking.State.DockBottom;
					case DockStyle.Fill:
						return Crownwood.Magic.Docking.State.Floating;
					default:
						return Crownwood.Magic.Docking.State.DockLeft;
				}				
			}			
		}
		/// <summary>
		/// Gets or sets the DockStyle.
		/// </summary>		
		public DockStyle DockStyle
		{
			get
			{
				return this.dockStyle;
			}
			set
			{
				if (value == DockStyle.None)
				{
					// not allowed
					return;
				}
				this.dockStyle = value;
			}
		}
		/// <summary>
		/// Enable or disable the tabbed docking mode.
		/// </summary>
		public bool TabbedMode
		{
			get
			{
				return this.tabbedMode;
			}
			set
			{
				this.tabbedMode = value;
			}
		}	
		#endregion
	}
	/// <summary>
	/// DockingManagerConverter provides a TypeConverter for the Crownwood.Magic.Docking.DockingManager
	/// </summary>
	public class DockingManagerConverter : ExpandableObjectConverter
	{
		public override bool CanConvertTo(ITypeDescriptorContext context,
			System.Type destinationType) 
		{
			if (destinationType == typeof(Crownwood.Magic.Docking.DockingManager))
				return true;

			return base.CanConvertTo(context, destinationType);
		}
	}	
}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Chris Richner
Software Developer (Senior) Zeit AG
Switzerland Switzerland
Biography
  • 1996 - 1998 PC Board PPL, HTML, DHTML, Javascript and ASP
  • 1999 - 2001 coding Centura against Sql Database (SqlBase,MSSQL,Oracle)
  • 2002 - 2004 C# Windows Forms
  • 2005 - 2006 C# ASP.NET, Windows Forms
  • 2006 - 2009 C#, WCF, WF, WPF
  • 2010 - 2012 C#, Dynamics CRM, Sharepoint, Silverlight
  • 2013 - 2013 C#, WCF DS (OData), WF, WPF
  • 2014 - now C#, Azure PaaS, Identity, OWIN, OData, Web Api
Interests
  • family & friends
  • chilaxing ,)
  • coding
Follow on   Twitter   Google+   LinkedIn

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150520.1 | Last Updated 17 May 2013
Article Copyright 2003 by Chris Richner
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid