WPF XML Browser Control

Ever wondered how to get a IE like look and feel of the xml in the default WPF web browser control? If your answer is – “Just navigate the Web Browser to the xml path”; You are right! But if you have to navigate to a in-memory xml? Read on to know and apply IE like styling for xml stored in a string variable.

Idea of writing a custom based xml browser control came in because I had a requirement to edit the xml on fly and validate it against a specified schema. User is allowed to edit only the standard xml(compiled as an embedded resource) that the tool provides and not navigate to any path.

This control helps you:

  1. Load the xml from the string and apply IE like styling
  2. Edit the xml
  3. Validate the xml against the defined schema

Before I go further, here is what you get:

image

The problem with web browser when navigating to a string is that it does not load the style for it. Hence the work around is to transform the xml and navigate to it. To do so you need the Xslt that IE uses. After googling for “xml pretty print”, I finally got one originally written by Jonathan Marsh of Microsoft for IE5 and modified by Steve Muench for conversion to XSLT 1.0 REC.  Copy the xml from here.

And here is the code to transform it:

/// <summary>
        /// Executes when XmlDoc DP is changed, Loads the xml and tranforms it using XSL provided
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        public static void OnXmlDocChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var browserControl = d as XmlBrowserControl;
            if (browserControl == null) return;
            var xmlString = e.NewValue as string;
            
            try
            {

                var xmlDocument = new XmlDocument();

                var xmlDocStyled = new StringBuilder(2500);
                // mark of web – to enable IE to force webpages to run in the security zone of the location the page was saved from
                // http://msdn.microsoft.com/en-us/library/ms537628(v=vs.85).aspx
                xmlDocStyled.Append("<!– saved from url=(0014)about:internet –>");

                var xslt = new XslCompiledTransform();
                //TODO: Do not forget to change the namespace, if you move the xsl sheet to your application
                var xsltFileStream =
                    typeof(XmlBrowserControl).Assembly.GetManifestResourceStream(
                        "WPFXmlBrowser.Controls.XmlBrowser.Resources.xml-pretty-print.xsl");
                if (xsltFileStream != null)
                {
                    //Load the xsltFile
                    var xmlReader = XmlReader.Create(xsltFileStream);
                    xslt.Load(xmlReader);
                    var settings = new XmlWriterSettings();
                    // writer for transformation
                    var writer = XmlWriter.Create(xmlDocStyled, settings);
                    if (xmlString != null) xmlDocument.LoadXml(xmlString);
                    xslt.Transform(xmlDocument, writer);

                }

                browserControl.EditText.Text = xmlString;
                browserControl.WebBrowser.NavigateToString(xmlDocStyled.ToString());
                browserControl.EditButton.Visibility = System.Windows.Visibility.Visible;
                browserControl.CopyClipButton.Visibility = System.Windows.Visibility.Visible;
            }
            catch (Exception ex)
            {
                browserControl.WebBrowser.NavigateToString("Unable to parse xml. Correct the following errors: " + ex.Message);
            }
        }

 

XSLT is provided as an embedded resource and it is loaded from the code. If you are moving the xslt to your project, make sure to change the namespace in the calling code.

image

You can download the code from my share here. This code works on my machine!

Feel free to modify the code, but as usual you don’t get warranty!

/*Nish*/

Hello Windows 8 world–Installation on a Virtual Machine

2009 was the year I wrote a post on Installing Windows 7 on VMware, and 2 years later with the same excitement here I am saying Hello to Windows 8. This time I am not elaborating on the installation but yes will share some interesting posts already on it.

Few approaches:

Installing Windows 8 Developer Preview in a virtual machine. – I did this, it worked for me!

Step by step instructions to install Windows 8 successfully on VMWare Workstation 8

Installing Windows 8 Developer Preview as bootable VHD” – It yields much better performance, this will be my next shot!

Before I decided to install it on the Virtual Box, I gave an attempt on the Windows Virtual PC which came pre-installed with my OS (if Windows XP Mode is enabled). But then the Win 8 version I wanted to install was a 64 bit developer preview and unfortunately Virtual PC does not support 64bit guest OS. You will get this error “This 64-bit application couldn’t load because your PC doesn’t have a 64-bit processor”.

Installation on a VirtualBox was a different experience for me – BSODs and Graphical driver crash. No you may not face this because unlike me; you would never attempt to run a Virtual PC in parallel with a Virtual Box Smile.

One important thing to do before you install is to check, if your processor supports Virtualization and enable it in your BIOS. If not you will get this error “Failed to start virtual machine (name of machine) VT-x is not available” when you start the VM.

If you are using an Intel Processor, check its specification at ark.intel.com, Intel Virtualization technology(VT-X) should be supported.

image

By default these features are disabled, so enable these from your BIOS settings.

Go ahead and complete your installation:

287664_10150801452540713_520785712_20554375_1592634805_o

I must say this before I conclude this post – “Win 8 without a touch monitor on a VM is just a Win 7 with painful experience!” If you are a developer and you want your machine to respond as per your original hardware then do a clean install or use a VHD!.

Some interesting links:

Windows Developer Preview Guide

Metro Style App Examples

WinRT Capabilities

Note: Please read the disclaimer on my page before you get started.

/*Nish*/

Android WIFI Problem – Obtaining Address…

Ever since I changed my broadband modem, I have been facing issues with my HTC Wildfire connecting to my WIFI router. Every time it connects to my WIFI, it gives a message “Obtaining address..” and its stuck with this message for sometime. Having just a fair knowledge on networking, it took me some steps to reach to a solution. And here it is…

For some of you it may work by simply restarting your WIFI or by restarting your Android device. If it doesn’t, read on to find out if your problem is similar to mine.

Before I jump into the solution, it is important that you understand my network and my devices. My internet broadband modem and WIFI router are two different entities – meaning my modem does not support WIFI routing, so I had to have a WIFI router separately.

  1. Modem – Binatone DT815 ADSL2+ router (supplied by Airtel India)
  2. WIFI Router – Netgear WGR614
  3. From here on for better understanding I will use the term “Modem” to represent my broadband device and “WIFI Router” to represent my WIFI device. Since both the devices are capable of DHCP, I had to disable one to avoid conflicts. I wanted the default gateway to be the modem’s, so I enabled DHCP only on my modem and disabled the other. Modem detects the WIFI router as just another device in its network and not as a router.

    My IP addresses are configured like this:

  1. Modem – 192.168.1.1
  2. WIFI Router – 192.168.1.2 (Set from router’s LAN Settings)
  3. Other devices which connect, get IPs assigned by the Modem with default gateway as 192.168.1.1

Whenever I tried connecting my android device to WIFI, it gets stuck at “Obtaining address..”. I knew the problem lies in address resolution, so it was either my device not accepting the IP issued or the modem not recognizing the android.

I logged into Modem’s configuration and checked the LAN Connection pool summary(this setting displays the connected devices and its MAC addresses). To my surprise I found that my android device was issued an IP which was same as my router (192.168.1.2) and thus the conflict.

There were two ways I could resolve this conflict:

  1. Change the WIFI router’s IP (from it’s LAN Settings – by logging into WIFI configuration)
  2. Use a Static IP Address in your android device.
    For some reason point 2 never worked for me; but point 1 did. Hope this helps someone.

Cheers

Have an operation to measure? Use Stopwatch()

Quite often we run into situations where we need to measure the elapsed time of a method/operation, and there are number of ways to do it. The simplest way to do is by using a Stopwatch. This class is available under the namespace System.Diagnostics.

To show you a demo, I have used a simple app which calculates the time taken to load a website on your local machine.

namespace Nish.Stopwatch
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("WebAddress> ");
            Console.WriteLine("Your website took about " + LoadWebsite(Console.ReadLine()).Seconds + " seconds to load on your machine");
            Console.ReadLine();
        }

        /// <summary>
        /// Gets the load time of a website
        /// </summary>
        /// <param name="websitePath">Path in the format: e.g. http://nnish.com </param>
        /// <returns>Time taken</returns>
        private static TimeSpan LoadWebsite(string websitePath)
        {
            System.Diagnostics.Stopwatch stpWatch = new System.Diagnostics.Stopwatch();
            stpWatch.Start();
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(websitePath);

            // execute the request
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            // Read the data in the stream
            StreamReader streamReader = new StreamReader(response.GetResponseStream());
            // s – will have your html content, I am not using this for now
            string s = streamReader.ReadToEnd();
            stpWatch.Stop();
            
            return stpWatch.Elapsed;
        }
    }
}

 

Time took for my website to load:

image

Look at the time Google took:

image

And now this was out of curiosity:

image

Please note: The load time depends on various factors like network speed, server location,  page content etc. So this data should not be treated as accurate. The idea of having this example is to show the usage of Stopwatch and not to determine the speed of the website.

Method Stopwatch.Start() starts the timer, and ticks in parallel until the Stopwatch.Stop() is executed. The start method does not start the elapsed time at 0, if executed again. To set the elapsed time to 0 use either Stopwatch.Restart() or call Stopwatch.Reset() before the next start(). So understand that “A Stopwatch instance calculates and retains the cumulative elapsed time across multiple time intervals, until the instance is reset/restarted.” – MSDN. To start a fresh timer use Stopwatch stopwatch = Stopwatch.StartNew() which is a static method.

This comes very handy when you use this for all your performance monitoring or benchmarking on/the your operations.

Cheers!

Long time since I blogged!

No laziness is not the only reason why I skipped blogging for months together. I was on a complete learning mode, when I say learning its not just the technical stuffs I am talking about. I was involved in various activities of life, which demanded a lot of my personal time. A lot of activities which were completely new to me, and had no clue on how to go about it. I am not completely done with it (that said there is no definite time frame on blogging), but have decided to pull out some of my time. My passion for technology and photography are in my breath and that keeps me alive, but off late I realized it wasn’t enough! probably I need some food to survive. And that is something which I will let you know in years to come!

My transition from an entrepreneur to a full time employee was a tough decision, but have to do that to sustain and to overcome the loses! Am I complaining? No I am lucky enough in doing something what I always wanted to do and that is programming! The point is having bitten by the entrepreneur bug in some time of my life, has not let me sleep peaceful. Regaining those momentum and going forward in that direction is even more riskier until I have some concrete things planned.

Other than the learning of life I had couple of new learning which were technical and they were completely new from my field of work. But it was necessary to keep the momentum on. Oh did I say I have some concrete plans? No not yet!

Sometimes taking a right decision is far more easier than making your decision right!

To restart blogging, I am initiating a simple technical post which is coming up next!

Cheers!

Accessing WPF controls on a non UI Thread

I am sure most of you would have run into this issue before. When you try to access a WPF control on a different thread other than your regular UI thread you get a runtime exception “The calling thread cannot access this object because a different thread owns it.”. To understand why this happens, it is important to know that WPF applications run on two different threads – one for rendering the controls and the other to manage the user interface. The rendering thread runs in the background and the thread which is visible for us to work on is the UI thread. And hence most of the objects are tied to the UI thread and this is known as thread affinity. Thread affinity is handled by the Dispatcher. Each user interface related work item is channeled through the Dispatcher class, that means every work item is queued by the UI thread in an object called Dispatcher. Dispatcher runs the work items on priority basis. Supporting work item prioritization allow WPF to work on a an item for more time and hence more time is consumed on the UI thread. UI thread will have at least one Dispatcher, and each Dispatcher can execute work items in exactly one thread. So it is important to release the work item from the thread as fast as possible so as to increase the UI responsiveness.  To keep the work item small,  I spawned newer threads and executed the discrete blocks of code on these threads. This is exactly where I ran into the exception stated above (when I tried to access the  WPF control).

So here is how I got the exception:

private void myButton_Click(object sender, RoutedEventArgs e)
{
    Thread t = new Thread(new ThreadStart(
        delegate
        {
            //accessing the TextBlock.Text on a different thread – **incorrect**
            myText.Text = "HI";
        }
        ));
    t.Start();
}

 

So how to get rid of this?

Now we know why a background running thread cannot access the UI thread. To get rid of this problem it is pretty simple – “Just ask the UI thread to do it for you”. Yes the background thread can request the UI thread to update the control properties on behalf of it. This is achieved by calling the Invoke or the BeginInvoke method of the DispatcherObject class. This will register the work items to the Dispatcher. Invoke is a synchronous call – that is, it doesn’t return until the UI thread actually finishes executing the delegate. BeginInvoke is asynchronous and returns immediately. So as stated above Dispatcher orders work items by priority and hence you can pass the priority using DispatcherPriority enumerator while registering the work item to Dispatcher. 
So here is the code below which solved my problem:

private void myButton_Click(object sender, RoutedEventArgs e)
{
    Thread t = new Thread(new ThreadStart(
        delegate
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action<TextBlock>(SetValue), myText);
        }
        ));
    t.Start();
}

private static void SetValue(TextBlock txt)
{
    txt.Text = "HI";
}

In the Dispatcher.Invoke() method used above takes three parameters – DispatcherPriority Enum, Delegate to execute the code and the parameter object. I used the Action<T> generic type to pass the control to the method to set its property.

It is suggested to use the setting of the control properties in the UI thread itself, and only move those code like say calculations to another thread. This will provide a better code maintenance.

However in the above example we do not improve the UI responsiveness, as the Invoke() method is called synchronously. Instead use BeginInvoke() method. My intention was to give an insight of the exception – why, and how to deal with it. If you need details on writing better responsive applications refer Shawn Wildermuth’s article

Wow another weekend in research -Cheers!

Animated Gif in WPF using Windows Forms Control

Loading an animated gif into WPF has been a challenge since the version 1 release. WPF does not support loading an animated gifs directly into an declarative <Image> or by code, and hence developers have come out with various workarounds. Some use a raw technique – writing few lines of code which extracts the frames of the GIF and animate them.  One other way to do is using the <MediaElement> FrameworkElement which is in the namespace System.Windows.Controls. <MediaElement> wraps the MediaPlayer class for declarative use and hence it supports both audio and video files. Using MediaElement you can load the animated gif the following way:

<MediaElement Source="file://D:\anim.gif"/>

Remember it is important to use “file://” and an absolute path for loading the gif. So you cannot embed the image to a resource file and now you know one of the limitations of it. Every approach does have advantages and limitations of its own, its important to use the right approach based on the project needs.

Another possible way is by making the working Jack do the trick – Yeah I meant lets go back to Win Forms picture box to do the magic. We know PictureBox seamlessly loaded the animated gifs in Win Form days. Wait a minute did I say lets change the project from WPF to Win Forms? No I didn’t. What I said is lets integrate the PictureBox alone to the WPF project. To use the right word, I should say that we need to host the Windows Forms Control in WPF. To host a Windows Forms Control you need to make use of the class WindowsFormsHost which appears in the System.Windows.Forms.Integration namespace in assembly WindowsFormsIntegration.dll.

Lets get to the code. The first step to do is add a reference to System.Windows.Forms.dll and WindowsFormsIntegration.dll to your WPF based project.

References

Add the following namespaces to your XAML Code.

<Window x:Class="WpfApplication2.Window1"
    xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
    xmlns:winForms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

Now you can host the PictureBox inside the WindowsFormsHost and set its Name.

    <Grid>
        <wfi:WindowsFormsHost>
            <winForms:PictureBox x:Name="pictureBoxLoading">
            </winForms:PictureBox>
        </wfi:WindowsFormsHost>
    </Grid>

In your code behind(Window1.xaml.cs), add this code to the Window_Loaded Event:

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.pictureBoxLoading.Image = System.Drawing.Image.FromFile("anim.gif"); ;
        }

Key points before execution:

  1. Make sure you provide the right path to load the image
  2. You can also load it from a resource file.

Since Windows Forms has several interesting built in controls that WPF lacks, using this technique you can make your favorite Windows Forms control work in WPF.

Cheers!

Error: Not enough storage is available to process this command

Today afternoon I was on a mission to complete a long pending personal project and as part of it I was developing a windows service which extended the support of starting and stopping the service from a console window. After the completion it was time for me to start testing that out and then this weird thing happened. Whenever the system encountered a Console.ReadLine(), it gave me a strange error: “Not enough storage is available to process this command.”  But executing a Console.WriteLine() was not an issue. After playing around with it for a while I figured out the project I had selected was Windows Service and hence it’s output type was Windows Application. Changing the project type to a Console application did the trick. Hopefully this helps someone.

Cheers!

Best blog award and me?

This is really amazing. Blogging was one of the activities I thought I was never good at. My last experience at the tech-ed forced me to write one, and this is truly surprising – Won the best blog award for writing down my experiences at the event. I received a Windows Vista Ultimate licensed copy from Vic at Xperience 2009/ Microsoft Community Tech Days event. This is my first blog entry and what a great way to start – It inspires! Thanks to BDotnet and BITPro panel members. 

Thank you VJ(MSIGeek) for scheduling the prize giving session little earlier than it was planned. It will not be good on my part if I do not mention a special thanks to VJ for having this session clicked for me and for Vic’s patience.

BestBlogBdotnet

WindowsVistaUltimate

Cheers!

Custom Configuration Section in C#

A very familiar way of implementing the frequently changing value in an application is by storing them in a configuration file’s <appSettings> section. When the project is big, storing too many values in application settings is not a suggested approach, as this can lead to confusions and many other integration problems. Many at times we have seen when the code is moved from a development environment to a production environment there is a mismatch in the the configuration or we loose out on some important values. These issues can be eliminated by simply using a custom configuration section. A project constitutes of many modules and each module will have configuration values specific to them. So it will be a good idea to group them to a single section, and every  module’s configuration values will reside in their respective section. This way by just looking at the configuration one can figure out which value relates to what module. It is also suggested to have a common section so that these values can be accessed by all the modules and will reduce duplication of values.

Going forward you will learn about creating custom configuration section, the corresponding value holder class, and properties to access them through out the application. I will make the demo simple to a console application, so that it is easy to understand.

Start a new Console application and add an application configuration file to it. Also reference System.Configuration.dll.

What’s in the Configuration?

  1. <?xml version=1.0 encoding=utf-8 ?>
  2. <configuration>
  3.     <configSections>
  4.         <section name=MyConfiguration type=ConfigurationC.MyConfiguration, ConfigurationC/>
  5.     </configSections>
  6.     <!– Configuration settings for MyConfiguration Starts –>
  7.     <MyConfiguration
  8.             To=support@nnish.com
  9.             From=sales@nnish.com>
  10.         <Messages>
  11.             <Message Name=Email Value=email/>
  12.             <Message Name=Sms Value=sms/>
  13.             <Message Name=Tweet Value=tweet />
  14.         </Messages>
  15.     </MyConfiguration>
  16.     <!– Configuration settings for MyConfiguration Ends –>
  17. </configuration>

Lets break this into bits and pieces. Notice the <configSections> element –this is where you register your custom configuration. To add a custom configuration – add an element <section name=”” type=””/>.

  • name – represents the name of the custom configuration
  • type – used as <namespace.Type>, <AssemblyName> (Type is the corresponding class which inherits ConfigurationSection)

And the <MyConfiguration>element is nothing but the custom configuration section which contains custom values stored.  I will explain multiple ways of storing in the config files and accessing them from the application. In the config, I store some values as the attribute of the main element, the main element has the sub element <Messages> and that in turn has the collection of <Messages> having attributes “Name” and “Value”. This can be easily related to <add> element in the <appSettings>.

What’s in the Code?

Now let us go ahead and build the classes for accessing these values in the application.

Remember these:

  • There should be a class in the application representing each element (including the sub elements) in the configuration file.
  • Class holding the custom Configuration Section should inherit from CustomSection
    • public class MyConfiguration : ConfigurationSection
  • The attributes/elements can be represented as a property which is of type ConfigurationProperty in the parent class.
  • Class representing an element collection should inherit from ConfigurationElementCollection
    • public class MessageCollection : ConfigurationElementCollection
  • Class representing an element should inherit from ConfigurationElement
    • public class MessageElement : ConfigurationElement

Since <Message> is the last child element, write the corresponding class for it first, and then <Messages> which is its parent and it holds the collection of <Messages> and finally the class for <MyConfiguration> which has attributes represented as properties in itself.

Element: <Message> – Class: MessageElement

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     /// <summary>
  5.     /// Class holds the <Message> element
  6.     /// </summary>
  7.     public class MessageElement : ConfigurationElement
  8.     {
  9.         // Holds the Name attribute of the Message
  10.         private static readonly ConfigurationProperty messageName =
  11.             new ConfigurationProperty(“Name”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  12.         // Holds the Value attribute value of Message.
  13.         private static readonly ConfigurationProperty messageValue =
  14.             new ConfigurationProperty(“Value”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  15.         public MessageElement()
  16.         {
  17.             base.Properties.Add(messageName);
  18.             base.Properties.Add(messageValue);
  19.         }
  20.         /// <summary>
  21.         /// Name
  22.         /// </summary>
  23.         [ConfigurationProperty(“Name”, IsRequired = true)]
  24.         public string Name
  25.         {
  26.             get { return (string)this[messageName]; }
  27.         }
  28.         /// <summary>
  29.         /// Value
  30.         /// </summary>
  31.         [ConfigurationProperty(“Value”, IsRequired = true)]
  32.         public string Value
  33.         {
  34.             get { return (string)this[messageValue]; }
  35.         }
  36.     }
  37. }

Explanation:

  • <Message> element has attributes “name” and “value” which are represented as ConfigurationProperty and its initialization takes the following parameters
    • name: The name of the configuration entity.  
    • type: The type of the configuration entity.
    • defaultValue: The default value of the configuration entity.
    • options:  One of the System.Configuration.ConfigurationPropertyOptions enumeration values
  • In the constructor add these properties to the base class Property Collection
  • Expose them as public property

Element: <Messages> – Class: MessageCollection

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     [ConfigurationCollection(typeof(MessageElement), AddItemName = “Message”,
  5.          CollectionType = ConfigurationElementCollectionType.BasicMap)]
  6.     public class MessageCollection : ConfigurationElementCollection
  7.     {
  8.         protected override ConfigurationElement CreateNewElement()
  9.         {
  10.             return new MessageElement();
  11.         }
  12.         protected override object GetElementKey(ConfigurationElement element)
  13.         {
  14.             return ((MessageElement)element).Name;
  15.         }
  16.      
  17.         new public MessageElement this[string name]
  18.         {
  19.             get { return (MessageElement)BaseGet(name); }
  20.         }
  21.     }
  22. }

Explanation:

  • MessageCollection class is inherited from the abstract class ConfigurationElementCollection and two of its abstract methods CreateElement() and GetElementKey() needs to be overridden
  • CreateElement() creates the new instance of the MessageElement
  • GetElementKey() Gets the element key for a Message element (we define Name attribute as the key, so that the value can be retrieved using the name)
  • new public MessageElement this[string name] – add this to retrieve the value with the key name. For e.g: ConfigurationManager.AppSettings[“test”];

 

Element: <MyConfiguration> – Class: MyConfiguration (Putting them all together[ConfigurationSection ])

  1. using System.Configuration;
  2. namespace ConfigurationC
  3. {
  4.     public class MyConfiguration : ConfigurationSection
  5.     {
  6.         private static readonly ConfigurationProperty toAttribute =
  7.              new ConfigurationProperty(“To”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  8.         
  9.         private static readonly ConfigurationProperty fromAttribute =
  10.              new ConfigurationProperty(“From”, typeof(string), string.Empty, ConfigurationPropertyOptions.IsRequired);
  11.         private static readonly ConfigurationProperty messagesElement =
  12.              new ConfigurationProperty(“Messages”, typeof(MessageCollection), null, ConfigurationPropertyOptions.IsRequired);
  13.         public MyConfiguration()
  14.         {
  15.             base.Properties.Add(toAttribute);
  16.             base.Properties.Add(fromAttribute);
  17.             base.Properties.Add(messagesElement);
  18.         }
  19.         /// <summary>
  20.         /// To
  21.         /// </summary>
  22.         [ConfigurationProperty(“To”, IsRequired = true)]
  23.         public string To
  24.         {
  25.             get { return (string)this[toAttribute]; }
  26.         }
  27.         
  28.         /// <summary>
  29.         /// From
  30.         /// </summary>
  31.         [ConfigurationProperty(“From”, IsRequired = true)]
  32.         public string From
  33.         {
  34.             get { return (string)this[fromAttribute]; }
  35.         }
  36.         /// <summary>
  37.         /// Messages Collection
  38.         /// </summary>
  39.         [ConfigurationProperty(“Messages”, IsRequired = true)]
  40.         public MessageCollection Messages
  41.         {
  42.             get { return (MessageCollection)this[messagesElement]; }
  43.         }
  44.     }
  45. }

Explanation:

  • Add all the Attributes and Elements as the ConfigurationProperty of corresponding type.

And the Program.cs

  1. using System;
  2. using System.Configuration;
  3. namespace ConfigurationC
  4. {
  5.    public class Program
  6.     {
  7.         public static MyConfiguration MyConfig;
  8.         static void Main(string[] args)
  9.         {
  10.             MyConfig = GetConfiguration();
  11.             Console.WriteLine(“This program comes with no warranty!”);
  12.             Console.WriteLine(“Values found in the configuration”);
  13.             Console.WriteLine(“To: “ + MyConfig.To);
  14.             Console.WriteLine(“From: “ + MyConfig.From);
  15.             Console.WriteLine(“Message Email: “ + MyConfig.Messages[“Email”].Value);
  16.             Console.WriteLine(“Message Sme: “ + MyConfig.Messages[“Sms”].Value);
  17.             Console.WriteLine(“Message Tweet: “ + MyConfig.Messages[“Tweet”].Value);
  18.             Console.ReadLine();
  19.         }
  20.         private static MyConfiguration GetConfiguration()
  21.         {
  22.             return (MyConfiguration)ConfigurationManager.GetSection(“MyConfiguration”);
  23.         }
  24.     }
  25. }

Above code snippet is self explanatory.

I hope I was able to walk you through a step by step process of a developing hello world Custom Configuration section.

Download the code!

Cheers!