<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3410915886830453368</id><updated>2011-11-27T18:50:05.382-05:00</updated><category term='RIA Services'/><category term='DataGrid'/><category term='data export'/><category term='Data visualization'/><category term='Context Menu'/><category term='Mouse Gestures'/><category term='CSV Generation'/><category term='Usercontrol'/><category term='Silverlight'/><category term='Pattern'/><title type='text'>Code Forward</title><subtitle type='html'>Blogs and other online resources have been of great help to me. So, I figure it is time to pay it forward. In code. I will blog about whatever I stumble across during software development, that I think may be of some use to fellow coders. I work mostly in Microsoft technology.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-8976631120043664074</id><published>2009-11-06T14:29:00.000-05:00</published><updated>2009-11-06T14:29:19.145-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RIA Services'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Shared classes in RIA Services</title><content type='html'>I have been playing around with RIA .NET Services. It seems like a very powerful and unified way to work with data. I have only skimmed the surface of it's capabilities, but I found a few curious things I want to see if others are experiencing too.&lt;br /&gt;&lt;br /&gt;A very cool feature of RIA Service is the concept of shared classes. Imagine you want to create a derived property on a data class (in my case, FullName = FirstName + " " LastName). You write that as a partial class, in a file named *.shared.cs (or *.shared.vb if you are using VB). I like how they have used convention over config for a lot of this in RIA Services. My code looked like&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Employee&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FullName&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;            get{&lt;span class="kwrd"&gt;return&lt;/span&gt; FirstName + &lt;span class="str"&gt;" "&lt;/span&gt; + LastName};&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;This worked fine, and my client displayed FullName without any problem. But, I couldn't edit the data anymore. Once I added a setter to the property, everything was good again.&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Employee&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; FullName&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; FirstName + &lt;span class="str"&gt;" "&lt;/span&gt; + LastName };&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;            set { }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;I guess this is because of how the code is generated on the client side, but haven't stepped through to see why exactly this is happening.&lt;br /&gt;&lt;br /&gt;Another thing I have found is that, when Visual Studio generates the proxy/shared code on the client side, the folder and the files are not automatically included in the project. You have to include the Generated_Code folder and it's files manually.&lt;br /&gt;&lt;br /&gt;Overall, I find the metadata-based validation and edit/batch edit/offline capabilities of RIA .NET services very exciting. Now, in the next version, if it starts generating validation metadata from constraints in the database, that will be uber-cool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-8976631120043664074?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/8976631120043664074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/11/shared-classes-in-ria-services.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/8976631120043664074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/8976631120043664074'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/11/shared-classes-in-ria-services.html' title='Shared classes in RIA Services'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-2225232736617092413</id><published>2009-10-28T18:59:00.001-04:00</published><updated>2009-10-28T19:03:44.248-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='data export'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='CSV Generation'/><title type='text'>Exporting data from Silverlight</title><content type='html'>We can put a lot of time and effort figuring out what our customers want to do with data, and tailoring the UI towards making those tasks pleasant, efficient, and seamless. But there comes a point where the user wants to put the data into a spreadsheet and analyze/share from there. Or, they may just want to print the data.&lt;br /&gt;&lt;br /&gt;Silverlight datagrids are not very helpful when it comes to exporting data. And, printer support for silverlight is non-existent. We got around this limitation by using a WebHandler that receives the export request, and returns a csv file.&lt;br /&gt;&lt;br /&gt;The export request contains all the information about the service method and parameters that populated data in the datagrid.&lt;br /&gt;&lt;br /&gt;The ExportRequestData is serialized by the silverlight client, passed to the handler on the query string, and deserialized by the handler. So, both the web and silverlight projects needs to understand this class. You can do this by creating a separate dll and referencing it in both the projects, but we were in tactical mode at the time and put a file in one project and just made a link to it in the other. Just make sure you don't introduce any code in it that Silverlight doesn't understand (since SL is a subset of full-fledged .net).&lt;br /&gt;&lt;br /&gt;Here is the code for ExportRequestData class:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;//This file is owned by the web project and linked to the silveright project.&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;//It is safer to edit this file within the context of silverlight&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;//because then the intellisense only shows the methods and properties you can use within Silverlight&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;//framework. If edited within web context, intellisense will show stuff you can do within&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="rem"&gt;//full-fledged .NET, and if you end up using stuff outside of silverlight framework, the silverlight&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="rem"&gt;//app will not build.&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ExportRequestData&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; _Parameters;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; Parameters&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        get&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (_Parameters == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                _Parameters = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; _Parameters;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        set { _Parameters = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Method { get; set; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key, &lt;span class="kwrd"&gt;object&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;value&lt;/span&gt; != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;            Parameters.Add(key, &lt;span class="kwrd"&gt;value&lt;/span&gt;.ToString());&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;    &lt;span class="rem"&gt;//expected format : method_name;param1=value1|param2=value2|param3=value3&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Serialize()&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;        StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;        sb.Append(Method.ToString()).Append(&lt;span class="str"&gt;";"&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (KeyValuePair&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; kv &lt;span class="kwrd"&gt;in&lt;/span&gt; Parameters)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;            sb.Append(kv.Key).Append(&lt;span class="str"&gt;"="&lt;/span&gt;).Append(kv.Value).Append(&lt;span class="str"&gt;"|"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; ret = sb.ToString();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; ret.Remove(ret.Length - 1);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;    &lt;span class="rem"&gt;//expected format : method_name;param1=value1|param2=value2|param3=value3&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; ExportRequestData Deserialize(&lt;span class="kwrd"&gt;string&lt;/span&gt; data)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;        ExportRequestData d = &lt;span class="kwrd"&gt;new&lt;/span&gt; ExportRequestData();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;        d.Parameters = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt;[] splitData = data.Split(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] { &lt;span class="str"&gt;';'&lt;/span&gt; });&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;        d.SetMethod(splitData[0]);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (splitData.Length &amp;gt; 1)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] p = splitData[1].Split(&lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] { &lt;span class="str"&gt;'|'&lt;/span&gt; });&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;            &lt;span class="kwrd"&gt;char&lt;/span&gt;[] paramSplitter = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;char&lt;/span&gt;[] { &lt;span class="str"&gt;'='&lt;/span&gt; };&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; s &lt;span class="kwrd"&gt;in&lt;/span&gt; p)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;                &lt;span class="kwrd"&gt;string&lt;/span&gt;[] param = s.Split(paramSplitter);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (param.Length &amp;gt; 1)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;                    d.Parameters.Add(param[0], param[1]);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; d;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;       &lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (Parameters.ContainsKey(key))&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Parameters[key];&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  75:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt;? GetBoolParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  76:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  78:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  79:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  80:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToBoolean(ret);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  81:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  82:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  83:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  84:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  85:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  86:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;short&lt;/span&gt;? GetShortParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  87:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  88:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  89:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  90:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  91:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToInt16(ret);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  92:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  93:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  94:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  95:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  96:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;byte&lt;/span&gt;? GetByteParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  97:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  98:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  99:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 100:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 101:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToByte(ret);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 102:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 103:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 104:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 105:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 106:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;? GetIntParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 107:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 108:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 109:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 110:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 111:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToInt32(ret);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 112:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 113:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 114:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 115:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 116:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; DateTime? GetDateTimeParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 117:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 118:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 119:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 120:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 121:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToDateTime(ret);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 122:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 123:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 124:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 125:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 126:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt;? GetDoubleParam(&lt;span class="kwrd"&gt;string&lt;/span&gt; key)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 127:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 128:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt; ret = GetParam(key);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 129:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 130:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 131:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; Convert.ToDouble(ret);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 132:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 133:  &lt;/span&gt;        &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt; 134:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt; 135:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The client tacks on the serialized ExportRequestData object (handler of Click event of the "Export" HyperlinkButton):&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;                var rd = &lt;span class="kwrd"&gt;new&lt;/span&gt; ExportRequestData { Method = &lt;span class="str"&gt;"MyMethod"&lt;/span&gt; };&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;                rd.AddParam(&lt;span class="str"&gt;"FirstParam"&lt;/span&gt;, param1Value);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;                rd.AddParam(&lt;span class="str"&gt;"SecondParam"&lt;/span&gt;, param2Value);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;                rd.AddParam(&lt;span class="str"&gt;"ThirdParam"&lt;/span&gt;, param3Value);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                MyHyperLinkButton.NavigateUri = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"http://mydomain.com/handler.ashx?data="&lt;/span&gt; HttpUtility.UrlEncode(data.Serialize()));&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;You will probably add authentication and other things to this. The caveat here is that you have to match the method and parameter names exactly to the ones in the web service. The order in which they are added, doesn't matter. Now, we are all set with the client. Onwards to the server code.&lt;br /&gt;&lt;br /&gt;The handler takes the request, deserializes it, calls the method with the parameters described in the request, and outputs the results as a csv.&lt;br /&gt;&lt;br /&gt;So the ProcessRequest in the handler looks like this:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="rem"&gt;//Re-construct the ExportRequestData object:&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;ExportRequestData rd = ExportRequestData.Deserialize(context.Request.QueryString[&lt;span class="str"&gt;"data"&lt;/span&gt;].ToString());&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;ExportResults(rd);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;ExportResults method uses reflection call the right method and get results. It casts the results to Object[], which then gets passed to a generic CsvExporter.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ExportResults(ExportRequestData rd)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        MyWebService svc = &lt;span class="kwrd"&gt;new&lt;/span&gt; MyWebService();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        MethodInfo mi = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(MyWebService).GetMethod(rd.Method);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        ParameterInfo[] pis = mi.GetParameters();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        &lt;span class="kwrd"&gt;object&lt;/span&gt;[] ps = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[pis.Length];&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; pis.Length; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                ps[i] = rd.GetParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(DateTime?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                ps[i] = rd.GetDateTimeParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;short&lt;/span&gt;?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                ps[i] = rd.GetShortParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;int&lt;/span&gt;?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                ps[i] = rd.GetIntParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;double&lt;/span&gt;?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;                ps[i] = rd.GetDoubleParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;byte&lt;/span&gt;?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;                ps[i] = rd.GetByteParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (pis[i].ParameterType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;bool&lt;/span&gt;?))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;                ps[i] = rd.GetBoolParam(pis[i].Name);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;        CsvExporter.Export((Object[])mi.Invoke(svc, ps), rd.Method, &lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The CsvExporter examines the actual type of the object in Object[] passed to it (it assumes that all the objects in the array are of the same type). It uses this info to create the header. In addition, if a property of the object is numeric, it adds a "=" in front of the value so it shows up correctly when displayed in Excel. Here is the code for the Exporter:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Regex NumericRegex;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;static&lt;/span&gt; CsvExporter()&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        NumericRegex = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^\d+$"&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;   &lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Export(Object[] source, &lt;span class="kwrd"&gt;string&lt;/span&gt; fileName)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;        HttpResponse response = HttpContext.Current.Response;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;        response.ContentType = &lt;span class="str"&gt;"text/plain"&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        response.AddHeader(&lt;span class="str"&gt;"Content-Disposition"&lt;/span&gt;, &lt;span class="str"&gt;"attachment;filename=\""&lt;/span&gt; + fileName + &lt;span class="str"&gt;"_"&lt;/span&gt; + DateTime.Now.ToString(&lt;span class="str"&gt;"MMddyyHHmmss"&lt;/span&gt;) + &lt;span class="str"&gt;".csv\""&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        response.Clear();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;        StreamWriter csvDoc = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(response.OutputStream);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (source.Length &amp;gt; 0)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;            PropertyInfo[] props = source[0].GetType().GetProperties();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PropertyInfo prop &lt;span class="kwrd"&gt;in&lt;/span&gt; props)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;                csvDoc.Write(&lt;span class="str"&gt;"\""&lt;/span&gt; + prop.Name.Replace(&lt;span class="str"&gt;"_"&lt;/span&gt;, &lt;span class="str"&gt;" "&lt;/span&gt;) + &lt;span class="str"&gt;"\","&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            csvDoc.WriteLine();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; o &lt;span class="kwrd"&gt;in&lt;/span&gt; source)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PropertyInfo prop &lt;span class="kwrd"&gt;in&lt;/span&gt; props)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;object&lt;/span&gt; v = prop.GetValue(o, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (v != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; (prop.PropertyType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;)) &amp;amp;&amp;amp; NumericRegex.IsMatch(v.ToString()))&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;                    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;                        csvDoc.Write(&lt;span class="str"&gt;"="&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;                    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;                    csvDoc.Write(&lt;span class="str"&gt;"\""&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;                    csvDoc.Write(v);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;                    csvDoc.Write(&lt;span class="str"&gt;"\","&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;                csvDoc.WriteLine();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;        csvDoc.Flush();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;        csvDoc.Close();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;        response.End();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;With this, we were able to implement a generic and reusable system to export data from our Silverlight UIs. I hope the info is helpful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-2225232736617092413?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/2225232736617092413/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/10/exporting-data-from-silverlight.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/2225232736617092413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/2225232736617092413'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/10/exporting-data-from-silverlight.html' title='Exporting data from Silverlight'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-5411312244275114812</id><published>2009-10-22T22:20:00.002-04:00</published><updated>2009-10-23T09:53:47.978-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Silverlight Datagrid Layout Manager: The code</title><content type='html'>In the previous post I talked about a datagrid layout manager we used in our product. There is a demo and a link to code in that &lt;a href="http://codeforward.blogspot.com/2009/10/silverlight-datagrid-letting-users.html"&gt;post&lt;/a&gt; as well. By the way, one thing I forgot to mention in that post: A user can drag/drop to rearrange the columns, and then if she opens "manage layout" and hit "save", the rearranged layout will persist to a future session. An added bonus.&lt;br /&gt;&lt;br /&gt;Here is the the full demo, including user control and consuming code: &lt;a href="http://www.filefactory.com/file/a06da5d/n/ContextMenuDemo_zip" target="New"&gt;http://www.filefactory.com/file/a06da5d/n/ContextMenuDemo_zip&lt;br /&gt;&lt;/a&gt;&lt;br /&gt;I will try to break down the code in this post.&lt;br /&gt;&lt;br /&gt;The column information in the datagrid is massaged into an ObservableCollection&lt;ordereditem&gt; object. The definition for OrderedItem:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; OrderedItem : INotifyPropertyChanged&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;event&lt;/span&gt; System.ComponentModel.PropertyChangedEventHandler PropertyChanged;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _Name;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Name; }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;            set&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                _Name = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                    PropertyChanged(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"Name"&lt;/span&gt;));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; DisplayName { get; set; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _Position;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Position&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Position; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            set&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;                _Position = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;                    PropertyChanged(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"Position"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _IsFrozen;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFrozen&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _IsFrozen; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;            set&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;                _IsFrozen = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt;                    PropertyChanged(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"IsFrozen"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _IsIncluded;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsIncluded&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _IsIncluded; }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;            set&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt;                _IsIncluded = &lt;span class="kwrd"&gt;value&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (PropertyChanged != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;                    PropertyChanged(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventArgs(&lt;span class="str"&gt;"IsIncluded"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; OrderedItem Copy()&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; OrderedItem&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;                DisplayName = DisplayName,&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;                IsIncluded = IsIncluded,&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt;                Name = Name,&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;                Position = Position&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;            };&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This method examines the datagrid and creates the ObservableCollection:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ShowLayoutDialog()&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;LayoutRoot.Visibility = Visibility.Visible;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;List&amp;lt;ordereditem&amp;gt; ls = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;ordereditem&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = ZeroBasedStartIndex; i &amp;lt; GridToFormat.Columns.Count; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;                var oi = &lt;span class="kwrd"&gt;new&lt;/span&gt; OrderedItem&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                    Name = GridToFormat.Columns[i].Header.ToString(),&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                    Position = GridToFormat.Columns[i].DisplayIndex + 1 - ZeroBasedStartIndex,&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                    IsIncluded = (GridToFormat.Columns[i].Visibility == Visibility.Visible),&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                    IsFrozen = GridToFormat.Columns[i].IsFrozen&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                };&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                oi.PropertyChanged += &lt;span class="kwrd"&gt;new&lt;/span&gt; PropertyChangedEventHandler(OrderedItem_PropertyChanged);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                ls.Add(oi);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            ls.Sort(&lt;span class="kwrd"&gt;new&lt;/span&gt; OrderedItemComparer());&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;            ChooserGrid.ItemsSource = ls.ToObservableCollection&amp;lt;OrderedItem&amp;gt;();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Here is the method that applies the layout to the grid. InitLayout() and the Save-click handler method calls this method to do their heavy lifting.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; UpdateGridLayout(OrderedItem[] layouts)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (layouts != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;int&lt;/span&gt; fc = (from l &lt;span class="kwrd"&gt;in&lt;/span&gt; layouts &lt;span class="kwrd"&gt;where&lt;/span&gt; l.IsFrozen select 1).Count();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                    GridToFormat.FrozenColumnCount = (fc &amp;gt; 0) ? fc + ZeroBasedStartIndex : 0;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (OrderedItem layout &lt;span class="kwrd"&gt;in&lt;/span&gt; layouts)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                    {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (DataGridColumn c &lt;span class="kwrd"&gt;in&lt;/span&gt; GridToFormat.Columns)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                            &lt;span class="kwrd"&gt;if&lt;/span&gt; (c.Header.ToString() == layout.Name)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                                c.Visibility = layout.IsIncluded ? Visibility.Visible : Visibility.Collapsed;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                                c.DisplayIndex = layout.Position - 1 + ZeroBasedStartIndex;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;                                &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;                            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;                        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;                    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;                &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = ZeroBasedStartIndex; i &amp;lt; GridToFormat.Columns.Count; i++)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;                    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;                        GridToFormat.Columns[i].DisplayIndex = i;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;                        GridToFormat.Columns[i].Visibility = Visibility.Visible;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;                    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;            &lt;span class="kwrd"&gt;catch&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt;                UpdateGridLayout(&lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;                _AppSettings[AppKey] = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;                _AppSettings.Save();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;There are other methods that handle PropertyChanged event for the OrderedItem, and to handle user actions to movver the item up or down. I just want to point out what each method did, and I think the xaml and cs code (that can be downloaded from link in previous post) are pretty self-explanatory. I hope this gives you enough info about the the guts of the user-control to tweak it to your liking.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-5411312244275114812?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/5411312244275114812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/10/silverlight-datagrid-layout-manager.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/5411312244275114812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/5411312244275114812'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/10/silverlight-datagrid-layout-manager.html' title='Silverlight Datagrid Layout Manager: The code'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-4922218806268905927</id><published>2009-10-14T21:54:00.002-04:00</published><updated>2009-10-14T22:06:39.701-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Silverlight DataGrid: Letting Users Manage Layout</title><content type='html'>We have a few datagrids that contain a lot of columns, and different columns are important to different users. They want to see only a subset of what is available, and use different fields as keys to the dataset. So, we had to come up with a way for the users to:&lt;br /&gt;1. Rearrrange the columns&lt;br /&gt;2. Make columns visibile/invisible&lt;br /&gt;3. Freeze some columns in the beginning (keys) so they remain visible during horizontal scrolling.&lt;br /&gt;4. Carry over the user preferences to future sessions.&lt;br /&gt;&lt;br /&gt;We managed to come up with a generic user control to do this for any datagrid, and I think it is worth sharing here. Here is an application that demonstrates the capability:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://silverlight.services.live.com/invoke/105917/Enable%20Users%20to%20Manage%20DataGrid%20Layout%20-%20Demo/iframe.html" scrolling="no" frameborder="0" style="width:100%; height:400px"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;It is just the same datagrid from previous posts, with some extraneous fields to play around with. You get the idea.&lt;br /&gt;&lt;br /&gt;The code for the user control can be found &lt;a href="http://www.filefactory.com/file/a0he029/n/DataGridLayoutChooser_zip" target="New"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To use the DataGridLayoutChooser, you would write some xaml like this:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;lcl:DataGridLayoutChooser&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="dgLayoutChooser"&lt;/span&gt; &lt;span class="attr"&gt;AppKey&lt;/span&gt;&lt;span class="kwrd"&gt;="dgLayout"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;RowSpan&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;The property AppKey is the key that it uses to save the preferences in isolated storage, for use in future sessions.&lt;br /&gt;&lt;br /&gt;When "Loaded" event handler for your app/usercontrol, you want to specify the DataGrid that the Chooser is formatting:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; Home_Loaded(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    dgLayoutChooser.GridToFormat = dg;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    dgLayoutChooser.InitLayout();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;InitLayout() applies any layout that the user may have saved from a previous session.&lt;br /&gt;Now, when the user wants to manage the layout (Click event in the demo, for instance), you call the ShowLayoutDialog() method on the Chooser:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; ManageLayout(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    dgLayoutChooser.ShowLayoutDialog();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;We will take a deeper look at the user-control code in the next post. The DataGridLayoutChooser is a very good candidate to be made into a real control, by the way. I will make that available in a few weeks, when I get around to it. In the meantime, I hope you find this UserControl as useful as we did.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-4922218806268905927?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/4922218806268905927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/10/silverlight-datagrid-letting-users.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4922218806268905927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4922218806268905927'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/10/silverlight-datagrid-letting-users.html' title='Silverlight DataGrid: Letting Users Manage Layout'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-4867851291021618927</id><published>2009-10-09T19:34:00.002-04:00</published><updated>2009-10-09T19:39:05.741-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Context Menu'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Copying Datagrid data to Clipboard through Context Menu</title><content type='html'>In my last post, I talked about adding context menu to Silverlight DataGrid. One thing that always frustrated our users was that they could not copy contents of a datagrid in our application to the clipboard.&lt;br /&gt;&lt;br /&gt;Here is the example (clipboard is accessible through javascript only in IE, mind you):&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://silverlight.services.live.com/invoke/105917/DataGrid%20with%20Ctx%20Menu%20to%20Copy%20Cell%20or%20Row%20content/iframe.html" scrolling="no" frameborder="0" style="width:100%; height:400px"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;I will make the full code available on Monday. Below, is a runthrough of how this was done.&lt;br /&gt;&lt;br /&gt;There are plenty of examples on how to access the clipboard in Silverlight through javascript (for IE, anyways). Here is the code that I used, from &lt;a href="http://www.jeff.wilcox.name/2008/05/clipboard-access/" target="New"&gt;Jeff Wilcox's example&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;1:          public static void SetText(string text)&lt;/pre&gt;&lt;pre&gt;2:          {&lt;/pre&gt;&lt;pre class="alt"&gt;3:              var clipboardData = (ScriptObject)HtmlPage.Window.GetProperty("clipboardData");&lt;/pre&gt;&lt;pre&gt;4:              if (clipboardData != null)&lt;/pre&gt;&lt;pre class="alt"&gt;5:              {&lt;/pre&gt;&lt;pre&gt;6:                  bool success = (bool)clipboardData.Invoke("setData", "text", text);&lt;/pre&gt;&lt;pre class="alt"&gt;7:                  if (!success)&lt;/pre&gt;&lt;pre&gt;8:                  {&lt;/pre&gt;&lt;pre class="alt"&gt;9:                      HtmlPage.Window.Alert(ClipboardFailure);&lt;/pre&gt;&lt;pre&gt;10:                  }&lt;/pre&gt;&lt;pre class="alt"&gt;11:              }&lt;/pre&gt;&lt;pre&gt;12:              else&lt;/pre&gt;&lt;pre class="alt"&gt;13:              {&lt;/pre&gt;&lt;pre&gt;14:                  HtmlPage.Window.Alert("clipboard not available");&lt;/pre&gt;&lt;pre class="alt"&gt;15:              }&lt;/pre&gt;&lt;pre&gt;16:          }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;You can always ctrl+C to copy contents of a textbox or textblock to clipboard, but DataGrid does not allow that. To do this, I take the cell in context, loop through it's children recursively, and write out the contents of the child if it is TextBlock or TextBox:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;1:          private static string GetText(UIElement uie)&lt;/pre&gt;&lt;pre&gt;2:          {&lt;/pre&gt;&lt;pre class="alt"&gt;3:              string ret = string.Empty;&lt;/pre&gt;&lt;pre&gt;4:              if (uie != null)&lt;/pre&gt;&lt;pre class="alt"&gt;5:              {&lt;/pre&gt;&lt;pre&gt;6:                  if (uie is TextBlock)&lt;/pre&gt;&lt;pre class="alt"&gt;7:                      ret = (uie as TextBlock).Text;&lt;/pre&gt;&lt;pre&gt;8:                  else if (uie is TextBox)&lt;/pre&gt;&lt;pre class="alt"&gt;9:                      ret = (uie as TextBox).Text;&lt;/pre&gt;&lt;pre&gt;10:                  else if (uie is Panel)&lt;/pre&gt;&lt;pre class="alt"&gt;11:                  {&lt;/pre&gt;&lt;pre&gt;12:                      foreach (var element in (uie as Panel).Children)&lt;/pre&gt;&lt;pre class="alt"&gt;13:                          ret += GetText(element);&lt;/pre&gt;&lt;pre&gt;14:                  }&lt;/pre&gt;&lt;pre class="alt"&gt;15:              }&lt;/pre&gt;&lt;pre&gt;16:              return ret;&lt;/pre&gt;&lt;pre class="alt"&gt;17:          }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now, what if we want to have a menu command that copies whole row data? I have a generic serializer that takes the datacontext of the row as object and, using reflection, recursively creates a string representation:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Serialize(&lt;span class="kwrd"&gt;object&lt;/span&gt; data)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (data != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                var sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;                var props = data.GetType().GetProperties();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;                sb.Append(data.GetType().Name);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var prop &lt;span class="kwrd"&gt;in&lt;/span&gt; props)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                    var o = prop.GetValue(data, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                    sb.Append(Environment.NewLine).Append(prop.Name).Append(&lt;span class="str"&gt;" = "&lt;/span&gt;);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (o == &lt;span class="kwrd"&gt;null&lt;/span&gt; || o &lt;span class="kwrd"&gt;is&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; || o &lt;span class="kwrd"&gt;is&lt;/span&gt; DateTime || o.GetType().IsPrimitive)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                        sb.Append(o);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                        sb.Append(Serialize(o).Replace(Environment.NewLine, Environment.NewLine + &lt;span class="str"&gt;"\t"&lt;/span&gt;));&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;                &lt;span class="kwrd"&gt;return&lt;/span&gt; sb.ToString();&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;How do we get to a reference to the cell? When context menu is requested, the DataGrid finds the cell where the right-click occurred, and keeps a reference to in a private field, to be used when the menu selection occurs. So the GetContextMenuContent method changes like so:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; List&amp;lt;ContextMenuItemInfo&amp;gt; GetContextMenuContent(System.Windows.Browser.HtmlEventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            Point curr = &lt;span class="kwrd"&gt;new&lt;/span&gt; Point(e.OffsetX, e.OffsetY);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            _CellInContext = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;            &lt;span class="kwrd"&gt;for&lt;/span&gt; (var i = 0; i &amp;lt; presenter.Children.Count; i++)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;                var row = (DataGridRow)presenter.Children[i];&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (ContextMenuInterceptor.IsPointWithinBounds(curr, row))&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var col &lt;span class="kwrd"&gt;in&lt;/span&gt; Columns)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                        var cell = col.GetCellContent(row.DataContext).Parent &lt;span class="kwrd"&gt;as&lt;/span&gt; DataGridCell;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (cell != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; ContextMenuInterceptor.IsPointWithinBounds(curr, cell))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                            _CellInContext = cell;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;                            &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;                        }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;                    }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ContextMenuItemInfo m &lt;span class="kwrd"&gt;in&lt;/span&gt; ContextMenuList)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;                        m.Tag = row;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;return&lt;/span&gt; ContextMenuList;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;                }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;And the HandleContextMenu actually handles some stuff instead of just raising an event:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; HandleContextMenuClick(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ContextMenuClickEventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (e.ClickedItem.Key)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;                &lt;span class="kwrd"&gt;case&lt;/span&gt; CMD_COPY_ROW:&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;                    Clipboard.SetText(Serialize(((DataGridRow)e.ClickedItem.Value).DataContext));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;                &lt;span class="kwrd"&gt;case&lt;/span&gt; CMD_COPY_CELL:&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_CellInContext != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                        Clipboard.SetText(GetText(_CellInContext.Content &lt;span class="kwrd"&gt;as&lt;/span&gt; UIElement));&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;                &lt;span class="kwrd"&gt;default&lt;/span&gt;:&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (ContextMenuClicked != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;                        ContextMenuClicked(sender, e);&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;        }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Both of these have worked very well for our application. Both "Copy Cell Content" and "Copy Row Data" are context menu commands in all our datagrids.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-4867851291021618927?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/4867851291021618927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/10/copying-datagrid-data-to-clipboard.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4867851291021618927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4867851291021618927'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/10/copying-datagrid-data-to-clipboard.html' title='Copying Datagrid data to Clipboard through Context Menu'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-4795325387176587794</id><published>2009-09-27T20:39:00.002-04:00</published><updated>2009-09-27T20:42:42.096-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Silverlight DataGrid with Row-Aware Context Menu</title><content type='html'>&amp;nbsp;In my&lt;a href="http://codeforward.blogspot.com/2009/08/pattern-for-control-specific-context.html"&gt; last post&lt;/a&gt; I talked about adding context-menus to controls. DataGrid is a control that we use in most projects, and it will be nice to have this context menu be aware of the row on which the user clicked and act on the datacontext for that row. Here is a sample application that demonstrates such bahavior:&lt;br /&gt;&lt;br /&gt;&lt;iframe frameborder="0" scrolling="no" src="http://silverlight.services.live.com/invoke/105917/DataGrid%20With%20Right-Click%20Context%20Menu/iframe.html" style="height: 400px; width: 100%;"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;The code can be found &lt;a href="http://www.filefactory.com/file/a0c080b/n/ContextMenuDemo_zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We are creating the context menu and handling right-clicks the same way as described in my earlier post. The main thing is to create a DataGrid which can tell you the row that is clicked. I &lt;a href="http://www.rshelby.com/post/silverlight-datagrid-mouse-wheel-support.aspx"&gt;found &lt;/a&gt;that if you inherit from DataGrid, you have access to the RowsPresenter.&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; PRESENTER_CHILD_NAME = &lt;span class="str"&gt;"RowsPresenter"&lt;/span&gt;;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;protected&lt;/span&gt; DataGridRowsPresenter presenter;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnApplyTemplate()&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;   &lt;span class="kwrd"&gt;base&lt;/span&gt;.OnApplyTemplate();&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;   presenter = (DataGridRowsPresenter)GetTemplateChild(PRESENTER_CHILD_NAME);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I took the row and set it as the "Tag" of the Menu Item. Now we have context.&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: Consolas, "Courier New", Courier, Monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; List&amp;lt;ContextMenuItemInfo&amp;gt; GetContextMenuContent(System.Windows.Browser.HtmlEventArgs e)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;    Point curr = &lt;span class="kwrd"&gt;new&lt;/span&gt; Point(e.OffsetX, e.OffsetY);&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (var i = 0; i &amp;lt; presenter.Children.Count; i++)&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;    {&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        var row = (DataGridRow)presenter.Children[i];&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (ContextMenuInterceptor.IsPointWithinBounds(curr, row))&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (ContextMenuItemInfo m &lt;span class="kwrd"&gt;in&lt;/span&gt; ContextMenuList)&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;            {&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;                m.Tag = row;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;            }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; ContextMenuList;&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;        }&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;    }&lt;/pre&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-4795325387176587794?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/4795325387176587794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/09/silverlight-datagrid-with-row-aware.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4795325387176587794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4795325387176587794'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/09/silverlight-datagrid-with-row-aware.html' title='Silverlight DataGrid with Row-Aware Context Menu'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-4872318421547755348</id><published>2009-08-31T23:01:00.001-04:00</published><updated>2009-08-31T23:05:19.513-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Pattern'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='Mouse Gestures'/><title type='text'>A Pattern For Control-Specific Context Menu on Right-Click in Silverlight</title><content type='html'>There are a lot of good examples online, about how to make Silverlight applications respond to mouse right-clicks. So, I am not going to rehash it in detail here. Instead, I will attempt to describe a pattern that I found useful, when I implemented right-click context menus for controls on a page. The requirements for the functionality are:&lt;br /&gt;&lt;br /&gt;1. There is a unified and consistent way to display context menu.&lt;br /&gt;2. The control provides the data for the display (image / text / data).&lt;br /&gt;3. The control is responsible for responding to the user selection.&lt;br /&gt;&lt;br /&gt;Here is a demo application that uses the pattern I describe. Just as before, there is something about the script on the silverlight live site that doesn't make it work right for firefox. Works fine in IE, and when hosted on another site, on Firefox too. Since the app works ok when code is compiled and run on any browser, I am not going to sweat it.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://silverlight.services.live.com/invoke/105917/Control-Specific%20Right-click%20Context%20Menu%20Demo/iframe.html" scrolling="no" frameborder="0" style="width:100%; height:600px"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Link to app here: &lt;a target="New" href="http://silverlight.services.live.com/invoke/105917/Control-Specific%20Right-click%20Context%20Menu%20Demo/iframe.html"&gt;http://silverlight.services.live.com/invoke/105917/Control-Specific%20Right-click%20Context%20Menu%20Demo/iframe.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The codebase can be downloaded here: &lt;a target="New" href="http://www.filefactory.com/file/ah498ca/n/ContextMenuDemo_zip"&gt;http://www.filefactory.com/file/ah498ca/n/ContextMenuDemo_zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The main component of the functionality is the right-click interceptor class, which interacts with the DOM and intercepts the right mouse down, mouseclick, oncontextmenu events. Make sure your app is set as "windowless". All these aspects, it shares with other examples online. We will come to some extra functionality of this class later. The RootVisual of the app has an instance of this class.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;private&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; OnMouseDown(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, HtmlEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (e.MouseButton == MouseButtons.Right)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;foreach&lt;/span&gt; (FrameworkElement ei &lt;span style=' color: Blue;'&gt;in&lt;/span&gt; _ElementsToIntercept)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  6&lt;/span&gt;                 {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  7&lt;/span&gt;                     &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (IsPointWithinBounds(&lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Point(e.OffsetX, e.OffsetY), ei))&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  8&lt;/span&gt;                     {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  9&lt;/span&gt;                         e.PreventDefault();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 10&lt;/span&gt;                         &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (MouseRightButtonDown != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 11&lt;/span&gt;                             MouseRightButtonDown(&lt;span style=' color: Blue;'&gt;this&lt;/span&gt;, e);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 12&lt;/span&gt;                         RightClickedControl = ei;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 13&lt;/span&gt;                         _IsButtonDown = &lt;span style=' color: Maroon;'&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 14&lt;/span&gt;                         &lt;span style=' color: Blue;'&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 15&lt;/span&gt;                     }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 16&lt;/span&gt;                 }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 17&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 18&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 19&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;private&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; OnMouseUp(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, HtmlEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 20&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 21&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (e.MouseButton == MouseButtons.Right &amp;amp;&amp;amp; _IsButtonDown)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 22&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 23&lt;/span&gt;                 e.PreventDefault();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 24&lt;/span&gt;                 _IsButtonDown = &lt;span style=' color: Maroon;'&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 25&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (MouseRightButtonUp != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 26&lt;/span&gt;                     MouseRightButtonUp(&lt;span style=' color: Blue;'&gt;this&lt;/span&gt;, e);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 27&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 28&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 29&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 30&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;private&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; OnContextMenu(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, HtmlEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 31&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 32&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;foreach&lt;/span&gt; (FrameworkElement ei &lt;span style=' color: Blue;'&gt;in&lt;/span&gt; _ElementsToIntercept)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 33&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 34&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (IsPointWithinBounds(&lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Point(e.OffsetX, e.OffsetY), ei))&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 35&lt;/span&gt;                 {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 36&lt;/span&gt;                     e.PreventDefault();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 37&lt;/span&gt;                     &lt;span style=' color: Blue;'&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 38&lt;/span&gt;                 }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 39&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 40&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 41&lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The second component is the "ISupportCOntextMenu" interface.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt;     &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;interface&lt;/span&gt; ISupportContextMenu&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt;     {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; HandleContextMenuClick(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, ContextMenuClickEventArgs e);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;         List&amp;lt;ContextMenuItemInfo&amp;gt; GetContextMenuContent(HtmlEventArgs e);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;Any control that needs a context menu needs to implement this interface, and the control needs to be registered with the rootvisual. Thre registration process brings us to the extra stuff in the interceptor. Interceptor maintains a list of references to ISupportContextMenu. Registration just adds to this list. When an interceptable event happens, the interceptor checks to see if it happened within the bounds of any of the items in the list (Big part of the whole thing).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;static&lt;/span&gt; &lt;span style=' color: Blue;'&gt;bool&lt;/span&gt; IsPointWithinBounds(Point p, FrameworkElement element)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;                 GeneralTransform gt = element.TransformToVisual(Application.Current.RootVisual &lt;span style=' color: Blue;'&gt;as&lt;/span&gt; FrameworkElement);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  6&lt;/span&gt;                 Point cp = gt.Transform(&lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Point(&lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;, &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;));&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  7&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  8&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (p.X &amp;lt;= cp.X + element.ActualWidth &amp;amp;&amp;amp; p.X &amp;gt;= cp.X &amp;amp;&amp;amp; p.Y &amp;lt;= cp.Y + element.ActualHeight &amp;amp;&amp;amp; p.Y &amp;gt;= cp.Y)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  9&lt;/span&gt;                     &lt;span style=' color: Blue;'&gt;return&lt;/span&gt; &lt;span style=' color: Maroon;'&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 10&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;else&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 11&lt;/span&gt;                     &lt;span style=' color: Blue;'&gt;return&lt;/span&gt; &lt;span style=' color: Maroon;'&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 12&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 13&lt;/span&gt;             &lt;span style=' color: Green;'&gt;//if the control has been cleared from parent 'transformtovisual' will throw an error.&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 14&lt;/span&gt;             &lt;span style=' color: Green;'&gt;//In that case return false&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 15&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;catch&lt;/span&gt; { &lt;span style=' color: Blue;'&gt;return&lt;/span&gt; &lt;span style=' color: Maroon;'&gt;false&lt;/span&gt;; }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 16&lt;/span&gt;         }&lt;/pre&gt;&lt;br /&gt;If it did, then it asks the control to provide data for the context menu (GetContextMenuContent()).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt; &lt;span style=' color: Green;'&gt;//From instantiating control:&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; Home()&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;             InitializeComponent();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  6&lt;/span&gt;             ((MainPage)App.Current.RootVisual).RegisterControlWithContextMenu(Ctx1);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  7&lt;/span&gt;             ((MainPage)App.Current.RootVisual).RegisterControlWithContextMenu(Ctx2);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  8&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  9&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 10&lt;/span&gt; &lt;span style=' color: Green;'&gt;//From RootVisual:&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 11&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 12&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; RegisterControlWithContextMenu(ISupportContextMenu control)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 13&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 14&lt;/span&gt;             _RightClickIntrcpt.AddElementToIntercept(control);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 15&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 16&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 17&lt;/span&gt; &lt;span style=' color: Green;'&gt;//From Interceptor:&lt;/span&gt;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 18&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 19&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; AddElementToIntercept(ISupportContextMenu fe)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 20&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 21&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (!_ElementsToIntercept.Contains(fe))&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 22&lt;/span&gt;                 _ElementsToIntercept.Add(fe);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 23&lt;/span&gt;         }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This brings us to the third component: ContextMenuItemInfo. &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt;     &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;class&lt;/span&gt; ContextMenuItemInfo&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt;     {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; Image Image { &lt;span style=' color: Blue;'&gt;get&lt;/span&gt;; &lt;span style=' color: Blue;'&gt;set&lt;/span&gt;; }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; &lt;span style=' color: Blue;'&gt;string&lt;/span&gt; Command { &lt;span style=' color: Blue;'&gt;get&lt;/span&gt;; &lt;span style=' color: Blue;'&gt;set&lt;/span&gt;; }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;public&lt;/span&gt; Object Tag { &lt;span style=' color: Blue;'&gt;get&lt;/span&gt;; &lt;span style=' color: Blue;'&gt;set&lt;/span&gt;; }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  6&lt;/span&gt;     }&lt;/pre&gt;You can provide a list of items, each of which contains an image (optional), text, and any kind of data that makes sense in the context (optional) to the interceptor. The text and data tag is passed back to the control as a KeyValuePair if user click on it.&lt;br /&gt;&lt;br /&gt;The third component is a popup control that holds a list box. This is in the root visual. The RootVisual responds to an event raised by the interceptor and takes the&amp;nbsp; List of ContextMenuItemInfo, populates the listbox, moves the popup to where the mouse is, and displays it. There is a DispatcherTimer and MouseEnter/MouseLeave events that make sure the popup is displayed and hidden in a graceful manner. In the RootVisual:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style='color: Teal; background-color: '&gt;  1&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;private&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; InitializeContextMenuIntercept()&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  2&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  3&lt;/span&gt;             InitializeContextMenuTimer();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  4&lt;/span&gt;             _RightClickIntrcpt = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; ContextMenuInterceptor();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  5&lt;/span&gt;             _RightClickIntrcpt.MouseRightButtonUp += &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; EventHandler&amp;lt;System.Windows.Browser.HtmlEventArgs&amp;gt;(_RightClickIntrcpt_MouseRightButtonUp);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  6&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  7&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  8&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;private&lt;/span&gt; &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; InitializeContextMenuTimer()&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt;  9&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 10&lt;/span&gt;             _ContextMenuTimer = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; DispatcherTimer();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 11&lt;/span&gt;             _ContextMenuTimer.Interval = TimeSpan.FromSeconds(&lt;span style=' color: Maroon;'&gt;2&lt;/span&gt;);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 12&lt;/span&gt;             _ContextMenuTimer.Tick += (s, e) =&amp;gt; ContextMenu_MouseLeave(&lt;span style=' color: Blue;'&gt;null&lt;/span&gt;, &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 13&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 14&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 15&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; _RightClickIntrcpt_MouseRightButtonUp(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, System.Windows.Browser.HtmlEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 16&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 17&lt;/span&gt;             ISupportContextMenu cntrl = _RightClickIntrcpt.RightClickedControl &lt;span style=' color: Blue;'&gt;as&lt;/span&gt; ISupportContextMenu;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 18&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (cntrl != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 19&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 20&lt;/span&gt;                 List&amp;lt;ContextMenuItemInfo&amp;gt; mnuContent = cntrl.GetContextMenuContent(e);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 21&lt;/span&gt;                 &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (mnuContent != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt; &amp;amp;&amp;amp; mnuContent.Count &amp;gt; &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 22&lt;/span&gt;                 {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 23&lt;/span&gt;                     ContextMenuListBox.ItemsSource = from mc &lt;span style=' color: Blue;'&gt;in&lt;/span&gt; mnuContent&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 24&lt;/span&gt;                                                      select &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; ListBoxItem&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 25&lt;/span&gt;                                                      {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 26&lt;/span&gt;                                                          Content = GetContextMenuItemVisual(mc.Command, mc.Image),&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 27&lt;/span&gt;                                                          Tag = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; KeyValuePair&amp;lt;&lt;span style=' color: Blue;'&gt;string&lt;/span&gt;, &lt;span style=' color: Blue;'&gt;object&lt;/span&gt;&amp;gt;(mc.Command, mc.Tag)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 28&lt;/span&gt;                                                      };&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 29&lt;/span&gt;                     ContextMenuListBox.MouseLeftButtonUp += ContextMenuListBox_MouseLeftButtonUp;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 30&lt;/span&gt;                     ContextMenuPopup.Margin = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Thickness(e.OffsetX, e.OffsetY, &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;, &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 31&lt;/span&gt;                     ContextMenuPopup.IsOpen = &lt;span style=' color: Maroon;'&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 32&lt;/span&gt;                     _ContextMenuTimer.Start();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 33&lt;/span&gt;                 }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 34&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 35&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 36&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 37&lt;/span&gt;         FrameworkElement GetContextMenuItemVisual(&lt;span style=' color: Blue;'&gt;string&lt;/span&gt; command, Image image)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 38&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 39&lt;/span&gt;             StackPanel ret = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; StackPanel&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 40&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 41&lt;/span&gt;                 Orientation = Orientation.Horizontal,&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 42&lt;/span&gt;                 Margin = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Thickness(&lt;span style=' color: Maroon;'&gt;2&lt;/span&gt;),&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 43&lt;/span&gt;             };&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 44&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (image != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 45&lt;/span&gt;             {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 46&lt;/span&gt;                 image.Margin = &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; Thickness(&lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;, &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;, &lt;span style=' color: Maroon;'&gt;4&lt;/span&gt;, &lt;span style=' color: Maroon;'&gt;0&lt;/span&gt;);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 47&lt;/span&gt;                 ret.Children.Add(image);&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 48&lt;/span&gt;             }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 49&lt;/span&gt;             ret.Children.Add(&lt;span style=' color: Blue;'&gt;new&lt;/span&gt; TextBlock { Text = command });&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 50&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;return&lt;/span&gt; ret;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 51&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 52&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 53&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 54&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; ContextMenuListBox_MouseLeftButtonUp(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, System.Windows.Input.MouseButtonEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 55&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 56&lt;/span&gt;             &lt;span style=' color: Blue;'&gt;if&lt;/span&gt; (ContextMenuListBox.SelectedItem != &lt;span style=' color: Blue;'&gt;null&lt;/span&gt;)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 57&lt;/span&gt;                 ((ISupportContextMenu)_RightClickIntrcpt.RightClickedControl).HandleContextMenuClick(&lt;span style=' color: Blue;'&gt;this&lt;/span&gt;, &lt;span style=' color: Blue;'&gt;new&lt;/span&gt; ContextMenuClickEventArgs&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 58&lt;/span&gt;                 {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 59&lt;/span&gt;                     ClickedItem = (KeyValuePair&amp;lt;&lt;span style=' color: Blue;'&gt;string&lt;/span&gt;, &lt;span style=' color: Blue;'&gt;object&lt;/span&gt;&amp;gt;)((ListBoxItem)ContextMenuListBox.SelectedItem).Tag&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 60&lt;/span&gt;                 });&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 61&lt;/span&gt;             ContextMenuListBox.MouseLeftButtonUp -= ContextMenuListBox_MouseLeftButtonUp;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 62&lt;/span&gt;             ContextMenuPopup.IsOpen = &lt;span style=' color: Maroon;'&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 63&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 64&lt;/span&gt; &lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 65&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; ContextMenu_MouseEnter(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 66&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 67&lt;/span&gt;             _ContextMenuTimer.Stop();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 68&lt;/span&gt;             ContextMenuPopup.IsOpen = &lt;span style=' color: Maroon;'&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 69&lt;/span&gt;         }&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 70&lt;/span&gt;         &lt;span style=' color: Blue;'&gt;void&lt;/span&gt; ContextMenu_MouseLeave(&lt;span style=' color: Blue;'&gt;object&lt;/span&gt; sender, RoutedEventArgs e)&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 71&lt;/span&gt;         {&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 72&lt;/span&gt;             ContextMenuPopup.IsOpen = &lt;span style=' color: Maroon;'&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 73&lt;/span&gt;             _ContextMenuTimer.Stop();&lt;br /&gt;&lt;span style='color: Teal; background-color: '&gt; 74&lt;/span&gt;         }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This ensures that a control has total say if it wants a context menu, and if so, what the content should be, and how the application should respond to user selection. I know that a lot of things are not elaborated here, but I am hoping it will make sense when you go through the code. If needed, I can augment this with some diagrams. Let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-4872318421547755348?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/4872318421547755348/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/08/pattern-for-control-specific-context.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4872318421547755348'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4872318421547755348'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/08/pattern-for-control-specific-context.html' title='A Pattern For Control-Specific Context Menu on Right-Click in Silverlight'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-6076959088776943596</id><published>2009-08-24T18:58:00.010-04:00</published><updated>2009-08-25T07:42:49.808-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='Mouse Gestures'/><title type='text'>Mouse DoubleClick in Silverlight</title><content type='html'>We are implementing a mouse-doubleclick event in the TimeLine Visualizer control, but that is not native to Silverlight. There are a number of code snippets on the web about how to do this, but I think the implementation of the event is nice enough to share here.&lt;br /&gt;&lt;br /&gt;The event fires when the mouse is clicked twice within a certain time, and within a certain distance. I think the spatial/temporal tolerances make for a smooth user experience. The code consists of static variables to store the position and time of last mouse-click, and extension methods to compare the current values to the stored values. The code should be self-explanatory (While we are one the subject, can anybody point me to a good online code formatter for blogger? Live Writer refuses to install on my machine which has Windows 7 Ultimate, 32-bit):&lt;br /&gt;&lt;br /&gt;&lt;pre  style="font-family:arial;font-size:12px;border:1px dashed #CCCCCC;width:99%;height:auto;overflow:auto;background:#f0f0f0;;background-image:URL(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif);padding:0px;color:#000000;text-align:left;line-height:20px;"&gt;&lt;code style="color:#000000;word-wrap:normal;"&gt;1:      #region Mouse Double Click  &lt;br /&gt;2:      //initialize to 2 secs back, so event doesnt fire very first time user clicks on control  &lt;br /&gt;3:      static DateTime _lastClicked = DateTime.Now.AddSeconds(-2);  &lt;br /&gt;4:      static Point _lastMousePosition = new Point(1, 1);  &lt;br /&gt;5:      private const double MousePositionTolerance = 20;  &lt;br /&gt;6:      public static bool IsDoubleClick(this MouseButtonEventArgs e)  &lt;br /&gt;7:      {  &lt;br /&gt;8:        bool ret = false;  &lt;br /&gt;9:        if ((DateTime.Now.Subtract(_lastClicked) &amp;lt; TimeSpan.FromMilliseconds(500))  &lt;br /&gt;10:          &amp;amp;&amp;amp; (e.GetPosition(null).GetDistance(_lastMousePosition) &amp;lt; MousePositionTolerance))  &lt;br /&gt;11:        {  &lt;br /&gt;12:          ret = true;  &lt;br /&gt;13:        }  &lt;br /&gt;14:        _lastClicked = DateTime.Now;  &lt;br /&gt;15:        _lastMousePosition = e.GetPosition(null);  &lt;br /&gt;16:        return ret;  &lt;br /&gt;17:      }  &lt;br /&gt;18:      #endregion  &lt;br /&gt;19:      public static double GetDistance(this Point current, Point other)  &lt;br /&gt;20:      {  &lt;br /&gt;21:        double x = current.X - other.X;  &lt;br /&gt;22:        double y = current.Y - other.Y;  &lt;br /&gt;23:        return Math.Sqrt(x * x + y * y);  &lt;br /&gt;24:      }  &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The consumer code will handle the MouseLeftButtonDown event and examine it to see if it is a double-click, like this:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;&lt;span style="color:black;"&gt;HandleMouseLeftButtonDown&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;object &lt;/span&gt;&lt;span style="color:black;"&gt;sender&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;MouseButtonEventArgs e&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;          &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;e.IsDoubleClick&lt;/span&gt;&lt;span style="color:gray;"&gt;())&lt;br /&gt;&lt;br /&gt;          &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;/span&gt;&lt;/code&gt;....&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;Caveat Emptor:&lt;br /&gt;The calling method should make sure that all code paths execute e.DoubleClick().&lt;br /&gt;&lt;br /&gt;Take, for instance, a calling method like this:&lt;br /&gt;&lt;br /&gt;if (condition1 == true)&lt;br /&gt;{&lt;br /&gt;  condition1 = false;&lt;br /&gt;  do something;&lt;br /&gt;}&lt;br /&gt;else if (e.IsDoubleClick())&lt;br /&gt;{&lt;br /&gt;  Do what you do on doubleclick;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Here IsDoubleClick is not called the first time the Mousedown event happens, so the static variables _lastPosition and _lastClicked are not set. Hence, IsDoubleClick will not return true when a true double-click happens.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Hope this helps.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-6076959088776943596?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/6076959088776943596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/08/mouse-doubleclick-in-silverlight.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/6076959088776943596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/6076959088776943596'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/08/mouse-doubleclick-in-silverlight.html' title='Mouse DoubleClick in Silverlight'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-4407316309015514175</id><published>2009-08-18T21:53:00.009-04:00</published><updated>2009-08-18T22:53:33.252-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Usercontrol'/><category scheme='http://www.blogger.com/atom/ns#' term='Data visualization'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>A Timeline Visualizer in Silverlight/C#: Part 2</title><content type='html'>The last post was a primer on consuming the TimeLineVisualizer control. If you want to just use the control as is, that is all you would need. You can customize the appearance by changing the colors and brushes in the xaml of TimeLineVisualizer and TimeLine controls. But, if you are interested in how these controls work, here you go:&lt;br /&gt;&lt;br /&gt;Link to code (control and demo): &lt;a target="new" href="http://www.filefactory.com/file/ah13e8g/n/VisualTimelineDemo_zip"&gt;http://www.filefactory.com/file/ah13e8g/n/VisualTimelineDemo_zip&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Link to demo: &lt;a target="new" href="http://silverlight.services.live.com/invoke/105917/TimeLine%20Visualizer%20Demo/iframe.html"&gt;http://silverlight.services.live.com/invoke/105917/TimeLine%20Visualizer%20Demo/iframe.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;TimeLineVisualizer xaml:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;    &lt;/span&gt;&lt;span style="color:gray;"&gt;&lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Grid x:Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"LayoutRoot" &lt;/span&gt;&lt;span style="color:black;"&gt;Background&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"White"&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;&lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;    &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;RowDefinition x:Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"TimeLineAxisRow" &lt;/span&gt;&lt;span style="color:black;"&gt;Height&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Auto"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&gt;&lt;br /&gt;    &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;RowDefinition x:Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"TimeLineObjectsRow" &lt;/span&gt;&lt;span style="color:black;"&gt;Height&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"*"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;&lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Canvas Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"AxisCanvas" &lt;/span&gt;&lt;span style="color:black;"&gt;Grid.Row&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0" &lt;/span&gt;&lt;span style="color:black;"&gt;Height&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"50" &lt;/span&gt;&lt;span style="color:black;"&gt;Margin&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0,0,20,0"&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;    &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Line Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"AxisLine" &lt;/span&gt;&lt;span style="color:black;"&gt;Stroke&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"#AA000000" &lt;/span&gt;&lt;span style="color:black;"&gt;StrokeThickness&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;".2" &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.Top&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"48" &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.Left&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;Canvas&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;&lt;&lt;/span&gt;&lt;span style="color:black;"&gt;ScrollViewer Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"PlotScrollViewer" &lt;/span&gt;&lt;span style="color:black;"&gt;BorderThickness&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0" &lt;/span&gt;&lt;span style="color:black;"&gt;Margin&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0" &lt;/span&gt;&lt;span style="color:black;"&gt;Padding&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0" &lt;/span&gt;&lt;span style="color:black;"&gt;Grid.Row&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"1" &lt;/span&gt;&lt;span style="color:black;"&gt;SizeChanged&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"ScrollViewer_SizeChanged"&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;    &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Canvas Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"PlotCanvas" &lt;/span&gt;&lt;span style="color:black;"&gt;SizeChanged&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_SizeChanged" &lt;/span&gt;&lt;span style="color:black;"&gt;MouseLeftButtonDown&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_MouseLeftButtonDown" &lt;/span&gt;&lt;span style="color:black;"&gt;MouseLeftButtonUp&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_MouseLeftButtonUp" &lt;/span&gt;&lt;span style="color:black;"&gt;MouseMove&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_MouseMove" &lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;        &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.Background&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;            &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;LinearGradientBrush EndPoint&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0.457,0.296" &lt;/span&gt;&lt;span style="color:black;"&gt;StartPoint&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0.459,1.296"&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;                &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;GradientStop Color&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"#FFCBCBCB"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&gt;&lt;br /&gt;                &lt;&lt;/span&gt;&lt;span style="color:black;"&gt;GradientStop Color&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"#FFFFFFFF" &lt;/span&gt;&lt;span style="color:black;"&gt;Offset&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"1.1"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&gt;&lt;br /&gt;            &lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;LinearGradientBrush&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;        &lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;Canvas.Background&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;    &lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;Canvas&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;ScrollViewer&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;&lt;br /&gt;&lt;!--&lt;/span--&gt;&lt;span style="color:black;"&gt;Grid&lt;/span&gt;&lt;span style="color:gray;"&gt;&gt;   &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;TimeLineVisualizer takes the data in the form of IEnumerable&amp;lt;timelinedata&amp;gt;:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;    &lt;/span&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineData &lt;/span&gt;&lt;span style="color:gray;"&gt;: &lt;/span&gt;&lt;span style="color:black;"&gt;INotifyPropertyChanged&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;private bool &lt;/span&gt;&lt;span style="color:black;"&gt;_IsHighLighted&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:black;"&gt;Brush BackGround { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public object &lt;/span&gt;&lt;span style="color:black;"&gt;DataContext { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:black;"&gt;DateTime Start { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:black;"&gt;DateTime End { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public string &lt;/span&gt;&lt;span style="color:black;"&gt;Label { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public object &lt;/span&gt;&lt;span style="color:black;"&gt;ToolTip { get&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;set&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public bool &lt;/span&gt;&lt;span style="color:black;"&gt;IsHighlighted&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    get { &lt;/span&gt;&lt;span style="color:blue;"&gt;return &lt;/span&gt;&lt;span style="color:black;"&gt;_IsHighLighted&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;    set&lt;br /&gt;&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        _IsHighLighted &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;value&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;PropertyChanged &lt;/span&gt;&lt;span style="color:gray;"&gt;!= &lt;/span&gt;&lt;span style="color:blue;"&gt;null&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;            &lt;/span&gt;&lt;span style="color:black;"&gt;PropertyChanged&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;this&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:black;"&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:darkred;"&gt;"IsHighLighted"&lt;/span&gt;&lt;span style="color:gray;"&gt;));&lt;br /&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#region INotifyPropertyChanged Members&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;public event &lt;/span&gt;&lt;span style="color:black;"&gt;PropertyChangedEventHandler PropertyChanged&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:black;"&gt;#endregion&lt;br /&gt;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When you set the ITemsSource for the visualizer, you should be able to massage any data into this form using LINQ, if the data has a schedule-like behavior. There is a DataContext property to hang any app-specific data on the timeline object. This will get included in the DetailRequested event if the timeline is selected at the time.&lt;br /&gt;&lt;br /&gt;Xaml for TimeLine:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;    &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Canvas Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"RootCanvas" &lt;/span&gt;&lt;span style="color:black;"&gt;SizeChanged&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_SizeChanged" &lt;/span&gt;&lt;span style="color:black;"&gt;MouseLeftButtonDown&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Canvas_MouseLeftButtonDown" &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Border Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"TimeLineBorder" &lt;/span&gt;&lt;span style="color:black;"&gt;CornerRadius&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"5" &lt;/span&gt;&lt;span style="color:black;"&gt;BorderBrush&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"#BB64789B"&lt;br /&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span style="color:black;"&gt;BorderThickness&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"1" &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.Top&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"0" &lt;/span&gt;&lt;span style="color:black;"&gt;MouseLeftButtonDown&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Border_MouseLeftButtonDown" &lt;/span&gt;&lt;span style="color:black;"&gt;Background&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"{StaticResource TimeLineBackground}"&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:black;"&gt;Border&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:black;"&gt;TextBlock FontWeight&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Medium"  &lt;/span&gt;&lt;span style="color:black;"&gt;MouseLeftButtonDown&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Border_MouseLeftButtonDown" &lt;/span&gt;&lt;span style="color:black;"&gt;FontSize&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"10" &lt;/span&gt;&lt;span style="color:black;"&gt;Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"TimeLineTextBlock" &lt;/span&gt;&lt;span style="color:black;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Center" &lt;/span&gt;&lt;span style="color:black;"&gt;VerticalAlignment&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"Center"&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:black;"&gt;TextBlock&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;&lt;/span&gt;&lt;span style="color:black;"&gt;Line Name&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"BottomBorderLine" &lt;/span&gt;&lt;span style="color:black;"&gt;Stroke&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;"#FFFFFFFF" &lt;/span&gt;&lt;span style="color:black;"&gt;StrokeThickness&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:darkred;"&gt;".1"&lt;/span&gt;&lt;span style="color:gray;"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;        &amp;lt;/&lt;/span&gt;&lt;span style="color:black;"&gt;Canvas&lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The visualizer just presents the data in the same order as it receives, so user OrderBy if you want to see data in a sequential format top to bottom.  For each TimeLineData object, the Visualizer control creates a TimeLine control, and stack them top to bottom in the canvas PlotCanvas.&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;&lt;span style="color:black;"&gt;VisualizeItemsSource&lt;/span&gt;&lt;span style="color:gray;"&gt;()&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//we may change the size of the plot depending on number of elements we have to draw.&lt;br /&gt;&lt;br /&gt;//Dont want to fire the size-changed event and redraw stuff, so unhook event handler&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.SizeChanged &lt;/span&gt;&lt;span style="color:gray;"&gt;-&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas_SizeChanged&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;String&lt;/span&gt;&lt;span style="color:black;"&gt;[] currHighlight &lt;/span&gt;&lt;span style="color:blue;"&gt;= null&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Children.Count &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;       currHighlight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;from tl &lt;/span&gt;&lt;span style="color:blue;"&gt;in &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Children&lt;br /&gt;&lt;br /&gt;           where&lt;br /&gt;&lt;br /&gt;           tl &lt;/span&gt;&lt;span style="color:blue;"&gt;is &lt;/span&gt;&lt;span style="color:black;"&gt;TimeLine &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;amp;&amp;amp; ((&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLine&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;tl&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.ItemsSource.IsHighlighted&lt;br /&gt;&lt;br /&gt;           select &lt;/span&gt;&lt;span style="color:gray;"&gt;((&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLine&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;tl&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.ItemsSource.Label&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.ToArray&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//remove all existing stuff on the plot canvas&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Children.Clear&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//if the elements can be more than the minimum specified height and still fit into the&lt;br /&gt;&lt;br /&gt;//viewport of scrollviewer, do that. Else grow the plotcanvas height to (elementCount * minimumHeight)&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Height &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;PlotScrollViewer.ActualHeight&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;totalHeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Height&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;tlHeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_itemsSource &lt;/span&gt;&lt;span style="color:gray;"&gt;!= &lt;/span&gt;&lt;span style="color:blue;"&gt;null&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;       tlHeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;totalHeight&lt;/span&gt;&lt;span style="color:gray;"&gt;/&lt;/span&gt;&lt;span style="color:black;"&gt;_itemsSource.Count&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;tlHeight &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:black;"&gt;MINIMUM_TIMELINE_HEIGHT&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;       tlHeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;MINIMUM_TIMELINE_HEIGHT&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;       &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Height &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_itemsSource &lt;/span&gt;&lt;span style="color:blue;"&gt;==null&lt;/span&gt;&lt;span style="color:black;"&gt;?0: MINIMUM_TIMELINE&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How an individual TimeLine visualizes it's data:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;&lt;span style="color:black;"&gt;VisualizeItemsSource&lt;/span&gt;&lt;span style="color:gray;"&gt;()&lt;br /&gt;&lt;br /&gt;     &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;         &lt;/span&gt;&lt;span style="color:green;"&gt;//make sure we have all the values needed, before attempting to visualize&lt;br /&gt;&lt;br /&gt;         &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineEnd &lt;/span&gt;&lt;span style="color:gray;"&gt;!= &lt;/span&gt;&lt;span style="color:blue;"&gt;null &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineStart &lt;/span&gt;&lt;span style="color:gray;"&gt;!= &lt;/span&gt;&lt;span style="color:blue;"&gt;null &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;amp;&amp;amp; &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource &lt;/span&gt;&lt;span style="color:gray;"&gt;!= &lt;/span&gt;&lt;span style="color:blue;"&gt;null&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;         &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:green;"&gt;//Width of the event: (event-length / timeline-length) * width of root canvas&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;w &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.End &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.Start&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays &lt;/span&gt;&lt;span style="color:gray;"&gt;/ (&lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineEnd.Value &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineStart.Value&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays &lt;/span&gt;&lt;span style="color:gray;"&gt;* &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.ActualWidth&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:green;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;TimeLineBorder.Width = (w &amp;gt; 0) ? w : 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;TimeLineBorder.Height = (RootCanvas.ActualHeight &amp;gt; 3) ? RootCanvas.ActualHeight - 3 : RootCanvas.ActualHeight;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.Background &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.BackGround&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineBorder&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;1.5&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:green;"&gt;//place where event starts in the timeline: (event-start - timeline-start)/(timeline-end - event-start) * width of root canvas&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;borderLeft &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.Start &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineStart.Value&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays &lt;/span&gt;&lt;span style="color:gray;"&gt;/ (&lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineEnd.Value &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_TimeLineStart.Value&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays &lt;/span&gt;&lt;span style="color:gray;"&gt;* &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.ActualWidth&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineBorder&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;borderLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:green;"&gt;//line at bottom of timeline, to separate it from next one.&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;BottomBorderLine&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.ActualHeight &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;0.1&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;BottomBorderLine.X2 &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.ActualWidth&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:green;"&gt;//write out the label and tooltip&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineTextBlock.Text &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.Label&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineTextBlock&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;borderLeft &lt;/span&gt;&lt;span style="color:gray;"&gt;+ &lt;/span&gt;&lt;span style="color:black;"&gt;4&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;                 &lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineTextBlock&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;borderLeft &lt;/span&gt;&lt;span style="color:gray;"&gt;+ &lt;/span&gt;&lt;span style="color:black;"&gt;5&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt; &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;                 &lt;/span&gt;&lt;span style="color:black;"&gt;textBlockLeft &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;3&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;ToolTipService.SetToolTip&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineBorder&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.ToolTip&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;ToolTipService.SetToolTip&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;TimeLineTextBlock&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;_ItemsSource.ToolTip&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;             &lt;/span&gt;&lt;span style="color:black;"&gt;RootCanvas.UpdateLayout&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;         &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;     }&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is the method that perform the painful details of drawing the axis:&lt;br /&gt;&lt;br /&gt;&lt;code  style="font-size:12px;"&gt;&lt;span style="color:black;"&gt;        &lt;/span&gt;&lt;span style="color:blue;"&gt;private void &lt;/span&gt;&lt;span style="color:black;"&gt;DrawAxis&lt;/span&gt;&lt;span style="color:gray;"&gt;()&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Clear all existing elements in axis canvas&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Clear&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//number of days in the range. Includes partial days.&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;numDays &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_endDate.Value &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_startDate.Value&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;totalWidth &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.ActualWidth&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Set the axis to span the whole plot canvas&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisLine.X2 &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;totalWidth&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;AxisLine&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Get the Width of a day as represented in the axis. This value wil be used to compute&lt;br /&gt;&lt;br /&gt;//the date/time info represented by a point on the plot canvas until the next time axis changes&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;totalWidth &lt;/span&gt;&lt;span style="color:gray;"&gt;/ &lt;/span&gt;&lt;span style="color:black;"&gt;numDays&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;_mouseHighlight.Width &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;_mouseHighlight.Height &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Height&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_mouseHighlight&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;0 &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;PlotCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_mouseHighlight&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//The first day may be a partial day. If it is, account for this on the axis.&lt;br /&gt;&lt;br /&gt;//axisOffset represents the part of the day before the axis starts&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;_axisOffset &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_startDate.Value.TimeOfDay &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_startDate.Value.Date.TimeOfDay&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;.TotalDays &lt;/span&gt;&lt;span style="color:gray;"&gt;* &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;for &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;i &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;i &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;lt;= &lt;/span&gt;&lt;span style="color:black;"&gt;numDays&lt;/span&gt;&lt;span style="color:gray;"&gt;; &lt;/span&gt;&lt;span style="color:black;"&gt;i&lt;/span&gt;&lt;span style="color:gray;"&gt;++)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//day we are dealing with&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;DateTime currentDate &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_startDate.Value.AddDays&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;i&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//'left' is the point on the axis that represents the start of the day&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;double &lt;/span&gt;&lt;span style="color:black;"&gt;left &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay &lt;/span&gt;&lt;span style="color:gray;"&gt;* &lt;/span&gt;&lt;span style="color:black;"&gt;i &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;_axisOffset&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//draw the vertical hash on axis&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;var l &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;Line { Y2 &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;10&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;StrokeThickness &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;0.1&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Stroke &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;SolidColorBrush { Color &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Colors.Black } }&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;( &lt;/span&gt;&lt;span style="color:black;"&gt;l&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;l&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;40&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;l&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Date and DayOfWeek are written on the axis if the width of a day is more than 20&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay &lt;/span&gt;&lt;span style="color:gray;"&gt;&amp;gt; &lt;/span&gt;&lt;span style="color:black;"&gt;20&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Write date on the axis, starting 3 units from center of the day width&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;var t &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;TextBlock { Text &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Day.ToString&lt;/span&gt;&lt;span style="color:gray;"&gt;(), &lt;/span&gt;&lt;span style="color:black;"&gt;FontSize &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;9&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeights.Thin&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Foreground &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;SolidColorBrush { Color &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Colors.Gray } }&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;t&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;left &lt;/span&gt;&lt;span style="color:gray;"&gt;+ &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay &lt;/span&gt;&lt;span style="color:gray;"&gt;/ &lt;/span&gt;&lt;span style="color:black;"&gt;2 &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;3&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;t&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;30&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;t&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Write dayOfWeek on the axis, starting 3 units from center of the day width&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;var d &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;TextBlock { Text &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.DayOfWeek.ToString&lt;/span&gt;&lt;span style="color:gray;"&gt;()&lt;/span&gt;&lt;span style="color:black;"&gt;.Substring&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;0&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;/span&gt;&lt;span style="color:black;"&gt;3&lt;/span&gt;&lt;span style="color:gray;"&gt;), &lt;/span&gt;&lt;span style="color:black;"&gt;FontSize &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;9&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeights.Medium&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Foreground &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;SolidColorBrush{Color&lt;/span&gt;&lt;span style="color:blue;"&gt;=&lt;/span&gt;&lt;span style="color:black;"&gt;Colors.LightGray } }&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;d&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;left &lt;/span&gt;&lt;span style="color:gray;"&gt;+ &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay &lt;/span&gt;&lt;span style="color:gray;"&gt;/ &lt;/span&gt;&lt;span style="color:black;"&gt;2 &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;8&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;d&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;15&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;d&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//if it is the first day of the month or the second day on the axis (because the first day may be&lt;br /&gt;&lt;br /&gt;//a partial and hence we won't see the value), write the month on the axis&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;i &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;1 &lt;/span&gt;&lt;span style="color:gray;"&gt;|| &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Day &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;      var tmonth &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;TextBlock { Text &lt;/span&gt;&lt;span style="color:blue;"&gt;= Enum&lt;/span&gt;&lt;span style="color:black;"&gt;.GetName&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:blue;"&gt;typeof&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;Months&lt;/span&gt;&lt;span style="color:gray;"&gt;), &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Month &lt;/span&gt;&lt;span style="color:gray;"&gt;- &lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;), &lt;/span&gt;&lt;span style="color:black;"&gt;FontSize &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;10&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeight &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;FontWeights.Bold&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;Foreground &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;SolidColorBrush { Color &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Colors.Gray } }&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Month &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;1&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;tmonth.Text &lt;/span&gt;&lt;span style="color:gray;"&gt;+&lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:darkred;"&gt;" " &lt;/span&gt;&lt;span style="color:gray;"&gt;+ &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Year&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;tmonth&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetTop&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;tmonth&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;2&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;tmonth&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Draw the vertical gridline on the plot canvas for the start of the day.&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;DrawGridLine&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//If the day is today, do some special stuff&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;if  &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.Date &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;DateTime.Now.Date&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;{&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//color the day in plot canvas&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;ColorColumn&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;, (&lt;/span&gt;&lt;span style="color:black;"&gt;Brush&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;Application.Current.Resources["TimeLineTodayColumn"]&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//Draw a colored rectangle on the axis that spans the entire day&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;var r &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;Rectangle&lt;br /&gt;&lt;br /&gt;      {&lt;br /&gt;&lt;br /&gt;      Height &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.ActualHeight&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Width &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Fill &lt;/span&gt;&lt;span style="color:blue;"&gt;= new &lt;/span&gt;&lt;span style="color:black;"&gt;SolidColorBrush { Color &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;Colors.Gray }&lt;/span&gt;&lt;span style="color:gray;"&gt;,&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Opacity &lt;/span&gt;&lt;span style="color:blue;"&gt;= &lt;/span&gt;&lt;span style="color:black;"&gt;.1&lt;br /&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;span style="color:gray;"&gt;;&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;Canvas.SetLeft&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;r&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;ToolTipService.SetToolTip&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;r&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:darkred;"&gt;"Today"&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;AxisCanvas.Children.Add&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;r&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color:green;"&gt;//if it is weekend and not today, color it differently.&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:blue;"&gt;else if &lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.DayOfWeek &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;DayOfWeek.Sunday &lt;/span&gt;&lt;span style="color:gray;"&gt;|| &lt;/span&gt;&lt;span style="color:black;"&gt;currentDate.DayOfWeek &lt;/span&gt;&lt;span style="color:blue;"&gt;== &lt;/span&gt;&lt;span style="color:black;"&gt;DayOfWeek.Saturday&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;ColorColumn&lt;/span&gt;&lt;span style="color:gray;"&gt;(&lt;/span&gt;&lt;span style="color:black;"&gt;left&lt;/span&gt;&lt;span style="color:gray;"&gt;, &lt;/span&gt;&lt;span style="color:black;"&gt;_widthOfADay&lt;/span&gt;&lt;span style="color:gray;"&gt;, (&lt;/span&gt;&lt;span style="color:black;"&gt;Brush&lt;/span&gt;&lt;span style="color:gray;"&gt;)&lt;/span&gt;&lt;span style="color:black;"&gt;Application.Current.Resources["TimeLineWeekendColumn"]&lt;/span&gt;&lt;span style="color:gray;"&gt;);&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;      AxisCanvas.UpdateLayout&lt;/span&gt;&lt;span style="color:gray;"&gt;();&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;span style="color:black;"&gt;}&lt;br /&gt;&lt;br /&gt;      &lt;/span&gt;&lt;/code&gt;&lt;br /&gt;Selection / deselection  are done by the TimeLine controls. Global deselection of timelines happens when user double-clicks outside a timeline. The timeline raises a GlobalDeselectRequested event, that gets handled by the visualizer. When a double-click happens inside a TimeLine, it raises an event, that causes the visualize to bundle up the datacontexts of all the selected timelines and pass them through in a DetailRequested event. This can be handled by the instatiating page, and do whatever it needs to do with the info.&lt;br /&gt;&lt;/timelinedata&gt;&lt;/timelinedata&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-4407316309015514175?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/4407316309015514175/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/08/timeline-visualizer-in-silverlightc_18.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4407316309015514175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/4407316309015514175'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/08/timeline-visualizer-in-silverlightc_18.html' title='A Timeline Visualizer in Silverlight/C#: Part 2'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3410915886830453368.post-6732963620998334576</id><published>2009-08-15T13:06:00.007-04:00</published><updated>2009-08-15T19:09:04.653-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Usercontrol'/><category scheme='http://www.blogger.com/atom/ns#' term='Data visualization'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>A Timeline Visualizer in Silverlight/C#: Part 1</title><content type='html'>I encountered a problem while developing an application for my current client: They needed to visualize a series of events on a timeline. Like a schedule or a Gantt chart. I couldn't find a canned solution for this, so I created one in Silverlight/C#. Ideally I want to create a templated control with declarative bindings, etc., but currently I just have it in the form of usercontrol. I figured it is still useful to share it here, since others will also have data that falls into this category, and could use ideas from this.&lt;br /&gt;&lt;br /&gt;Here is a sample of how the control can be used. There is a bunch of UI functionality like click &amp;amp; drag, select/unselect item, mousewheel zoom in/zoom out, doubleclick to raise 'getdetail' event, add new item, etc. For some reason, Mousewheel works only in IE and not in Firefox. It works everywhere when you run it locally. I suspect the disparity is because of some site weirdness; I am using MS's free 10G silverlight streaming space to host the app. If anybody has any ideas, please let me know.&lt;br /&gt;&lt;a target="new" href="http://silverlight.services.live.com/invoke/105917/TimeLine%20Visualizer%20Demo/iframe.html"&gt;http://silverlight.services.live.com/invoke/105917/TimeLine%20Visualizer%20Demo/iframe.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe width=100% height=500px src="http://silverlight.services.live.com/invoke/105917/TimeLine%20Visualizer%20Demo/iframe.html" scrolling="no" frameborder="1"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;You can get the entire solution from filefactory: &lt;a href="http://www.filefactory.com/file/ah13e8g/n/VisualTimelineDemo_zip"&gt;http://www.filefactory.com/file/ah13e8g/n/VisualTimelineDemo_zip&lt;/a&gt;.&lt;br /&gt;Now, for the code. We will start looking at this from the outside in.&lt;br /&gt;The relevant xaml in the page looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(204, 204, 204); padding: 0px; background: rgb(240, 240, 240) url(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif) repeat scroll 0% 0%; overflow: auto; font-family: arial; font-size: 12px; width: 99%; height: auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"&gt;&lt;code style="color: rgb(0, 0, 0);"&gt;   &amp;lt;Grid x:Name="LayoutRoot"&amp;gt;&lt;br /&gt;&amp;lt;Grid.RowDefinitions&amp;gt;&lt;br /&gt; &amp;lt;RowDefinition Height="Auto"/&amp;gt;&lt;br /&gt; &amp;lt;RowDefinition Height="*"/&amp;gt;&lt;br /&gt; &amp;lt;RowDefinition Height="Auto"/&amp;gt;&lt;br /&gt;&amp;lt;/Grid.RowDefinitions&amp;gt;&lt;br /&gt;&amp;lt;Border BorderBrush="#99000000" BorderThickness="1" CornerRadius="4,4,0,0" Margin="2" Grid.Row="0"&amp;gt;&lt;br /&gt;   &amp;lt;TextBlock TextWrapping="Wrap" Margin="4,0,2,0" Text="Click on an item to select, click again to deselect. Double-Click outside any item to deselect globally. Click and drag to move. Use Mousewheel to zoom in/out. Doubleclick to request details of selected timeline item(s)."/&amp;gt;&lt;br /&gt;&amp;lt;/Border&amp;gt;&lt;br /&gt;&amp;lt;local:TimeLineVisualizer Name="tl" Grid.Row="1"/&amp;gt;&lt;br /&gt;&amp;lt;Border BorderBrush="#99000000" BorderThickness="1" CornerRadius="0,0,4,4" Margin="2" Grid.Row="2"&amp;gt;&lt;br /&gt; &amp;lt;StackPanel Orientation="Horizontal" Margin="4"&amp;gt;&lt;br /&gt;   &amp;lt;TextBlock Margin="4,0,2,0" Text="TimeLine Item Name:"/&amp;gt;&lt;br /&gt;   &amp;lt;TextBox Name="ItemNameTextBox" Width="100"/&amp;gt;&lt;br /&gt;   &amp;lt;TextBlock Margin="4,0,2,0" Text="Start:"/&amp;gt;&lt;br /&gt;   &amp;lt;basics:DatePicker Name="StartDatePicker"/&amp;gt;&lt;br /&gt;   &amp;lt;TextBlock Margin="4,0,2,0" Text="End:"/&amp;gt;&lt;br /&gt;   &amp;lt;basics:DatePicker Name="EndDatePicker"/&amp;gt;&lt;br /&gt;   &amp;lt;Button Margin="4,0,4,0" Name="Btn_InsertTimeLine" Content="Add Item to TimeLine" Click="Button_Click"/&amp;gt;&lt;br /&gt; &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&amp;lt;/Border&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Class Diagram for TimeLineVisualizer:&lt;br /&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 339px; height: 348px;" src="http://3.bp.blogspot.com/_Pxh3z4pDSQc/SobrbxF7R6I/AAAAAAAADeo/2LJIXy5Majg/s400/TimelineVisualizerClassDiagram.png" alt="" id="BLOGGER_PHOTO_ID_5370238467953084322" border="0" /&gt;Here is the code-behind in the page that deals with TimeLineVisualizer events:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(204, 204, 204); padding: 0px; background: rgb(240, 240, 240) url(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif) repeat scroll 0% 0%; overflow: auto; font-family: arial; font-size: 12px; width: 99%; height: auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"&gt;&lt;code style="color: rgb(0, 0, 0);"&gt;     public Home()&lt;br /&gt;  {&lt;br /&gt;------&lt;br /&gt;    tl.TimeLineChanged += (s, e) =&amp;gt; SetTimeLineItemSource();&lt;br /&gt;    tl.DetailRequested += new EventHandler&amp;lt;DetailRequestedEventArgs&amp;gt;(tl_DetailRequested);&lt;br /&gt;  }&lt;br /&gt;  void tl_DetailRequested(object sender, DetailRequestedEventArgs e)&lt;br /&gt;  {&lt;br /&gt;    MessageBox.Show("'DetailRequested' event raised by TimeLine");&lt;br /&gt;  }&lt;br /&gt;  void Home_Loaded(object sender, RoutedEventArgs e)&lt;br /&gt;  {&lt;br /&gt;    SetTimeLineItemSource();&lt;br /&gt;  }&lt;br /&gt;  private void SetTimeLineItemSource()&lt;br /&gt;  {&lt;br /&gt;    tl.ItemsSource = from t in DataAccess.TimeLines&lt;br /&gt;             where ExtensionMethods.Intersects(t.Start, t.End, tl.StartDate.Value, tl.EndDate.Value)&lt;br /&gt;             select t;&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The “ExtensionMethods.Intersects” method justs tells you if 2 date ranges intersect:&lt;br /&gt;&lt;br /&gt;&lt;pre style="border: 1px dashed rgb(204, 204, 204); padding: 0px; background: rgb(240, 240, 240) url(http://2.bp.blogspot.com/_z5ltvMQPaa8/SjJXr_U2YBI/AAAAAAAAAAM/46OqEP32CJ8/s320/codebg.gif) repeat scroll 0% 0%; overflow: auto; font-family: arial; font-size: 12px; width: 99%; height: auto; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"&gt;&lt;code style="color: rgb(0, 0, 0);"&gt;     //not really an extension method&lt;br /&gt;   public static bool Intersects(DateTime r1Start, DateTime r1End, DateTime r2Start, DateTime r2End)&lt;br /&gt;   {&lt;br /&gt;     return (r1Start == r2Start) || (r1Start &amp;gt; r2Start ? r1Start &amp;lt;= r2End : r2Start &amp;lt;= r1End);&lt;br /&gt;   }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;In the next entry, we will look at the TimeLineVisualizer usercontrol.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3410915886830453368-6732963620998334576?l=codeforward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://codeforward.blogspot.com/feeds/6732963620998334576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://codeforward.blogspot.com/2009/08/timeline-visualizer-in-silverlightc.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/6732963620998334576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3410915886830453368/posts/default/6732963620998334576'/><link rel='alternate' type='text/html' href='http://codeforward.blogspot.com/2009/08/timeline-visualizer-in-silverlightc.html' title='A Timeline Visualizer in Silverlight/C#: Part 1'/><author><name>Jose</name><uri>http://www.blogger.com/profile/04599759019145570094</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Pxh3z4pDSQc/SobrbxF7R6I/AAAAAAAADeo/2LJIXy5Majg/s72-c/TimelineVisualizerClassDiagram.png' height='72' width='72'/><thr:total>13</thr:total></entry></feed>
