<?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-7059224265445023060</id><updated>2011-12-11T13:17:27.890Z</updated><category term='Sorting'/><category term='LINQ'/><category term='jQuery'/><category term='MultiBinding'/><category term='SQL'/><category term='Sandstorm'/><category term='RadioButton'/><category term='RememberThis'/><category term='.Net'/><category term='DataGrid'/><category term='Converters'/><category term='Triggers'/><category term='Formatting'/><category term='VisualTree'/><category term='Generics'/><category term='Focus'/><category term='C#'/><category term='Canvas'/><category term='VirtualizingPanel'/><category term='MVC3'/><category term='Constructor'/><category term='Collections'/><category term='Routed Commands'/><category term='3D'/><category term='Event Handlers'/><category term='WCF'/><category term='Resources'/><category term='Validation'/><category term='ComboBox'/><category term='Data Binding'/><category term='Exceptions'/><category term='WPF'/><title type='text'>The WPF Waltz</title><subtitle type='html'>One step forward, two steps back</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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>87</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7059224265445023060.post-8789074245412254967</id><published>2011-12-05T14:34:00.000Z</published><updated>2011-12-05T14:34:21.178Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='RadioButton'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>RadioButton groups</title><content type='html'>A workaround from Martin for RadioButton groups.&lt;br /&gt;&lt;br /&gt;There’s a bug in WPF (still) around RadioButton groups which doesn’t immediately manifest but will eventually seem to strike.&lt;br /&gt;&lt;br /&gt;There’s a slightly confusing summary of issues here : http://social.msdn.microsoft.com/forums/en-US/wpf/thread/8eb8280a-19c4-4502-8260-f74633a9e2f2/&lt;br /&gt;&lt;br /&gt;Suffice to say if you have 2 (or more) radio buttons and put them in the same group, they will reliably update each others status for a while as you’d expect.  At some point (in my case I found this reliably happens after changing Document tabs a few times, or going forwards &amp; back again in a Wizard workflow), the bindings stop working and you end up unable to check either RadioButton anymore.&lt;br /&gt;&lt;br /&gt;I’ve messed around with various approaches – a couple are suggested in the post above.&lt;br /&gt;The simplest option appears however to simply drop the GroupName=”x” from the XAML and simply do the “single-selection” logic yourself in the backing properties on your VM.&lt;br /&gt;&lt;br /&gt;i.e. :&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;RadioButton ssform:FormItem.LabelContent="{Binding Source={StaticResource ViewModel}, Path=Strings.V_Coupon, Mode=OneTime}"&lt;br /&gt;                            Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_eCoupon, Mode=OneTime}"&lt;br /&gt;                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"&lt;br /&gt;                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsECouponATrigger, Mode=TwoWay}" /&amp;gt;&lt;br /&gt;&amp;lt;RadioButton Content="{Binding Source={StaticResource ViewModel}, Path=Strings.V_PrintCoupon, Mode=OneTime}"&lt;br /&gt;                            IsEnabled="{Binding Source={StaticResource ViewModel}, Path=IsCouponATrigger}"&lt;br /&gt;                            IsChecked="{Binding Source={StaticResource ViewModel}, Path=IsPrintedCouponATrigger, Mode=TwoWay}" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;and&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public bool IsPrintedCouponATrigger&lt;br /&gt;{&lt;br /&gt;   get { return PromoBase.UIChoices.IsPrintedCouponATrigger; }&lt;br /&gt;   set&lt;br /&gt;   {&lt;br /&gt;      if (value != PromoBase.UIChoices.IsPrintedCouponATrigger)&lt;br /&gt;      {&lt;br /&gt;         PromoBase.UIChoices.IsPrintedCouponATrigger = value;&lt;br /&gt;         IsECouponATrigger = !value;&lt;br /&gt;         OnPropertyChanged("IsPrintedCouponATrigger");&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;public bool IsECouponATrigger&lt;br /&gt;{&lt;br /&gt;   get { return PromoBase.UIChoices.IsECouponATrigger; }&lt;br /&gt;   set&lt;br /&gt;   {&lt;br /&gt;      if (value != PromoBase.UIChoices.IsECouponATrigger)&lt;br /&gt;      {&lt;br /&gt;         PromoBase.UIChoices.IsECouponATrigger = value;&lt;br /&gt;         IsPrintedCouponATrigger = !value;&lt;br /&gt;         OnPropertyChanged("IsECouponATrigger");&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Note the check that the value has actually changed in the setter – without this, you get into a nice infinite loop of PropertyChange notifications as each changes the other in turn! &lt;br /&gt;&lt;br /&gt;Annoying bug, but simple enough to work around once you know about it..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8789074245412254967?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8789074245412254967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8789074245412254967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8789074245412254967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8789074245412254967'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/12/radiobutton-groups.html' title='RadioButton groups'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8554773963013132927</id><published>2011-12-03T20:07:00.001Z</published><updated>2011-12-03T20:22:07.490Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>3D VisualBrush and TextureCoordinates</title><content type='html'>This post starts with the last example from the 3D Towards a Solid post.&lt;br /&gt;The previous examples all used a single colour for the Material applied to a surface.&lt;br /&gt;This example replaces the Brush with a StackPanel containing a TextBlock and Button.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                        &amp;lt;VisualBrush&amp;gt;&lt;br /&gt;                           &amp;lt;VisualBrush.Visual&amp;gt;&lt;br /&gt;                              &amp;lt;StackPanel&amp;gt;&lt;br /&gt;                                 &amp;lt;TextBlock FontSize="10pt"&lt;br /&gt;                                            Margin="2"&amp;gt;Hello, from the Front!&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;                                 &amp;lt;Button Margin="2"&amp;gt;A Button&amp;lt;/Button&amp;gt;&lt;br /&gt;                              &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;                           &amp;lt;/VisualBrush.Visual&amp;gt;&lt;br /&gt;                        &amp;lt;/VisualBrush&amp;gt;&lt;br /&gt;                     &amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  -0.5, -0.5, 0.5  -0.5, 0.5, 0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;0.5, -0.5, -0.5  0.5, -0.5, 0.5  0.5, 0.5, 0.5  0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;At this point the front of the cube will be transparent and the TextBlock and Button will not appear. We need to add TextCoordinates to map the VisualBrush to the Mesh.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TextureCoordinates&amp;gt;0,1 1,1 1,0 0,0&amp;lt;/MeshGeometry3D.TextureCoordinates&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                        &amp;lt;VisualBrush&amp;gt;&lt;br /&gt;                           &amp;lt;VisualBrush.Visual&amp;gt;&lt;br /&gt;                              &amp;lt;StackPanel&amp;gt;&lt;br /&gt;                                 &amp;lt;TextBlock FontSize="10pt"&lt;br /&gt;                                            Margin="2"&amp;gt;Hello, from the Front!&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;                                 &amp;lt;Button Margin="2"&amp;gt;A Button&amp;lt;/Button&amp;gt;&lt;br /&gt;                              &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;                           &amp;lt;/VisualBrush.Visual&amp;gt;&lt;br /&gt;                        &amp;lt;/VisualBrush&amp;gt;&lt;br /&gt;                     &amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  -0.5, -0.5, 0.5  -0.5, 0.5, 0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;0.5, -0.5, -0.5  0.5, -0.5, 0.5  0.5, 0.5, 0.5  0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;To apply the texture to the "back" of the we need to "flip" the TextureCoordinates horizontally around the Y axis to match the way we previously changed the TriangleIndices.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TextureCoordinates&amp;gt;1,1 0,1 0,0 1,0&amp;lt;/MeshGeometry3D.TextureCoordinates&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                        &amp;lt;VisualBrush&amp;gt;&lt;br /&gt;                           &amp;lt;VisualBrush.Visual&amp;gt;&lt;br /&gt;                              &amp;lt;StackPanel&amp;gt;&lt;br /&gt;                                 &amp;lt;TextBlock FontSize="10pt"&lt;br /&gt;                                            Margin="2"&amp;gt;Hello, from the Back!&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;                                 &amp;lt;Button Margin="2"&amp;gt;A Button&amp;lt;/Button&amp;gt;&lt;br /&gt;                              &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;                           &amp;lt;/VisualBrush.Visual&amp;gt;&lt;br /&gt;                        &amp;lt;/VisualBrush&amp;gt;&lt;br /&gt;                     &amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TextureCoordinates&amp;gt;0,1 1,1 1,0 0,0&amp;lt;/MeshGeometry3D.TextureCoordinates&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                        &amp;lt;VisualBrush&amp;gt;&lt;br /&gt;                           &amp;lt;VisualBrush.Visual&amp;gt;&lt;br /&gt;                              &amp;lt;StackPanel&amp;gt;&lt;br /&gt;                                 &amp;lt;TextBlock FontSize="10pt"&lt;br /&gt;                                            Margin="2"&amp;gt;Hello, from the Front!&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;                                 &amp;lt;Button Margin="2"&amp;gt;A Button&amp;lt;/Button&amp;gt;&lt;br /&gt;                              &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;                           &amp;lt;/VisualBrush.Visual&amp;gt;&lt;br /&gt;                        &amp;lt;/VisualBrush&amp;gt;&lt;br /&gt;                     &amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  -0.5, -0.5, 0.5  -0.5, 0.5, 0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;0.5, -0.5, -0.5  0.5, -0.5, 0.5  0.5, 0.5, 0.5  0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8554773963013132927?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8554773963013132927/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8554773963013132927' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8554773963013132927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8554773963013132927'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/12/3d-visualbrush-and-texturecoordinates.html' title='3D VisualBrush and TextureCoordinates'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4399751319743845192</id><published>2011-12-03T11:53:00.000Z</published><updated>2011-12-03T11:53:11.239Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>3D Towards a Solid</title><content type='html'>This post starts with the last example from the 3D Rotation post. I want to add a second face of a cube, opposite the original surface. First add a Model3DGroup to contain all the GeometryModel3D elements that will form the cube.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And add the second surface exactly the same as the first but with the Z coordinates moved from -0.5 to +0.5.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We can now see two Maroon/Blue surfaces rotating but we always see the same colour for both surfaces. The original surface needs to point "out" from the centre of the cube. The easiest way would appear to be drawing the Triangles in a different order so their Normals are reversed. Swap 0 and 1, swap 2 and 3 in the TriangleIndices list.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Finally, add the remaining two vertical surfaces of the cube. The "left" surface uses the same TriangleIndices as the "front" whereas the "right" surface uses the same TriangleIndices as the "back".&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;Model3DGroup&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, +0.5  0.5, -0.5, +0.5  0.5, 0.5, +0.5  -0.5, 0.5, +0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  -0.5, -0.5, 0.5  -0.5, 0.5, 0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;0.5, -0.5, -0.5  0.5, -0.5, 0.5  0.5, 0.5, 0.5  0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;1 0 3 3 2 1&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;            &amp;lt;/Model3DGroup&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4399751319743845192?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4399751319743845192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4399751319743845192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4399751319743845192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4399751319743845192'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/12/3d-towards-solid.html' title='3D Towards a Solid'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5237923187727810734</id><published>2011-12-03T10:25:00.000Z</published><updated>2011-12-03T10:25:09.362Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>3D Rotation</title><content type='html'>This post starts with the simple 3D model example from the first 3D post but with the camera moved back to its original position.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We want to rotate the Model around the Y axis, represented by the "1" in the definition of AxisAngleRotation3D.Axis below. Because the Model has a negative Z coordinate (-0.5) the Z component will gradually increase until the angle of rotation is 180 degrees at which point the Z coordinate becomes 0.5. Because the Z coordinate is closer  to use the Model will appear larger. &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Starting with an Angle of 0 (zero) degrees gives the same result as previously. Increasing the Angle to more than 90 degrees the reverse side of the Model comes into view.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;                  &amp;lt;AxisAngleRotation3D&amp;gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;120&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The rotation can be animated by applying a DoubleAnimation to the RotateTransform.&lt;br /&gt;Reset the Angle to zero, name the AxisAngleRotation3D and add a Grid.Trigger to start the animation.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Transform&amp;gt;&lt;br /&gt;            &amp;lt;RotateTransform3D&amp;gt;&lt;br /&gt;               &amp;lt;RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;                  &amp;lt;AxisAngleRotation3D  x:Name="Rotate"&amp;gt;&lt;/font&gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Axis&amp;gt;0,1,0&amp;lt;/AxisAngleRotation3D.Axis&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;AxisAngleRotation3D.Angle&amp;gt;0&amp;lt;/AxisAngleRotation3D.Angle&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;                  &amp;lt;/AxisAngleRotation3D&amp;gt;&lt;br /&gt;               &amp;lt;/RotateTransform3D.Rotation&amp;gt;&lt;br /&gt;            &amp;lt;/RotateTransform3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Transform&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;   &amp;lt;Grid.Triggers&amp;gt;&lt;br /&gt;      &amp;lt;EventTrigger RoutedEvent="Grid.MouseDown"&amp;gt;&lt;br /&gt;         &amp;lt;BeginStoryboard&amp;gt;&lt;br /&gt;            &amp;lt;Storyboard&amp;gt;&lt;br /&gt;               &amp;lt;DoubleAnimation From="0"&lt;br /&gt;                                To="360"&lt;br /&gt;                                BeginTime="0:0:0"&lt;br /&gt;                                Duration="0:0:4"&lt;br /&gt;                                Storyboard.TargetName="Rotate"&lt;br /&gt;                                Storyboard.TargetProperty="Angle" /&amp;gt;&lt;br /&gt;            &amp;lt;/Storyboard&amp;gt;&lt;br /&gt;         &amp;lt;/BeginStoryboard&amp;gt;&lt;br /&gt;      &amp;lt;/EventTrigger&amp;gt;&lt;br /&gt;   &amp;lt;/Grid.Triggers&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5237923187727810734?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5237923187727810734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5237923187727810734' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5237923187727810734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5237923187727810734'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/12/3d-rotation.html' title='3D Rotation'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-9004058622854697770</id><published>2011-12-03T09:46:00.002Z</published><updated>2011-12-03T12:13:32.074Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>3D Foundations</title><content type='html'>To use 3D in WPF we need a minimum of an object, somewhere to draw it, a camera to see it and some light to illuminate the scene. Which in the following examples roughly correspond to GeometryModel3D, Viewport3D,  PerspectiveCamera and AmbientLight respectively.&lt;br /&gt;Starting with the Model and Viewport the bare minimum to describe a square is:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Each Mesh position is a triplet of X, Y and Z. Positive X is UP. Positive Y is RIGHT. Positive Z is OUT of the screen.&lt;br /&gt;The Mesh triplets are numbered from 0 (zero) starting in BottomLeft and working anti-clockwise.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;3 ------------ 2&lt;br /&gt;|              |&lt;br /&gt;|              |&lt;br /&gt;|              |&lt;br /&gt;0 ------------ 1&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;These form the indices used to cover the surface in triangles. Each triangle is drawn anti-clockwise to keep the "Normals" pointing in the same direction. I'm not going to mention Normals again.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;&lt;font color="red"&gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;The model has two surfaces and each can have its own material. The front surface, Material, has been coloured Maroon.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;         &lt;font color="red"&gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;At this point nothing can be seen on screen because there is no camera.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;         &lt;font color="red"&gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;At this point we should see a Black square which is the Maroon surface of the model in an unlit scene. Next we add some AmbientLight.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &lt;font color="red"&gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &lt;/font&gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;We should now be able to see a Maroon surface. The Model's reverse surface, BackMaterial, will be coloured Blue.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;      &lt;font color="red"&gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;&lt;/font&gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,-1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Finally, reposition the camera and the direction it is looking in order to see the other side of the model. We should now see the blue surface.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Grid Background="AliceBlue"&amp;gt;&lt;br /&gt;   &amp;lt;Viewport3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;GeometryModel3D&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;                  &amp;lt;MeshGeometry3D&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.Positions&amp;gt;-0.5, -0.5, -0.5  0.5, -0.5, -0.5  0.5, 0.5, -0.5  -0.5, 0.5, -0.5&amp;lt;/MeshGeometry3D.Positions&amp;gt;&lt;br /&gt;                     &amp;lt;MeshGeometry3D.TriangleIndices&amp;gt;0 1 2 2 3 0&amp;lt;/MeshGeometry3D.TriangleIndices&amp;gt;&lt;br /&gt;                  &amp;lt;/MeshGeometry3D&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Geometry&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.Material&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Maroon&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.Material&amp;gt;&lt;br /&gt;               &amp;lt;GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;                  &amp;lt;DiffuseMaterial&amp;gt;&lt;br /&gt;                     &amp;lt;DiffuseMaterial.Brush&amp;gt;Blue&amp;lt;/DiffuseMaterial.Brush&amp;gt;&lt;br /&gt;                  &amp;lt;/DiffuseMaterial&amp;gt;&lt;br /&gt;               &amp;lt;/GeometryModel3D.BackMaterial&amp;gt;&lt;br /&gt;            &amp;lt;/GeometryModel3D&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;ModelVisual3D&amp;gt;&lt;br /&gt;         &amp;lt;ModelVisual3D.Content&amp;gt;&lt;br /&gt;            &amp;lt;AmbientLight Color="White" /&amp;gt;&lt;br /&gt;         &amp;lt;/ModelVisual3D.Content&amp;gt;&lt;br /&gt;      &amp;lt;/ModelVisual3D&amp;gt;&lt;br /&gt;      &amp;lt;Viewport3D.Camera&amp;gt;&lt;br /&gt;         &amp;lt;PerspectiveCamera&amp;gt;&lt;br /&gt;      &lt;font color="red"&gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.LookDirection&amp;gt;0,0,1&amp;lt;/PerspectiveCamera.LookDirection&amp;gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.Position&amp;gt;0,0,-2&amp;lt;/PerspectiveCamera.Position&amp;gt;&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;            &amp;lt;PerspectiveCamera.FieldOfView&amp;gt;90&amp;lt;/PerspectiveCamera.FieldOfView&amp;gt;&lt;br /&gt;         &amp;lt;/PerspectiveCamera&amp;gt;&lt;br /&gt;      &amp;lt;/Viewport3D.Camera&amp;gt;&lt;br /&gt;   &amp;lt;/Viewport3D&amp;gt;&lt;br /&gt;&amp;lt;/Grid&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-9004058622854697770?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/9004058622854697770/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=9004058622854697770' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/9004058622854697770'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/9004058622854697770'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/12/3d.html' title='3D Foundations'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-6234827750034561858</id><published>2011-11-24T14:06:00.000Z</published><updated>2011-11-24T14:06:47.705Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>Null values passed via XML into a Stored Proc</title><content type='html'>If the XML that gets into your proc looks something like this:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;'&amp;lt;ArrayOfFeeSaveRequest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&amp;gt;&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;&amp;lt;RunNumber xsi:nil="true"&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Then you will not get nulls in the output from SELECT on the prepared document.&lt;br /&gt;You have to add '&amp;lt;root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/&amp;gt;’ onto the sp_xml_preparedocument command&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;EXEC sp_xml_preparedocument @XMLDoc OUTPUT,@XMLOtherFees,'&amp;lt;root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/&amp;gt;'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Then in your WITH you need something like this:&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;WITH  (&lt;br /&gt;                        FeeID INT,&lt;br /&gt;                        StartDate DATETIME,&lt;br /&gt;                        EndDate DATETIME 'EndDate[not(@xsi:nil = "true")]',   --ALLOW NULLS!!!!!!!!!!!&lt;br /&gt;                        RecurringOrSingleFlag BIT,&lt;br /&gt;                        TransactionTypeID INT,&lt;br /&gt;                        IsRepresentedFee BIT,&lt;br /&gt;                        HostFeeID NVARCHAR(40),&lt;br /&gt;                        Amount DECIMAL(18,4),&lt;br /&gt;                        Comments NVARCHAR(128),&lt;br /&gt;                        DirectDebitID INT&lt;br /&gt;                  )&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-6234827750034561858?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/6234827750034561858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=6234827750034561858' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6234827750034561858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6234827750034561858'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/11/null-values-passed-via-xml-into-stored.html' title='Null values passed via XML into a Stored Proc'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2231419278196404143</id><published>2011-11-22T13:46:00.000Z</published><updated>2011-11-22T13:46:29.191Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>ExecuteScalar</title><content type='html'>A tip from Si:&lt;br /&gt;I’m not sure if this has been mentioned before BUT did you know that the ExecuteScalar method on an SqlCommand will cheerfully truncate any string returned through it? That means that XML returned from a stored procedure say may or may not be cut in half depending on its size. The solution is to use the ExecuteXmlReader method instead. Details in this link &lt;a href="http://aspnetresources.com/blog/executescalar_truncates_xml"&gt;ExecuteScalar truncates&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2231419278196404143?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2231419278196404143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2231419278196404143' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2231419278196404143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2231419278196404143'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/11/executescalar.html' title='ExecuteScalar'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4428230465614603680</id><published>2011-09-30T16:46:00.001+01:00</published><updated>2011-09-30T16:50:05.196+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>SQL Output Parameter</title><content type='html'>I don't why but any SQL Parameters that are defined as outputs are not available until the SqlDataReader has been closed.&lt;br /&gt;So this works:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;SqlParameter reservationNumberParameter = new SqlParameter("@ReservationNumber", SqlDbType.NVarChar, 15);&lt;br /&gt;reservationNumberParameter.Direction = ParameterDirection.Output;&lt;br /&gt;command.Parameters.Add(reservationNumberParameter);&lt;br /&gt;&lt;br /&gt;reader = command.ExecuteReader();&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;font color="green"&gt;reader.Close();&lt;br /&gt;&lt;br /&gt;reservationNumber = Convert.ToString(reservationNumberParameter.Value);&lt;/font&gt;&lt;/strong&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Whereas this does not work:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;SqlParameter reservationNumberParameter = new SqlParameter("@ReservationNumber", SqlDbType.NVarChar, 15);&lt;br /&gt;reservationNumberParameter.Direction = ParameterDirection.Output;&lt;br /&gt;command.Parameters.Add(reservationNumberParameter);&lt;br /&gt;&lt;br /&gt;reader = command.ExecuteReader();&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;font color="red"&gt;reservationNumber = Convert.ToString(reservationNumberParameter.Value);&lt;br /&gt;&lt;br /&gt;reader.Close();&lt;/font&gt;&lt;/strong&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4428230465614603680?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4428230465614603680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4428230465614603680' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4428230465614603680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4428230465614603680'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/09/sql-output-parameter.html' title='SQL Output Parameter'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3574515433462017869</id><published>2011-08-22T16:11:00.003+01:00</published><updated>2011-08-22T16:12:55.534+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Formatting'/><title type='text'>DataGridTextColumn Text Alignment</title><content type='html'>&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;DataGridTextColumn.CellStyle&amp;gt;&lt;br /&gt;  &amp;lt;Style&amp;gt;&lt;br /&gt;    &amp;lt;Setter Property="FrameworkElement.HorizontalAlignment" Value="Right" /&amp;gt;&lt;br /&gt;  &amp;lt;/Style&amp;gt;&lt;br /&gt;&amp;lt;/DataGridTextColumn.CellStyle&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3574515433462017869?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3574515433462017869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3574515433462017869' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3574515433462017869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3574515433462017869'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/08/datagridtextcolumn-text-alignment.html' title='DataGridTextColumn Text Alignment'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7822110613802392659</id><published>2011-04-22T12:09:00.004+01:00</published><updated>2011-04-22T13:41:05.717+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC3'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jQuery Callbacks</title><content type='html'>A recent foray into jQuery land left me floundering with the callback syntax.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;$("#datepicker").datepicker(&lt;br /&gt;  {&lt;br /&gt;    // The CallBack argument is an anonymous function&lt;br /&gt;    onSelect: function(dateText, inst)&lt;br /&gt;    {&lt;br /&gt;      // This invokes the real function&lt;br /&gt;      &lt;span style="color: red;"&gt;myCallBackFunction(dateText, inst);&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;// This is the real function that will&lt;br /&gt;// be executed when the onSelect&lt;br /&gt;// invokes its Callback&lt;br /&gt;&lt;span style="color: red;"&gt;function myCallBackFunction(dateText,inst)&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;  $("#selectedDate").val(dateText);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;With a simple callback function the anonymous function can contain the processing.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;$("#datepicker").datepicker(&lt;br /&gt;  {&lt;br /&gt;    // The CallBack argument is an anonymous function&lt;br /&gt;    onSelect: function(dateText, inst)&lt;br /&gt;    {&lt;br /&gt;      &lt;span style="color: red;"&gt;$("#selectedDate").val(dateText);&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;);&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7822110613802392659?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7822110613802392659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7822110613802392659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7822110613802392659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7822110613802392659'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/04/jquery-callbacks.html' title='jQuery Callbacks'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2638045296445216628</id><published>2011-03-12T09:55:00.003Z</published><updated>2011-03-12T09:59:19.836Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='RememberThis'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><title type='text'>ResourceStrings Access Modifier</title><content type='html'>When a new Resource file is added to a project the Access Modifier defaults to Internal.&lt;br /&gt;&lt;br /&gt;There is a small combobox at the top of the Resource editor that allows it to be changed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2638045296445216628?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2638045296445216628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2638045296445216628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2638045296445216628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2638045296445216628'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/03/resourcestrings-access-modifier.html' title='ResourceStrings Access Modifier'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5523177514284326828</id><published>2011-03-10T09:08:00.004Z</published><updated>2011-03-10T13:41:50.355Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='RememberThis'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>COM Data Types</title><content type='html'>Data type conversions from COM to .Net&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;IDL Type&lt;/td&gt;&lt;td&gt;.NET Type&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;char&lt;/td&gt;&lt;td&gt;System.SByte&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;short&lt;/td&gt;&lt;td&gt;System.Int16&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;int, long, HRESULT and SCODE&lt;/td&gt;&lt;td&gt;System.Int32&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;int64&lt;/td&gt;&lt;td&gt;System.Int64&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;unsigned char&lt;/td&gt;&lt;td&gt;System.Byte&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;unsigned short&lt;/td&gt;&lt;td&gt;System.UInt16&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;unsigned int and unsigned long&lt;/td&gt;&lt;td&gt;System.UInt32&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;uint64&lt;/td&gt;&lt;td&gt;System.UInt64&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;float&lt;/td&gt;&lt;td&gt;System.Single&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;double&lt;/td&gt;&lt;td&gt;System.Double&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;BSTR, LPSTR and LPWSTR&lt;/td&gt;&lt;td&gt;System.String&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;VARIANT_BOOL&lt;/td&gt;&lt;td&gt;System.Boolean&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;DATE&lt;/td&gt;&lt;td&gt;System.DateTime&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;GUID&lt;/td&gt;&lt;td&gt;System.Guid&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;DECIMAL&lt;/td&gt;&lt;td&gt;System.Decimal&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;CURRENCY&lt;/td&gt;&lt;td&gt;System.Decimal&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;VARIANT&lt;/td&gt;&lt;td&gt;System.Object&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;IUnknown*&lt;/td&gt;&lt;td&gt;System.Object&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;IDispatch*&lt;/td&gt;&lt;td&gt;System.Object&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;void*&lt;/td&gt;&lt;td&gt;System.IntPtr&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;IDispatchEx*&lt;/td&gt;&lt;td&gt;System.Runtime.InteropServices.Expando.IExpando&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;IEnumVariant*&lt;/td&gt;&lt;td&gt;System.Collections.IEnumerator&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;COM&lt;/td&gt;&lt;td&gt;IDL&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;boolean and small&lt;/td&gt;&lt;td&gt;char&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;wchar_t&lt;/td&gt;&lt;td&gt;unsigned short&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;hyper and __int64&lt;/td&gt;&lt;td&gt;int64&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;[string] char*&lt;/td&gt;&lt;td&gt;LPSTR&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;[string] wchar_t*&lt;/td&gt;&lt;td&gt;LPWSTR&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;byte&lt;/td&gt;&lt;td&gt;unsigned char&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;unsigned hyper and unsigned __int64&lt;/td&gt;&lt;td&gt;uint64&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5523177514284326828?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5523177514284326828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5523177514284326828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5523177514284326828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5523177514284326828'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/03/com-data-types.html' title='COM Data Types'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-6786262734891617753</id><published>2011-02-16T07:37:00.004Z</published><updated>2011-05-14T06:26:42.237+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><category scheme='http://www.blogger.com/atom/ns#' term='Triggers'/><title type='text'>MouseOver Triggers</title><content type='html'>Here is a minimal example of changing the background colour of a TextBlock when MouseOver is detected.&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Window.Resources&amp;gt;&lt;br /&gt;    &amp;lt;Style TargetType="TextBlock"&amp;gt;&lt;br /&gt;        &amp;lt;Style.Triggers&amp;gt;&lt;br /&gt;            &amp;lt;Trigger Property="IsMouseOver" Value="True"&amp;gt;&lt;br /&gt;                &amp;lt;Setter Property="Background" Value="Pink" /&amp;gt;&lt;br /&gt;            &amp;lt;/Trigger&amp;gt;&lt;br /&gt;        &amp;lt;/Style.Triggers&amp;gt;&lt;br /&gt;    &amp;lt;/Style&amp;gt;&lt;br /&gt;&amp;lt;/Window.Resources&amp;gt;&lt;br /&gt;&amp;lt;StackPanel&amp;gt;&lt;br /&gt;    &amp;lt;TextBlock&amp;gt;Hello World&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;&amp;lt;/StackPanel&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-6786262734891617753?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/6786262734891617753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=6786262734891617753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6786262734891617753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6786262734891617753'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/02/mouseover-triggers.html' title='MouseOver Triggers'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3974393788184526995</id><published>2011-01-18T12:15:00.001Z</published><updated>2011-01-18T12:18:24.848Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><title type='text'>Moving down a cell in a datagrid when you press Enter</title><content type='html'>In Stock we have some DataGrids for things like Counts, which we want to be able to enter values for successive rows from the keyboard.. ie, 1 &lt;enter&gt;, 3 &lt;enter&gt; etc..&lt;br /&gt;&lt;br /&gt;While Tab moves across a cell, Enter doesn’t move the cell focus (since we’re using a custom control of a textbox in there, the textbox swallows the enter).&lt;br /&gt;&lt;br /&gt;To enable the Enter to work, you can just add a KeyDown handler for the TextBox in the template and then add this code behind :&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;      private void TextBox_KeyDown(object sender, KeyEventArgs e)&lt;br /&gt;      {&lt;br /&gt;         if ((e.Key == Key.Enter) || (e.Key == Key.Return))&lt;br /&gt;         {&lt;br /&gt;            TextBox FocusedControl = Keyboard.FocusedElement as TextBox;&lt;br /&gt;&lt;br /&gt;            if (FocusedControl != null)&lt;br /&gt;            {&lt;br /&gt;               TraversalRequest Traversal = new TraversalRequest(FocusNavigationDirection.Down);&lt;br /&gt;&lt;br /&gt;               FocusedControl.MoveFocus(Traversal);&lt;br /&gt;            }&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;Nice and simple in the end --- it turns out that the TraversalRequest and FocusNavigationDirection classes/enums are very simple and powerful &amp; not limited to DataGrids at all.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3974393788184526995?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3974393788184526995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3974393788184526995' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3974393788184526995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3974393788184526995'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/01/moving-down-cell-in-datagrid-when-you.html' title='Moving down a cell in a datagrid when you press Enter'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3549132372023199400</id><published>2011-01-10T12:04:00.005Z</published><updated>2011-01-12T13:01:43.244Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>ResourceStrings in XAML</title><content type='html'>I needed to replace some hard-coded text in the xaml templates used in our Till Roll control. There was no easy route through to a general ViewModel that could expose some relevant properties to bind to.&lt;br /&gt;In the end I chose to bind directly to the ResourceStrings resource using an x:Static &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;...&lt;br /&gt;xmlns:local="clr-namespace:Sandstorm.PointOfSale.Modules.Tender.Resources"&lt;br /&gt;...&lt;br /&gt;&amp;lt;TextBlock Padding="20,0,0,0" Text="{Binding Source={x:Static local:ResourceStrings.V_Discount}, Mode=OneTime}" FontStyle="Italic"/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3549132372023199400?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3549132372023199400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3549132372023199400' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3549132372023199400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3549132372023199400'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2011/01/resourcestrings-in-xaml.html' title='ResourceStrings in XAML'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7218418291446037121</id><published>2010-12-08T07:08:00.004Z</published><updated>2010-12-08T07:28:52.102Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>EditorBrowsable</title><content type='html'>The EditorBrowsableAttribute class specifies whether a property or method is viewable via Intellisense.&lt;br /&gt;It is used like this:&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;...&lt;br /&gt;[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]&lt;br /&gt;protected void AdvancedMethod()&lt;br /&gt;{&lt;br /&gt;//The property or method is a feature that only advanced users should see. An editor can either show or hide such properties&lt;br /&gt;}&lt;br /&gt;[EditorBrowsableAttribute(EditorBrowsableState.Always)]&lt;br /&gt;protected void AlwaysMethod()&lt;br /&gt;{&lt;br /&gt;//The property or method is always browsable from within an editor&lt;br /&gt;}&lt;br /&gt;[EditorBrowsableAttribute(EditorBrowsableState.Never)]&lt;br /&gt;protected void NeverMethod()&lt;br /&gt;{&lt;br /&gt;//The property or method is never browsable from within an editor&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;I wanted to use it with a class that provided a fluent interface to hide the common methods like Equals, GetHashCode, GetType, ToString etc. to make the fluent interface syntax cleaner.&lt;br /&gt;It transpires that it is only used by Intellisense when the decorated item is in a referenced assembly - shame.&lt;br /&gt;Here is the fuller explanation from Linda Lui, Microsoft Online Community Support back in June 2006:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Speaking for C#, the EditorBrowsableAttribute attribute only influences C# &lt;br /&gt;IntelliSense filtering behavior if the decorated item is imported from &lt;br /&gt;metadata. &lt;br /&gt;That's to say, you should compile the EditorBrowsableAttribute-decorated &lt;br /&gt;project(e.g project 1) into an assembly(.dll or .exe) and then in another &lt;br /&gt;project(e.g project 2) add a reference to that assembly.  In project 2, you &lt;br /&gt;should see the attribute at work. &lt;br /&gt;C# IntelliSense filtering behavior is not influenced if you are coding in &lt;br /&gt;project 1. What's more, if you add a project-to-project reference to &lt;br /&gt;project 1 in project 2, C# IntelliSense filtering behavior is not &lt;br /&gt;influenced when you are coding in project 2 either. &lt;br /&gt;The IDE is intended to filter items from consumers of your assembly and not &lt;br /&gt;to filter items from yourself as you code the assembly.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7218418291446037121?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7218418291446037121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7218418291446037121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7218418291446037121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7218418291446037121'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/12/editorbrowsable.html' title='EditorBrowsable'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-166373168204630288</id><published>2010-09-28T13:02:00.004+01:00</published><updated>2010-09-28T13:07:04.244+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>UpdateSourceTrigger in DataGrid</title><content type='html'>Inside a DataGrid, any control you add into a TemplateColumn which is bound TwoWay, used to use its default value of UpdateSourceTrigger, but the .NET 4 version of DataGrid overrides this by default to be Explicit.&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;DataGrid&amp;gt;&lt;br /&gt;  &amp;lt;DataGrid.Columns&amp;gt;&lt;br /&gt;    &amp;lt;DataGrid.TemplateColumn&amp;gt;&lt;br /&gt;      &amp;lt;DataTemplate&amp;gt;&lt;br /&gt;        &amp;lt;TextBox   Text={Binding MyProperty} /&amp;gt;&lt;br /&gt;&amp;lt;/.....&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This used to work just fine.. When the value in TextBox changed, it would update MyProperty when the textbox lost focus (this is the default value for a textbox of UpdateSourceTrigger).&lt;br /&gt;This no longer happens.&lt;br /&gt;We now need to explicitly set the UpdateSourceTrigger for all UI controls inside a DataGrid Template column which should be updating their underlying property store.&lt;br /&gt;&lt;br /&gt;Now becomes:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;    &amp;lt;TextBox   Text={Binding MyProperty, UpdateSourceTrigger=LostFocus} /&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-166373168204630288?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/166373168204630288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=166373168204630288' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/166373168204630288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/166373168204630288'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/09/updatesourcetrigger-in-datagrid.html' title='UpdateSourceTrigger in DataGrid'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4171908378082882702</id><published>2010-07-09T11:31:00.007+01:00</published><updated>2010-07-09T21:46:07.208+01:00</updated><title type='text'>XAML for non-UI data</title><content type='html'>I hadn't considered using XAML to describe non-UI data or using the XamlReader to load/parse a XML data file. This post is a simple step-by-step guide to defining a XAML model and the associated C# classes to load our StateMachine Maps.&lt;br /&gt;&lt;br /&gt;Starting with the bare minimum XAML and data class:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;MapLoader&lt;br /&gt;  xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;&amp;lt;/MapLoader&amp;gt;&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class MapLoader&lt;br /&gt;   {&lt;br /&gt;      public static MapLoader Load(string location)&lt;br /&gt;      {&lt;br /&gt;         return (MapLoader)XamlReader.Load(new XmlTextReader(location));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Adding a collection of States:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;MapLoader&lt;br /&gt;  xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;&lt;div style="color:red"&gt;&lt;br /&gt;  &amp;lt;MapLoader.States&amp;gt;&lt;br /&gt;    &amp;lt;State Name="Start"&amp;gt;&lt;br /&gt;    &amp;lt;/State&amp;gt;&lt;br /&gt;  &amp;lt;/MapLoader.States&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&amp;lt;/MapLoader&amp;gt;&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class MapLoader&lt;br /&gt;   {&lt;br /&gt;&lt;div style="color:red"&gt;      public StateList States { get; set; }&lt;br /&gt;&lt;br /&gt;      public MapLoader()&lt;br /&gt;      {&lt;br /&gt;         States = new StateList();&lt;br /&gt;      }&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;      public static MapLoader Load(string location)&lt;br /&gt;      {&lt;br /&gt;         return (MapLoader)XamlReader.Load(new XmlTextReader(location));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;div style="color:red"&gt;   [Serializable]&lt;br /&gt;   public class StateList : List&amp;lt;State&amp;gt; { }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class State&lt;br /&gt;   {&lt;br /&gt;      public string Name { get; set; }&lt;br /&gt;   }&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Each State has a collection of Events:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;MapLoader&lt;br /&gt;  xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;  &amp;lt;MapLoader.States&amp;gt;&lt;br /&gt;    &amp;lt;State Name="Start"&amp;gt;&lt;br /&gt;&lt;div style="color:red"&gt;&lt;br /&gt;      &amp;lt;State.Events&amp;gt;&lt;br /&gt;        &amp;lt;Event Name="OnGoToFirstPage" /&amp;gt;&lt;br /&gt;      &amp;lt;/State.Events&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;    &amp;lt;/State&amp;gt;&lt;br /&gt;  &amp;lt;/MapLoader.States&amp;gt;&lt;br /&gt;&amp;lt;/MapLoader&amp;gt;&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class MapLoader&lt;br /&gt;   {&lt;br /&gt;      public StateList States { get; set; }&lt;br /&gt;&lt;br /&gt;      public MapLoader()&lt;br /&gt;      {&lt;br /&gt;         States = new StateList();&lt;br /&gt;      }&lt;br /&gt;      public static MapLoader Load(string location)&lt;br /&gt;      {&lt;br /&gt;         return (MapLoader)XamlReader.Load(new XmlTextReader(location));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class StateList : List&amp;lt;State&amp;gt; { }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class State&lt;br /&gt;   {&lt;br /&gt;&lt;div style="color:red"&gt;      public string Name { get; set; }&lt;br /&gt;&lt;br /&gt;      public State()&lt;br /&gt;      {&lt;br /&gt;         Events = new EventList();&lt;br /&gt;      }&lt;/div&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;&lt;div style="color:red"&gt;   [Serializable]&lt;br /&gt;   public class EventList : List&amp;lt;Event&amp;gt; { }&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class Event&lt;br /&gt;   {&lt;br /&gt;      public string Name { get; set; }&lt;br /&gt;   }&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;By decorating the MapLoader and State classes with the [ContentProperty] attribute we avoid the need to explictly reference the collection classes:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;MapLoader&lt;br /&gt;  xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;&lt;div style="color:red"&gt;&lt;br /&gt;    &amp;lt;State Name="Start"&amp;gt;&lt;br /&gt;      &amp;lt;Event Name="OnGoToFirstPage"/&amp;gt;&lt;br /&gt;    &amp;lt;/State&amp;gt;&lt;br /&gt;    &amp;lt;State Name="FirstPage"&amp;gt;&lt;br /&gt;      &amp;lt;Event Name="OnGoToLastPage"/&amp;gt;&lt;br /&gt;      &amp;lt;Event Name="OnGoToMiddlePage"/&amp;gt;&lt;br /&gt;    &amp;lt;/State&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&amp;lt;/MapLoader&amp;gt;&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;&lt;div style="color:red"&gt;   [ContentProperty("States")]&lt;/div&gt;&lt;br /&gt;   public class MapLoader&lt;br /&gt;   {&lt;br /&gt;      public StateList States { get; set; }&lt;br /&gt;&lt;br /&gt;      public MapLoader()&lt;br /&gt;      {&lt;br /&gt;         States = new StateList();&lt;br /&gt;      }&lt;br /&gt;      public static MapLoader Load(string location)&lt;br /&gt;      {&lt;br /&gt;         return (MapLoader)XamlReader.Load(new XmlTextReader(location));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;&lt;div style="color:red"&gt;   [ContentProperty("Events")]&lt;/div&gt;&lt;br /&gt;   public class State&lt;br /&gt;   {&lt;br /&gt;      public string Name { get; set; }&lt;br /&gt;&lt;br /&gt;      public State()&lt;br /&gt;      {&lt;br /&gt;         Events = new EventList();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Final version with all the attributes defined for States and Events:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;MapLoader&lt;br /&gt;  xmlns="clr-namespace:DrawStateMachineMap;assembly=DrawStateMachineMap"&lt;br /&gt;  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&amp;gt;&lt;br /&gt;  &amp;lt;State Name="Start"&amp;gt;&lt;br /&gt;    &amp;lt;Event&lt;br /&gt;      Name="OnGoToFirstPage"&lt;br /&gt;      GotoState="FirstPage"&lt;br /&gt;      RunAction="DisplayFirstPage"&lt;br /&gt;      LayoutX="440"&lt;br /&gt;      LayoutY="120" /&amp;gt;&lt;br /&gt;  &amp;lt;/State&amp;gt;&lt;br /&gt;  &amp;lt;State&lt;br /&gt;    Name="FirstPage"&lt;br /&gt;    LayoutX="320"&lt;br /&gt;    LayoutY="200"&amp;gt;&lt;br /&gt;    &amp;lt;Event&lt;br /&gt;      Name="OnGoToLastPage"&lt;br /&gt;      GotoState="LastPage"&lt;br /&gt;      RunAction="DisplayLastPage"&lt;br /&gt;      LayoutX="660"&lt;br /&gt;      LayoutY="260" /&amp;gt;&lt;br /&gt;    &amp;lt;Event&lt;br /&gt;      Name="OnGoToMiddlePage"&lt;br /&gt;      GotoState="MiddlePage"&lt;br /&gt;      RunAction="DisplayMiddlePage"&lt;br /&gt;      LayoutX="440"&lt;br /&gt;      LayoutY="300" /&amp;gt;&lt;br /&gt;  &amp;lt;/State&amp;gt;&lt;br /&gt;&amp;lt;/MapLoader&amp;gt;&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   [ContentProperty("States")]&lt;br /&gt;   public class MapLoader&lt;br /&gt;   {&lt;br /&gt;      public StateList States { get; set; }&lt;br /&gt;&lt;br /&gt;      public MapLoader()&lt;br /&gt;      {&lt;br /&gt;         States = new StateList();&lt;br /&gt;      }&lt;br /&gt;      public static MapLoader Load(string location)&lt;br /&gt;      {&lt;br /&gt;         return (MapLoader)XamlReader.Load(new XmlTextReader(location));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   [ContentProperty("Events")]&lt;br /&gt;   public class State&lt;br /&gt;   {&lt;br /&gt;      public string Name { get; set; }&lt;br /&gt;      public int LayoutX { get; set; }&lt;br /&gt;      public int LayoutY { get; set; }&lt;br /&gt;      public EventList Events { get; set; }&lt;br /&gt;&lt;br /&gt;      public State()&lt;br /&gt;      {&lt;br /&gt;         Events = new EventList();&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class Event&lt;br /&gt;   {&lt;br /&gt;      public string Name { get; set; }&lt;br /&gt;      public string GotoState { get; set; }&lt;br /&gt;      public string RunAction { get; set; }&lt;br /&gt;      public int LayoutX { get; set; }&lt;br /&gt;      public int LayoutY { get; set; }&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class StateList : List&amp;lt;State&amp;gt; { }&lt;br /&gt;&lt;br /&gt;   [Serializable]&lt;br /&gt;   public class EventList : List&amp;lt;Event&amp;gt; { }&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4171908378082882702?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4171908378082882702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4171908378082882702' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4171908378082882702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4171908378082882702'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/07/xmlnsclr-namespacedrawstatemachinemapas.html' title='XAML for non-UI data'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7299578038335203331</id><published>2010-07-03T17:30:00.002+01:00</published><updated>2010-07-03T17:31:57.858+01:00</updated><title type='text'>Comparing equality of generic objects</title><content type='html'>&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;T value1;&lt;br /&gt;T value2;&lt;br /&gt;bool result = EqualityComparer&lt;TState&gt;.Default.Equals(value1, value2)&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7299578038335203331?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7299578038335203331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7299578038335203331' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7299578038335203331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7299578038335203331'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/07/comparing-equality-of-generic-objects.html' title='Comparing equality of generic objects'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4578299478185590827</id><published>2010-07-03T07:07:00.003+01:00</published><updated>2010-07-03T07:12:49.291+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='DataGrid'/><category scheme='http://www.blogger.com/atom/ns#' term='VirtualizingPanel'/><title type='text'>Martin's DataGrid VirtualizingPanel Epiphany</title><content type='html'>I have a View which looks a bit like this :&lt;br /&gt;&lt;br /&gt;&amp;lt;DataGrid ItemSource={BindingToSomethingWithManyHundredRows} /&amp;gt;&lt;br /&gt;&lt;br /&gt;Now, you probably know a little about Virtualizing Panels.. Basically.. Rather than try to draw all 800 rows immediately, it’ll create the UI Elements for the rows actually visible on the screen (and a few extra to smooth scrolling), and then only create others as they’re scrolled into the visible area.&lt;br /&gt;&lt;br /&gt;By default, DataGrid uses a VirtualizingPanel so all is happy and rendering takes about 0.3 secs.  If I explicitly use a non virtualizing layout panel to display the rows, it’ll take about 15 seconds, so we don’t like this much.&lt;br /&gt;&lt;br /&gt;Now.. I wanted to put a ComboBox above the DataGrid on the View, so while I was messing about with code I simply dropped a &lt;StackPanel&gt; around the pair and carried on.   So now I have :&lt;br /&gt;&lt;br /&gt;&amp;lt;StackPanel&amp;gt;&lt;br /&gt;   &amp;lt;ComboBox/&amp;gt;&lt;br /&gt;   &amp;lt;Grid/&amp;gt;&lt;br /&gt;&amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&lt;br /&gt;Now.. I’ve done this before and I know that doing this will switch off the scrollbar of the Grid because the stackpanel has told the grid that it has as much space as it needs (so the rows disappear off the bottom of the page with no way to scroll to them).. But I was only testing some code I was working on, so I didn’t care..&lt;br /&gt;&lt;br /&gt;What did surprise the heck out of me (which in hindsight it shouldn’t) is that it now took 15 seconds to render...   So what’s happening?  Well we’re still using a Virtualizing Panel, but it thinks all rows are visible because of the stackpanel, so it goes ahead and draws them all, even though they’re not actually visible..&lt;br /&gt;&lt;br /&gt;So.. I’ve replaced my StackPanel with a Grid and all is happy again... But, I figured it was a worthwhile point to mention for you all – you don’t want to put StackPanels around ItemsControls which would Virtualize the layout panel for you..  A) you’ll lose scrolling unless you jump through various hoops, but B) you’ll lose all the performance benefits of using a Virtualizing Panel..  Which can be very dramatic..&lt;br /&gt;&lt;br /&gt;Good luck &amp; may all your panels be virtualizing&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4578299478185590827?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4578299478185590827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4578299478185590827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4578299478185590827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4578299478185590827'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/07/martins-datagrid-virtualizingpanel.html' title='Martin&apos;s DataGrid VirtualizingPanel Epiphany'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2021782227276034999</id><published>2010-07-03T06:54:00.003+01:00</published><updated>2010-07-03T07:04:19.295+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='RememberThis'/><category scheme='http://www.blogger.com/atom/ns#' term='Sandstorm'/><title type='text'>Shell Skins</title><content type='html'>To allow different shells to have very different styles by default, (e.g. for Kiosks vs Management apps) the selection of the application skin file is made in Client\Sandstorm\Sandstorm\Views\app.xaml.cs. On startup it looks in the shell config file for a value called ShellSkin for its path to the skin xaml file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2021782227276034999?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2021782227276034999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2021782227276034999' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2021782227276034999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2021782227276034999'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/07/shell-skins.html' title='Shell Skins'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2057830803183650490</id><published>2010-06-05T22:05:00.008+01:00</published><updated>2010-06-06T09:21:26.198+01:00</updated><title type='text'>Linking TextBox Key Presses to a DelegateCommand</title><content type='html'>I needed to detect the &amp;lt;return&amp;gt; key being pressed in a TextBox. The original technique used a KeyPress event and a small event handler in the code-behind. Since we're using MVVM I wanted to replace the event handler with a DelegateCommand.&lt;br /&gt;This .Net 4 only solution binds the DelegateCommand to the Command property of a KeyBinding.&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:10px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;...&lt;br /&gt;KeyReturnCommand = new DelegateCommand&lt;string&gt;(ReturnKeyPressed);&lt;br /&gt;...&lt;br /&gt;public DelegateCommand&lt;string&gt; KeyReturnCommand { get; set; }&lt;br /&gt;private void ReturnKeyPressed(string text)&lt;br /&gt;{&lt;br /&gt;   MessageBox.Show(text);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:10px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&amp;lt;TextBox x:Name="SearchText" Width="100" Height="25"&amp;gt;&lt;br /&gt;   &amp;lt;TextBox.InputBindings&amp;gt;&lt;br /&gt;       &amp;lt;KeyBinding &lt;br /&gt;           Command="{Binding KeyReturnCommand}" &lt;br /&gt;           CommandParameter="{Binding ElementName=SearchText, Path=Text}"  &lt;br /&gt;           Key="Enter"/&amp;gt;&lt;br /&gt;   &amp;lt;/TextBox.InputBindings&amp;gt;&lt;br /&gt;&amp;lt;/TextBox&amp;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/7059224265445023060-2057830803183650490?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2057830803183650490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2057830803183650490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2057830803183650490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2057830803183650490'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/06/linking-textbox-key-presses-to.html' title='Linking TextBox Key Presses to a DelegateCommand'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4825898980514559542</id><published>2010-06-02T08:16:00.001+01:00</published><updated>2010-06-02T08:19:35.280+01:00</updated><title type='text'>Current Item Pointers</title><content type='html'>&lt;div dir="ltr"&gt;&lt;font color="#000000" face="Tahoma"&gt;&lt;font size="2"&gt;Views also support the notion of a current item. You can navigate through the objects in a collection view. As you navigate, you are moving an item pointer that allows you to retrieve the object  that exists at that particular location in the collection.&lt;/font&gt;&lt;/font&gt;&lt;/div&gt; &lt;div dir="ltr"&gt;&lt;font color="#000000" face="Tahoma"&gt;&amp;nbsp;&lt;/div&gt; &lt;div&gt; &lt;div dir="ltr"&gt; &lt;div class="subsection"&gt; &lt;p&gt;&lt;font size="2"&gt;Because WPF binds to a collection only by using a view (either a view you specify, or the collection's default view), all bindings to collections have a current item pointer. When binding to a view, the slash (&amp;quot;/&amp;quot;) character in a &lt;span&gt;&lt;span class="input"&gt;Path&lt;/span&gt;&lt;/span&gt; value designates the current item of the view.&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font size="2"&gt;&lt;/font&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;font size="2"&gt;In the following example, the data context is a collection view. The first line binds to the collection. The second line binds to the current item in the collection. The third line binds to the &lt;span class="code"&gt;Description&lt;/span&gt; property of the current item in the collection.&lt;/font&gt;&lt;/p&gt; &lt;div class="LW_CodeSnippetContainer"&gt;&lt;a name="CodeSpippet11"&gt;&lt;/a&gt; &lt;div class="LW_CodeSnippetContainerTabs"&gt; &lt;div class="LW_CodeSnippetContainerTabLeftActive cl_lw_codesnippet_lt_tab_active"&gt; &lt;font size="2"&gt;&lt;/font&gt;&lt;/div&gt; &lt;div class="LW_CodeSnippetToolBar"&gt; &lt;div class="LW_CodeSnippetToolBarText"&gt;&lt;a title="Copy to clipboard." href="UrlBlockedError.aspx" target="_blank"&gt;&lt;font color="#1364c4" size="2"&gt;&lt;/font&gt;&lt;/a&gt;&lt;/div&gt; &lt;/div&gt; &lt;div class="LW_CodeSnippetContainerTabActiveFirst"&gt;&lt;span style="COLOR: blue"&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;/span&gt;&amp;nbsp;&lt;/div&gt; &lt;div class="LW_CodeSnippetContainerTabActiveFirst"&gt;&lt;font size="2"&gt;&lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Button&lt;/span&gt; &lt;span style="COLOR: red"&gt;Content&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;{Binding }&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Button&lt;/span&gt; &lt;span style="COLOR: red"&gt; Content&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;{Binding Path=/}&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span style="COLOR: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="COLOR: #a31515"&gt;Button&lt;/span&gt; &lt;span style="COLOR: red"&gt; Content&lt;/span&gt;&lt;span style="COLOR: blue"&gt;=&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt;&lt;span style="COLOR: blue"&gt;{Binding Path=/Description}&lt;/span&gt;&lt;span style="COLOR: black"&gt;&amp;quot;&lt;/span&gt; &lt;span style="COLOR: blue"&gt;/&amp;gt;&lt;/span&gt; &lt;br /&gt; &lt;/font&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/div&gt; &lt;/font&gt;&lt;/div&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4825898980514559542?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4825898980514559542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4825898980514559542' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4825898980514559542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4825898980514559542'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/06/current-item-pointers.html' title='Current Item Pointers'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4160104726621735330</id><published>2010-06-02T08:12:00.003+01:00</published><updated>2010-06-02T08:15:52.541+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Debugging Bindings</title><content type='html'>I just want to keep track of this page to remind me how to get more information about a binding when debugging binding issues.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.presentationtracesources.tracelevel.aspx"&gt;PresentationTraceSources.TraceLevel&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4160104726621735330?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4160104726621735330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4160104726621735330' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4160104726621735330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4160104726621735330'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/06/debugging-bindings.html' title='Debugging Bindings'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-1172731065942003481</id><published>2010-05-10T09:49:00.008+01:00</published><updated>2010-05-10T15:30:49.522+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Canvas'/><title type='text'>Drawing WPF Curves with Arrow heads</title><content type='html'>Having drawn the shapes, the curves and found their intersection point, I finally needed to draw an arrow head. In order to draw the arrow at the right angle we need to know the tangent of the Bezier curve at the intersection point. Since that is beyond my maths capability I chose to find the intersection point between the line and an imaginary, slightly larger, rectangle that surrounds the target shape. The difference between the two intersection points provides the required angle for the arrow head.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private static void DrawArrowHead(Canvas canvas, PathGeometry linePath, Rect shapeRect, Color color)&lt;br /&gt;{&lt;br /&gt;   // Get the intersection point of the imaginary, slightly&lt;br /&gt;   // larger rectangle that surrounds the targer shape.&lt;br /&gt;   Rect outerRect = new Rect(shapeRect.Left - 10, shapeRect.Top - 10, shapeRect.Width + 20, shapeRect.Height + 20);&lt;br /&gt;&lt;br /&gt;   RectangleGeometry shapeGeometry = new RectangleGeometry(shapeRect);&lt;br /&gt;   Point[] intersectPoints = GetIntersectionPoints(linePath, shapeGeometry);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   double innerLeft = intersectPoints[0].X;&lt;br /&gt;   double innerTop = intersectPoints[0].Y;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   shapeGeometry = new RectangleGeometry(outerRect);&lt;br /&gt;   intersectPoints = GetIntersectionPoints(linePath, shapeGeometry);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   double outerLeft = intersectPoints[0].X;&lt;br /&gt;   double outerTop = intersectPoints[0].Y;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   Polygon arrowHead = new Polygon();&lt;br /&gt;   arrowHead.Points = new PointCollection();&lt;br /&gt;   arrowHead.Points.Add(new Point(innerLeft, innerTop));&lt;br /&gt;   arrowHead.Points.Add(new Point(innerLeft + 10, innerTop + 5));&lt;br /&gt;   arrowHead.Points.Add(new Point(innerLeft + 10, innerTop - 5));&lt;br /&gt;   arrowHead.Points.Add(new Point(innerLeft, innerTop));&lt;br /&gt;   arrowHead.Stroke = new SolidColorBrush(color);&lt;br /&gt;   arrowHead.Fill = new SolidColorBrush(color);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   // The differences between the intersection points on&lt;br /&gt;   // the inner and outer shapes gives us the base and&lt;br /&gt;   // perpendicular of the right-angled triangle&lt;br /&gt;   double baseSize = innerLeft - outerLeft;&lt;br /&gt;   double perpSize = innerTop - outerTop;&lt;br /&gt;   // Calculate the angle in degrees using ATan&lt;br /&gt;   double angle = Math.Atan(perpSize / baseSize) * 180 / Math.PI;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   // Rotate another 180 degrees for lines in the 3rd &amp; 4th quadrants&lt;br /&gt;   if (baseSize &gt;= 0) angle += 180;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   // Apply the rotation to the arrow head&lt;br /&gt;   RotateTransform rt = new RotateTransform(angle, innerLeft, innerTop);&lt;br /&gt;   arrowHead.RenderTransform = rt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   // Arrow heads are drawn over the lines but&lt;br /&gt;   // under the shapes&lt;br /&gt;   Canvas.SetZIndex(arrowHead, (int)Layer.Arrow);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   canvas.Children.Add(arrowHead);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-1172731065942003481?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/1172731065942003481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=1172731065942003481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1172731065942003481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1172731065942003481'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/05/drawing-wpf-curves-with-arrow-heads.html' title='Drawing WPF Curves with Arrow heads'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7630987966289350402</id><published>2010-05-10T09:43:00.002+01:00</published><updated>2010-05-10T09:47:29.051+01:00</updated><title type='text'>Drawing WPF Bezier Curves programmatically</title><content type='html'>I needed to draw a curved line between the mid-points of two shapes, centered on X1,Y1 and X2, Y2.&lt;br /&gt;This method also returns a PathGeometry which is then used to determine the Intersection between the curve and the shapes.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private static PathGeometry DrawLine(Canvas canvas, double X1, double Y1, double X2, double Y2, Color color)&lt;br /&gt;{&lt;br /&gt;   QuadraticBezierSegment qbs = new QuadraticBezierSegment(new Point(X2, Y1), new Point(X2, Y2), true);&lt;br /&gt;   &lt;br /&gt;   PathSegmentCollection pscollection = new PathSegmentCollection();&lt;br /&gt;   pscollection.Add(qbs);&lt;br /&gt;&lt;br /&gt;   PathFigure pf = new PathFigure();&lt;br /&gt;   pf.Segments = pscollection;&lt;br /&gt;   pf.StartPoint = new Point(X1, Y1);&lt;br /&gt;&lt;br /&gt;   PathFigureCollection pfcollection = new PathFigureCollection();&lt;br /&gt;   pfcollection.Add(pf);&lt;br /&gt;&lt;br /&gt;   PathGeometry pathGeometry = new PathGeometry();&lt;br /&gt;   pathGeometry.Figures = pfcollection;&lt;br /&gt;&lt;br /&gt;   Path path = new Path();&lt;br /&gt;   path.Data = pathGeometry;&lt;br /&gt;   path.Stroke = new SolidColorBrush(color);&lt;br /&gt;   path.StrokeThickness = 2;&lt;br /&gt;   Canvas.SetZIndex(path, (int)Layer.Line);&lt;br /&gt;   canvas.Children.Add(path);&lt;br /&gt;   &lt;br /&gt;   return pathGeometry;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7630987966289350402?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7630987966289350402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7630987966289350402' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7630987966289350402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7630987966289350402'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/05/drawing-wpf-bezier-curves.html' title='Drawing WPF Bezier Curves programmatically'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4602942548209739301</id><published>2010-05-10T09:36:00.002+01:00</published><updated>2010-05-10T09:41:06.491+01:00</updated><title type='text'>Intersection of two WPF geometries</title><content type='html'>I needed to determine the intersection point of a Rectangle and a Bezier curve. I found the following code &lt;a href="http://siphon9.net/loune/2009/08/getting-the-intersection-points-of-two-path-geometries-in-wpf/"&gt;here.&lt;/a&gt;&lt;br/&gt;&lt;br /&gt;I've included the code below in case the link is lost in the future.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public static Point[] GetIntersectionPoints(Geometry g1, Geometry g2)&lt;br /&gt;{&lt;br /&gt;   Geometry og1 = g1.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));&lt;br /&gt;   Geometry og2 = g2.GetWidenedPathGeometry(new Pen(Brushes.Black, 1.0));&lt;br /&gt;&lt;br /&gt;   CombinedGeometry cg = new CombinedGeometry(GeometryCombineMode.Intersect, og1, og2);&lt;br /&gt;   PathGeometry pg = cg.GetFlattenedPathGeometry();&lt;br /&gt;   Point[] result = new Point[pg.Figures.Count];&lt;br /&gt;&lt;br /&gt;   for (int i = 0; i &lt; pg.Figures.Count; i++)&lt;br /&gt;   {&lt;br /&gt;      Rect fig = new PathGeometry(new PathFigure[] { pg.Figures[i] }).Bounds;&lt;br /&gt;      result[i] = new Point(fig.Left + fig.Width / 2.0, fig.Top + fig.Height / 2.0);&lt;br /&gt;   }&lt;br /&gt;   return result;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4602942548209739301?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4602942548209739301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4602942548209739301' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4602942548209739301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4602942548209739301'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/05/intersection-of-two-wpf-geometries.html' title='Intersection of two WPF geometries'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2879482587655044860</id><published>2010-05-10T09:18:00.002+01:00</published><updated>2010-05-10T09:22:36.354+01:00</updated><title type='text'>Canvas</title><content type='html'>I think this is about the minimum you need to draw a shape on a Canvas programmatically.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Window x:Class="DrawStateMachineMap.Window2"&lt;br /&gt;    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;    Title="Window2" Height="300" Width="300"&amp;gt;&lt;br /&gt;    &amp;lt;Grid&amp;gt;&lt;br /&gt;      &amp;lt;Canvas Name="MainCanvas"&amp;gt;&amp;lt;/Canvas&amp;gt;&lt;br /&gt;   &amp;lt;/Grid&amp;gt;&lt;br /&gt;&amp;lt;/Window&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;      public Window2()&lt;br /&gt;      {&lt;br /&gt;         InitializeComponent();&lt;br /&gt;&lt;br /&gt;         Rectangle aRectangle = new Rectangle();&lt;br /&gt;         aRectangle.Width = 100;&lt;br /&gt;         aRectangle.Height = 50;&lt;br /&gt;         aRectangle.Stroke = Brushes.Red;&lt;br /&gt;&lt;br /&gt;         Canvas.SetLeft(aRectangle, 10);&lt;br /&gt;         Canvas.SetTop(aRectangle, 15);&lt;br /&gt;&lt;br /&gt;         MainCanvas.Children.Add(aRectangle);&lt;br /&gt;      }&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2879482587655044860?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2879482587655044860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2879482587655044860' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2879482587655044860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2879482587655044860'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/05/canvas.html' title='Canvas'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-176835114916812164</id><published>2010-05-08T08:54:00.002+01:00</published><updated>2010-05-08T09:01:00.548+01:00</updated><title type='text'>Loading XML documents stored in the Output directory</title><content type='html'>I wanted to load an XML document that is distributed with my project.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;// Load the XML State Transition Map&lt;br /&gt;XmlDocument xmlStateMap = new XmlDocument();&lt;br /&gt;xmlStateMap.Load(stateMapName);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I set the Copy to Output Directory property of the XML file to "Copy always". However the file never appeared in bin\debug. I also had to change the Build Action property from the default value of "Resource" to "Content" .&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-176835114916812164?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/176835114916812164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=176835114916812164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/176835114916812164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/176835114916812164'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2010/05/loading-xml-documents-stored-in-output.html' title='Loading XML documents stored in the Output directory'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4622453595044451042</id><published>2009-08-20T12:52:00.007+01:00</published><updated>2009-08-20T13:04:28.110+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><title type='text'>How to set a property to a DynamicResource reference in code</title><content type='html'>We recently needed to create a control in code and apply a style. The best reference I could find was this one at Josh Smith's blog: &lt;a href="http://joshsmithonwpf.wordpress.com/2007/06/29/how-to-set-a-property-to-a-dynamicresource-reference-in-code/"&gt;How to set a property to a DynamicResource reference in code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Our own example in XAML and C# looked like this:&lt;br /&gt;&lt;div class="mycode"&gt;&amp;lt;ItemsControl Style="{DynamicResource &lt;strong&gt;POSDatesTimesButtonItemsControlStyle&lt;/strong&gt;}"&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="mycode"&gt;FrameworkElementFactory itemsControlElement = new FrameworkElementFactory(typeof(ItemsControl));&lt;br /&gt;itemsControlElement.SetResourceReference(ItemsControl.StyleProperty,&lt;br /&gt; &lt;strong&gt;"POSDatesTimesButtonItemsControlStyle"&lt;/strong&gt;);&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4622453595044451042?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4622453595044451042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4622453595044451042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4622453595044451042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4622453595044451042'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/08/how-to-set-property-to-dynamicresource.html' title='How to set a property to a DynamicResource reference in code'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3945216171636020594</id><published>2009-07-27T14:17:00.004+01:00</published><updated>2009-08-06T11:08:27.935+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><title type='text'>Syncronous ProgressBar status updates</title><content type='html'>Within our application we make calls to server services both synchronously and asynchronously. There are some service calls that we want to make synchronously and still be able to show the progress bar if the process is lengthy. The existing progress bar was on the UI thread and therefore never updated until the service call completed. Martin has upgraded the progress bar to overcome this limitation.&lt;br /&gt;&lt;br /&gt;Within each DocumentViewModel, there is an internal reference counter (held in the AbstractDocumentViewModel) which keeps track of how many things are currently in progress for that document.&lt;br /&gt;When this counter &gt; 0, the progress bar (or spinning busy graphic) is shown on that document.&lt;br /&gt; &lt;br /&gt;In order to notify it that something is in progress (usually a service call or something which will take a detectable period of time to complete), within your DocumentViewModel class, you can call :&lt;br /&gt;&lt;div class="mycode"&gt;ProgressBarToggle(true);&lt;/div&gt; &lt;br /&gt;And to notify that this action is finished with : &lt;br /&gt;&lt;div class="mycode"&gt;ProgressBarToggle(false);&lt;/div&gt; &lt;br /&gt;The method ProgressBarToggle, is threadsafe and may be called on any thread.  If it is called on the UI thread in direct response to a UI event such as a button click, then the method will take care of the fact that the UI would normally not update the progress bar visibility until the event handling method was complete &amp; fork the thread to handle outstanding UI messages and binding updates, before continuing on with the functionality of the event handling method.  In effect a VB-style “DoEvents” under the covers.&lt;br /&gt; &lt;br /&gt;[Note : This has been added to the fledgling developer document in sharepoint : &lt;br /&gt;.../Leisureflexdotnet/Design%2Documents/Forms/AllItems.aspx/“Sandstorm Developer Notes Braindump.docx”]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3945216171636020594?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3945216171636020594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3945216171636020594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3945216171636020594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3945216171636020594'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/07/syncronous-progressbar-status-updates.html' title='Syncronous ProgressBar status updates'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-1098177950820411628</id><published>2009-07-27T13:49:00.003+01:00</published><updated>2009-07-27T13:53:10.222+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RememberThis'/><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>WCF Fault Exception</title><content type='html'>Martin had an obscure problem with WCF on our Fitspace / Fitness First Widget.&lt;br /&gt;&lt;br /&gt;This article describes a similar issue &lt;a href="http://www.softinsight.com/bnoyes/2009/07/23/ObscureWCFExceptionNdashMislaidBlame.aspx"&gt;Obscure WCF Exception mislaid blame&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-1098177950820411628?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/1098177950820411628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=1098177950820411628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1098177950820411628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1098177950820411628'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/07/wcf-fault-exception.html' title='WCF Fault Exception'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3719381489276356886</id><published>2009-07-15T15:17:00.006+01:00</published><updated>2009-07-29T08:04:24.955+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Formatting'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Databinding and Nullable Types</title><content type='html'>In this article (&lt;a href="http://karlshifflett.wordpress.com/2008/12/16/using-wpf-binding-stringformat-property-with-nullable-types/"&gt;Using WPF Binding StringFormat property with nullable types&lt;/a&gt;) Karl Shifflett describes how to bind to properties that have a nullable type.&lt;br /&gt;&lt;br /&gt;In summary, use TargetNullValue property of the binding like this:&lt;br /&gt;&lt;div class="mycode"&gt;&amp;lt;TextBox&lt;br /&gt;   Text="{Binding Path=NumberOfComputers,&lt;br /&gt;         &lt;strong&gt;TargetNullValue={x:Static sys:String.Empty},&lt;/strong&gt;&lt;br /&gt;         StringFormat=\{0:D\}}" /&amp;gt;&lt;/div&gt;&lt;br /&gt;TargetNullValue requires .NET 3.5 Framework Service Pack 1. Previously this would have required a IValueConverter class to deal with the Null values.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3719381489276356886?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3719381489276356886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3719381489276356886' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3719381489276356886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3719381489276356886'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/07/databinding-and-nullable-types.html' title='Databinding and Nullable Types'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7285373954841840632</id><published>2009-07-15T14:49:00.004+01:00</published><updated>2009-07-15T14:55:55.339+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Sorting Arrays</title><content type='html'>Martin pointed me at this interesting blog regarding Array.Sort &lt;a href="http://blogs.vbcity.com/xtab/archive/2009/07/06/9352.aspx"&gt;Sorting Arrays&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I used Array.Sort previously in this post &lt;a href="http://mikestedman.blogspot.com/2009/01/sorting-and-de-duping-arrays.html"&gt;Sorting and De-Duping Arrays&lt;/a&gt; but didn't investigate further at that time.&lt;br /&gt;&lt;br /&gt;A quick look at Array.Sort(...) shows that it has 17 overloads and lots of things to try out at some point in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7285373954841840632?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7285373954841840632/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7285373954841840632' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7285373954841840632'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7285373954841840632'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/07/sorting-arrays.html' title='Sorting Arrays'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2012586058527151378</id><published>2009-07-14T15:24:00.011+01:00</published><updated>2009-07-29T13:16:40.480+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ComboBox'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Parameter Ordering</title><content type='html'>Although the two ComboBox samples below look very similar they actually function a little differently.&lt;br /&gt;The first sample sets the selected item based on the SelectedItem binding and then almost instantaneously sets the SelectedItem based on the first record in the ItemsSource binding. &lt;br /&gt;&lt;div class="mycode"&gt;&amp;lt;ComboBox&lt;br /&gt;   DisplayMemberPath="Description"  &lt;br /&gt;   &lt;strong&gt;SelectedItem="{Binding Path=EditedCourse.Centre, Mode=TwoWay}"&lt;/strong&gt;             &lt;br /&gt;   SSForm:FormItem.LabelContent="Centre"&lt;br /&gt;   IsEditable="{Binding Path=EditedCourse.IsCentreEditable}"&amp;gt;&lt;br /&gt;   &amp;lt;ComboBox.ItemsSource&amp;gt;&lt;br /&gt;      &amp;lt;Binding&lt;br /&gt;        Mode="OneWay"&amp;gt;&lt;br /&gt;        &amp;lt;Binding.Source&amp;gt;&lt;br /&gt;          &amp;lt;CollectionViewSource&lt;br /&gt;                x:Name="PART_CentresView"&lt;br /&gt;                Source="{Binding Source={StaticResource ViewModel}, Path=Centres, Mode=OneWay}" /&amp;gt;&lt;br /&gt;        &amp;lt;/Binding.Source&amp;gt;&lt;br /&gt;      &amp;lt;/Binding&amp;gt;&lt;br /&gt;   &amp;lt;/ComboBox.ItemsSource&amp;gt;                            &lt;br /&gt;&amp;lt;/ComboBox&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The second sample sets the selected item based on the SelectedItem binding only and therefore does what I would have expected to happen from the first sample.&lt;br /&gt;&lt;div class="mycode"&gt;&amp;lt;ComboBox&lt;br /&gt;    DisplayMemberPath="Description"               &lt;br /&gt;    SSForm:FormItem.LabelContent="Centre"&lt;br /&gt;    IsEditable="{Binding Path=EditedCourse.IsCentreEditable}"&amp;gt;&lt;br /&gt;    &amp;lt;ComboBox.ItemsSource&amp;gt;&lt;br /&gt;        &amp;lt;Binding&lt;br /&gt;           Mode="OneWay"&amp;gt;&lt;br /&gt;           &amp;lt;Binding.Source&amp;gt;&lt;br /&gt;             &amp;lt;CollectionViewSource&lt;br /&gt;                x:Name="PART_CentresView"&lt;br /&gt;                Source="{Binding Source={StaticResource ViewModel}, Path=Centres, Mode=OneWay}" /&amp;gt;&lt;br /&gt;                &amp;lt;/Binding.Source&amp;gt;&lt;br /&gt;        &amp;lt;/Binding&amp;gt;&lt;br /&gt;    &amp;lt;/ComboBox.ItemsSource&amp;gt;               &lt;br /&gt;    &lt;strong&gt;&amp;lt;ComboBox.SelectedItem&amp;gt;&lt;br /&gt;       &amp;lt;Binding&lt;br /&gt;          Path="EditedCourse.Centre"&lt;br /&gt;          Mode="TwoWay" /&amp;gt;&lt;br /&gt;    &amp;lt;/ComboBox.SelectedItem&amp;gt;&lt;/strong&gt;               &lt;br /&gt;&amp;lt;/ComboBox&amp;gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The implication is that the selected item is not necessarily what you would expect it to be. &lt;br /&gt; &lt;br /&gt;In the first sample, the final selected item is the first (default) entry in the item source collection, and in the second sample the final selected item is the item bound to in the SelectedItem property.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2012586058527151378?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2012586058527151378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2012586058527151378' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2012586058527151378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2012586058527151378'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/07/parameter-ordering.html' title='Parameter Ordering'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3736248098602264057</id><published>2009-04-16T10:07:00.002+01:00</published><updated>2009-04-16T11:36:15.567+01:00</updated><title type='text'>Regex</title><content type='html'>For some unknown reason people use Regex.&lt;br /&gt;&lt;br /&gt;This is a useful link with examples from O'Reilly: &lt;a href="http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html"&gt;Regex 101&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3736248098602264057?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3736248098602264057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3736248098602264057' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3736248098602264057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3736248098602264057'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/04/regex.html' title='Regex'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7620285390307180093</id><published>2009-04-06T16:48:00.003+01:00</published><updated>2009-04-06T17:20:01.577+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Constructor'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Constructors</title><content type='html'>It became apparent the other day that I'd either forgotten some stuff about constructors or never knew it in the first place.&lt;br /&gt;&lt;br /&gt;This web page has a good explanation of all the issues: &lt;a href="http://www.yoda.arachsys.com/csharp/constructors.html"&gt;Constructors&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For example, what I hadn't really considered is that:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class MySimpleClass&lt;br /&gt;{&lt;br /&gt;    public MySimpleClass()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;is converted by the compiler into:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class MySimpleClass&lt;br /&gt;{&lt;br /&gt;    public MySimpleClass() : base()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/code&gt;which makes a bunch of stuff easier to understand.&lt;br /&gt;&lt;br /&gt;Similarly 'this' can be used to invoke constructors in the same class:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class MySimpleClass : MyBaseClass&lt;br /&gt;{&lt;br /&gt;    public MySimpleClass() : this(5)&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    public MySimpleClass(int x) : base(x)&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7620285390307180093?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7620285390307180093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7620285390307180093' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7620285390307180093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7620285390307180093'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/04/constructors.html' title='Constructors'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-991713507301980068</id><published>2009-04-06T15:56:00.004+01:00</published><updated>2009-04-06T16:34:11.820+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>DataTemplateSelector</title><content type='html'>On our till roll I want to display each different category of product using a specific DataTemplate.&lt;br /&gt;&lt;br /&gt;We start by defining the DataTemplates to be used in the usual way:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14pxcolor:#000000;" &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:red;"&gt; x&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:red;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;="listBookingTemplate"&amp;gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:red;"&gt; x&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:red;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;="listCCardTemplate"&amp;gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:red;"&gt; x&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:red;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;="listCashTemplate"&amp;gt;...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:red;"&gt; x&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:red;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;="listDefaultTemplate"&amp;gt;...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then the DataTemplateSelector which is the link between the xaml DataTemplates and the C# class (TillRollTemplateSelector) that determines which template to use:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5pxfont-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ss&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:#a31515;"&gt;TillRollTemplateSelector&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:red;"&gt; BookingTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; listBookingTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;}"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:red;"&gt; CCardTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; listCCardTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;}"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:red;"&gt; CashTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; listCashTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;}"&lt;/span&gt;  &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:red;"&gt; DefaultTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; listDefaultTemplate&lt;/span&gt;&lt;span style="color:blue;"&gt;}"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:red;"&gt; x&lt;/span&gt;&lt;span style="color:blue;"&gt;:&lt;/span&gt;&lt;span style="color:red;"&gt;Key&lt;/span&gt;&lt;span style="color:blue;"&gt;="tillTemplateSelector" /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then we need to wire up the template selector resource (tillTemplateSelector) to the ListBox that will display the data:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5pxfont-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#a31515;"&gt;ListBox&lt;/span&gt;&lt;span style="color:red;"&gt; Name&lt;/span&gt;&lt;span style="color:blue;"&gt;="theTillRoll"&lt;/span&gt;&lt;span style="color:red;"&gt; Height&lt;/span&gt;&lt;span style="color:blue;"&gt;="250"&lt;/span&gt;&lt;span style="color:red;"&gt; Width&lt;/span&gt;&lt;span style="color:blue;"&gt;="330"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;  &lt;span style="color:red;"&gt; ItemsSource&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;Binding&lt;/span&gt;&lt;span style="color:red;"&gt; Source&lt;/span&gt;&lt;span style="color:blue;"&gt;={&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; ViewModel&lt;/span&gt;&lt;span style="color:blue;"&gt;},&lt;/span&gt;&lt;span style="color:red;"&gt; Path&lt;/span&gt;&lt;span style="color:blue;"&gt;=SaleItems}"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;  &lt;span style="color:red;"&gt; ItemTemplateSelector&lt;/span&gt;&lt;span style="color:blue;"&gt;="{&lt;/span&gt;&lt;span style="color:#a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color:red;"&gt; tillTemplateSelector&lt;/span&gt;&lt;span style="color:blue;"&gt;}"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;  &lt;span style="color:blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Finally, we define the C# class:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5pxfont-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;TillRollTemplateSelector&lt;/span&gt; : &lt;span style="color:#2b91af;"&gt;DataTemplateSelector&lt;/span&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;DataTemplate&lt;/span&gt; BookingTemplate { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;DataTemplate&lt;/span&gt; CashTemplate { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;DataTemplate&lt;/span&gt; CCardTemplate { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;DataTemplate&lt;/span&gt; DefaultTemplate { &lt;span style="color:blue;"&gt;get&lt;/span&gt;; &lt;span style="color:blue;"&gt;set&lt;/span&gt;; }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;override&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;DataTemplate&lt;/span&gt; SelectTemplate(&lt;span style="color:blue;"&gt;object&lt;/span&gt; item, &lt;span style="color:#2b91af;"&gt;DependencyObject&lt;/span&gt; container)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   {&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;      &lt;span style="color:blue;"&gt;if&lt;/span&gt; (item &lt;span style="color:blue;"&gt;is&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;BookingLineItem&lt;/span&gt;) &lt;span style="color:blue;"&gt;return&lt;/span&gt; BookingTemplate;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;      &lt;span style="color:blue;"&gt;if&lt;/span&gt; (item &lt;span style="color:blue;"&gt;is&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;CashPaymentLineItem&lt;/span&gt;) &lt;span style="color:blue;"&gt;return&lt;/span&gt; CashTemplate;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;      &lt;span style="color:blue;"&gt;if&lt;/span&gt; (item &lt;span style="color:blue;"&gt;is&lt;/span&gt; &lt;span style="color:#2b91af;"&gt;CCardPaymentLineItem&lt;/span&gt;) &lt;span style="color:blue;"&gt;return&lt;/span&gt; CCardTemplate;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;      &lt;span style="color:blue;"&gt;return&lt;/span&gt; DefaultTemplate;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   }&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The object item passed to the SelectTemplate method is of the same type as bound to the ListBox via the ItemsSource.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-991713507301980068?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/991713507301980068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=991713507301980068' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/991713507301980068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/991713507301980068'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/04/datatemplateselector.html' title='DataTemplateSelector'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3804252173720428114</id><published>2009-04-06T15:41:00.004+01:00</published><updated>2011-03-02T22:13:33.617Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='MultiBinding'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>MultiBinding</title><content type='html'>I wanted to control the IsEnabled property of a Button based on the properties of two other controls.&lt;br /&gt;Specifically I wanted to only enable the LogIn button if both the Site combobox and UserName textbox had a value available.&lt;br /&gt;&lt;br /&gt;I created a MultiBinding for the Button like this:&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white; font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee; font-size: 12px; border: 1px dashed #999999; line-height: 14px; padding: 5px; overflow: auto;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Button.IsEnabled&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #a31515;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;MultiBinding&lt;/span&gt;&lt;span style="color: red;"&gt; Converter&lt;/span&gt;&lt;span style="color: blue;"&gt;=&amp;quot;{&lt;/span&gt;&lt;span style="color: #a31515;"&gt;StaticResource&lt;/span&gt;&lt;span style="color: red;"&gt; loginConverter&lt;/span&gt;&lt;span style="color: blue;"&gt;}&amp;quot;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #a31515;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Binding&lt;/span&gt;&lt;span style="color: red;"&gt; ElementName&lt;/span&gt;&lt;span style="color: blue;"&gt;=&amp;quot;xSite&amp;quot;&lt;/span&gt;&lt;span style="color: red;"&gt; Path&lt;/span&gt;&lt;span style="color: blue;"&gt;=&amp;quot;SelectedIndex&amp;quot;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #a31515;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Binding&lt;/span&gt;&lt;span style="color: red;"&gt; ElementName&lt;/span&gt;&lt;span style="color: blue;"&gt;=&amp;quot;xUsername&amp;quot;&lt;/span&gt;&lt;span style="color: red;"&gt; Path&lt;/span&gt;&lt;span style="color: blue;"&gt;=&amp;quot;Text&amp;quot;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #a31515;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;MultiBinding&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Button.IsEnabled&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;And a IMultiValueConverter like this:&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white; font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee; font-size: 12px; border: 1px dashed #999999; line-height: 14px; padding: 5px; overflow: auto;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;LoginConverter&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IMultiValueConverter&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt; Convert(&lt;span style="color: blue;"&gt;object&lt;/span&gt;[] values, &lt;span style="color: #2b91af;"&gt;Type&lt;/span&gt; targetType, &lt;span style="color: blue;"&gt;object&lt;/span&gt; parameter, &lt;span style="color: #2b91af;"&gt;CultureInfo&lt;/span&gt; culture)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// SelectedIndex of the ComboBox&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; selectedIndex = (&lt;span style="color: blue;"&gt;int&lt;/span&gt;)values[0];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// Length of Text in TextBox&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; selectedLength = ((&lt;span style="color: blue;"&gt;string&lt;/span&gt;)values[1]).Length;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// Only enable Button if both Combo and TextBox have data&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (selectedIndex == -1 || selectedLength==0)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;object&lt;/span&gt;[] ConvertBack(&lt;span style="color: blue;"&gt;object&lt;/span&gt; value, &lt;span style="color: #2b91af;"&gt;Type&lt;/span&gt;[] targetTypes, &lt;span style="color: blue;"&gt;object&lt;/span&gt; parameter, &lt;span style="color: #2b91af;"&gt;CultureInfo&lt;/span&gt; culture)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;NotImplementedException&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The array of object[] values are presented in the same order as the Bindings within the MultiBinding.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3804252173720428114?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3804252173720428114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3804252173720428114' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3804252173720428114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3804252173720428114'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/04/multibinding.html' title='MultiBinding'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4276626380838971600</id><published>2009-03-13T22:22:00.006Z</published><updated>2009-03-13T22:54:08.981Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Validation'/><category scheme='http://www.blogger.com/atom/ns#' term='Formatting'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Forcing OnPropertyChanged to update the UI</title><content type='html'>Having used my new Func&amp;lt;T, T&amp;gt; friend (see &lt;a href="http://mikestedman.blogspot.com/2009/03/action-and-func.html"&gt;Action&amp;lt;T&amp;gt; and Func&amp;lt;T, TResult&amp;gt;&lt;/a&gt;) the bound TextBox refused to show the revised value. Even though OnPropertyChanged("...") had been called the property's "getter" was not called by WPF.&lt;br /&gt;&lt;br /&gt;I don't really understand why.&lt;br /&gt;&lt;br /&gt;To get round this problem I added a FormattingConverter to the TextBox called DoNothingConverter. Its presence is sufficient to ensure the UI updates.&lt;br /&gt;&lt;br /&gt;&lt;pre style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; FONT-SIZE: 12px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; COLOR: #000000; LINE-HEIGHT: 14px; PADDING-TOP: 5px; BORDER-BOTTOM: #999999 1px dashed; FONT-FAMILY: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; BACKGROUND-COLOR: #eee"&gt;&lt;code&gt;public class DoNothingConverter : IValueConverter&lt;br /&gt;{&lt;br /&gt;   public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)&lt;br /&gt;   {&lt;br /&gt;      return value;&lt;br /&gt;   }&lt;br /&gt;   public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)&lt;br /&gt;   {&lt;br /&gt;      return value;&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4276626380838971600?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4276626380838971600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4276626380838971600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4276626380838971600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4276626380838971600'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/03/forcing-onpropertychanged-to-update-ui.html' title='Forcing OnPropertyChanged to update the UI'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-463242392080624419</id><published>2009-03-13T22:12:00.004Z</published><updated>2009-03-13T22:36:01.391Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Validation'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Formatting'/><title type='text'>Action&lt;T&gt; and Func&lt;T, TResult&gt;</title><content type='html'>I wanted to pass a validation routine to my SetValue method that uses generics. So I used the Action&lt;t&gt; delegate system.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; FONT-SIZE: 12px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; COLOR: #000000; LINE-HEIGHT: 14px; PADDING-TOP: 5px; BORDER-BOTTOM: #999999 1px dashed; FONT-FAMILY: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; BACKGROUND-COLOR: #eee"&gt;&lt;code&gt;protected void SetValue&lt;t&gt;(T newValue, Action&lt;t&gt; validate)&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;  validate.Invoke(newValue);&lt;br /&gt;...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;That worked fine until I wanted to change the value (for formatting purposes). So I moved to using the Func&lt;t,&gt; delegate system instead. Since I want the result to be of the same type as the passed argument I used &amp;lt;T, T&amp;gt; instead of &amp;lt;T, TResult&amp;gt;.&lt;br /&gt;&lt;pre style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; FONT-SIZE: 12px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; COLOR: #000000; LINE-HEIGHT: 14px; PADDING-TOP: 5px; BORDER-BOTTOM: #999999 1px dashed; FONT-FAMILY: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; BACKGROUND-COLOR: #eee"&gt;&lt;code&gt;&lt;br /&gt;protected T SetValue&lt;t&gt;(T newValue, Func&lt;t,&gt; validate)&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;  newValue = validate.Invoke(newValue);&lt;br /&gt;...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-463242392080624419?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/463242392080624419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=463242392080624419' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/463242392080624419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/463242392080624419'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/03/action-and-func.html' title='Action&amp;lt;T&amp;gt; and Func&amp;lt;T, TResult&amp;gt;'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5129352576328661738</id><published>2009-02-20T20:46:00.002Z</published><updated>2009-02-20T20:52:12.718Z</updated><title type='text'>WPF transparent windows and VNC</title><content type='html'>&lt;font face="Calibri"&gt;&amp;nbsp;&lt;/font&gt;  &lt;div&gt;We've found that VNC doesn't transmit any info for transparent windows in a WPF app..&lt;/div&gt; &lt;div&gt;So.. when we use VNC for support.. we can't see :&lt;/div&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt; &lt;div&gt;The logon box&lt;/div&gt; &lt;div&gt;The popup menus&lt;/div&gt; &lt;div&gt;Any MessageBoxes&lt;/div&gt; &lt;div&gt;&amp;nbsp;&lt;/div&gt; &lt;div&gt;Not handy…. (not sure of the solution to this yet – might be something we can do with VNC.. might be a "support skin" change.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5129352576328661738?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5129352576328661738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5129352576328661738' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5129352576328661738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5129352576328661738'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/02/wpf-transparent-windows-and-vnc.html' title='WPF transparent windows and VNC'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3531460441329640382</id><published>2009-02-12T19:36:00.000Z</published><updated>2009-02-12T19:37:25.815Z</updated><title type='text'>WCF Exceptions and Fault Contracts</title><content type='html'>Just a straight link to an excellent article: &lt;a href="http://blog.petegoo.com/archive/2008/04/16/wcf-exceptions-and-fault-contracts.aspx"&gt;WCF Exceptions and Fault Contracts&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3531460441329640382?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3531460441329640382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3531460441329640382' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3531460441329640382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3531460441329640382'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/02/wcf-exceptions-and-fault-contracts.html' title='WCF Exceptions and Fault Contracts'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4675156120359935839</id><published>2009-02-02T17:21:00.000Z</published><updated>2009-02-02T17:37:10.475Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Routed Commands'/><title type='text'>Passing an Enum as a CommandParameter</title><content type='html'>We wanted to pass an Enum as a CommandParameter and struggled to find the right syntax. The final result turned out to be straightforward.&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;xmlns:Util="clr-namespace:Sandstorm.Documents.FlexBlockBookings.Util&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&amp;lt;RadioButton Name="rbPriceByActivity"  &lt;br /&gt;Content="By Activity"  &lt;br /&gt;Command="{Binding Path=BBChangePricingCommand}" &lt;br /&gt;CommandParameter="&lt;font style="color:red"&gt;{x:static Util:PricingOptions.ByActivity}&lt;/font&gt;"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4675156120359935839?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4675156120359935839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4675156120359935839' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4675156120359935839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4675156120359935839'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/02/passing-enum-as-commandparameter.html' title='Passing an Enum as a CommandParameter'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-6041321908370244682</id><published>2009-02-01T10:39:00.002Z</published><updated>2009-03-17T14:34:28.328Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Validation'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Validation in MVVM</title><content type='html'>We're following the MVVM pattern and using Josh Smith's example app &lt;a href="http://joshsmithonwpf.wordpress.com/2008/11/14/using-a-viewmodel-to-provide-meaningful-validation-error-messages"&gt;Using a Viewmodel to provide meaningful Validation Error Messages&lt;/a&gt; to implement validation.&lt;br /&gt;&lt;br /&gt;When I was in debugger I noticed that some code was executing twice so I traced through the code once the focus left the textbox.&lt;br /&gt;&lt;br /&gt;The order of processing was:&lt;br /&gt;&lt;pre style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; COLOR: #000000; LINE-HEIGHT: 14px; PADDING-TOP: 5px; BORDER-BOTTOM: #999999 1px dashedfont-family:Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace;font-size:12px;color:#000000;"   &gt;&lt;code&gt;[External Code]&lt;br /&gt;ViewModel.Property.Set&lt;br /&gt;  OnPropertyChanged&lt;br /&gt;[External Code]&lt;br /&gt;&lt;span style="color:red;"&gt;ViewModel.this[propertyName]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;But when you add in a FormattingConverter the order becomes:&lt;pre style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; COLOR: #000000; LINE-HEIGHT: 14px; PADDING-TOP: 5px; BORDER-BOTTOM: #999999 1px dashedfont-family:Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace;font-size:12px;color:#000000;"   &gt;&lt;code&gt;[External Code]&lt;br /&gt;FormattingConverter.ConvertBack&lt;br /&gt;[External Code]&lt;br /&gt;ViewModel.Property.Set&lt;br /&gt;  OnPropertyChanged&lt;br /&gt;    [External Code]&lt;br /&gt;    ViewModel.Property.Get&lt;br /&gt;    [External Code]&lt;br /&gt;    FormattingConverter.Convert&lt;br /&gt;    [External Code]&lt;br /&gt;    &lt;span style="color:red;"&gt;ViewModel.this[propertyName]&lt;/span&gt;&lt;br /&gt;[External Code]&lt;br /&gt;&lt;span style="color:red;"&gt;ViewModel.this[propertyName]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;Which means that the validation gets fired twice.&lt;br /&gt;&lt;br /&gt;Because we don't want invalid data in our Model we've recently moved the setting of the Model.Property into the ModelView.this[propertyName] method - not ideal but it is the last opportunity where we still have control. Of course the "double-validation" results in the Model.Property being set twice. Not usually a problem but I fear some hidden side-effect somewhere down the line.&lt;br /&gt;&lt;br /&gt;Another slight aggravation is that the Convert function is called before the validation and therefore invalid data will fail to convert then we'll attempt the conversion in the validation process (which was the whole point of this exercise).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-6041321908370244682?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/6041321908370244682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=6041321908370244682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6041321908370244682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6041321908370244682'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/02/validation-in-mvvm.html' title='Validation in MVVM'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2545721506808179158</id><published>2009-02-01T07:56:00.000Z</published><updated>2009-02-01T08:03:37.560Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><title type='text'>IsVisibleChanged</title><content type='html'>I have the following code which is trying to detect that I’ve clicked on a button and my UserControl is now visible, so I want to set focus to a sensible control in that usercontrol.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white; font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee; font-size: 12px; border: 1px dashed #999999; line-height: 14px; padding: 5px; overflow: auto;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;void&lt;/span&gt; UCBBNotes_IsVisibleChanged(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, DependencyPropertyChangedEventArgs e)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; ((&lt;span style="color: blue;"&gt;bool&lt;/span&gt;)e.NewValue == &lt;span style="color: blue;"&gt;true&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; a = txtNotes.Focus();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// a returns false &lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; txtNotes.UpdateLayout();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; b = txtNotes.Focus();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// b returns true&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;So, when reacting to certain events such as “IsVisibleChanged”, the event is called before the layout has updated all the child controls.  So txtNotes.Focus() fails because txtNotes.IsVisible = False at that point.&lt;br /&gt;&lt;br /&gt;This can either be fixed as above by forcing an UpdateLayout by the Dispatcher – which probably isn’t ideal.   Or, instead of watching for the usercontrol to become visible, watch for the textbox we want to focus upon to become visible, like this :&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white; font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee; font-size: 12px; border: 1px dashed #999999; line-height: 14px; padding: 5px; overflow: auto;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;void&lt;/span&gt; txtNotes_IsVisibleChanged(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, DependencyPropertyChangedEventArgs e)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; ((&lt;span style="color: blue;"&gt;bool&lt;/span&gt;)e.NewValue == &lt;span style="color: blue;"&gt;true&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; txtNotes.Focus();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&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/7059224265445023060-2545721506808179158?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2545721506808179158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2545721506808179158' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2545721506808179158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2545721506808179158'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/isvisiblechanged.html' title='IsVisibleChanged'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4627969345411200756</id><published>2009-01-30T11:40:00.000Z</published><updated>2009-01-30T14:32:25.268Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>We hail Regex! We hail Regex! No, we *hate* Regex, we *hate* Regex</title><content type='html'>A useful article about using Regex.Replace&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.knowdotnet.com/articles/regereplacementstrings.html"&gt;Using Replacement Strings with Regex.Replace&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4627969345411200756?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4627969345411200756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4627969345411200756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4627969345411200756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4627969345411200756'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/we-hail-regex-we-hail-regex-no-we-hate.html' title='We hail Regex! We hail Regex! No, we *hate* Regex, we *hate* Regex'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3985522788805319210</id><published>2009-01-29T10:37:00.000Z</published><updated>2009-01-30T12:33:07.695Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Sorting and De-duping arrays</title><content type='html'>I seem to be obsessed with sorting based on the number of posts I've made on the topic.&lt;br /&gt;Sorting a simple string[] is easy using:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;[] recordIds = { &lt;span style="color:#a31515;"&gt;"q"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"z"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"a"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"b"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"q"&lt;/span&gt; };&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:#2b91af;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;strong&gt;&lt;span style="color:#2b91af;"&gt;Array&lt;/span&gt;.Sort(recordIds);&lt;/strong&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;To stop a third party component from failing we had to ensure that our string[] array contained only unique strings. Sorting and de-duping using LINQ could be done in a single line:&lt;br /&gt;&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;[] recordIds = { &lt;span style="color:#a31515;"&gt;"q"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"z"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"a"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"b"&lt;/span&gt;, &lt;span style="color:#a31515;"&gt;"q"&lt;/span&gt; };&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;strong&gt;&lt;span style="color:blue;"&gt;var&lt;/span&gt; sortedUniqueIds = (&lt;span style="color:blue;"&gt;from&lt;/span&gt; id &lt;span style="color:blue;"&gt;in&lt;/span&gt; recordIds &lt;span style="color:blue;"&gt;orderby&lt;/span&gt; id &lt;span style="color:blue;"&gt;select&lt;/span&gt; id).Distinct();&lt;/strong&gt;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt; &lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;int&lt;/span&gt; i=0;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;&lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:blue;"&gt;string&lt;/span&gt; id &lt;span style="color:blue;"&gt;in&lt;/span&gt; sortedUniqueIds)&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;{&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;   recordIds[i++] = id;&lt;/pre&gt;&lt;pre style="MARGIN: 0px"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Microsoft have an excellent LINQ samples page: &lt;a href="http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx"&gt;101 LINQ Samples&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3985522788805319210?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3985522788805319210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3985522788805319210' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3985522788805319210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3985522788805319210'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/sorting-and-de-duping-arrays.html' title='Sorting and De-duping arrays'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4622382517239067898</id><published>2009-01-28T11:40:00.000Z</published><updated>2009-01-28T12:00:27.684Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Unhandled Exceptions in VS2008</title><content type='html'>In our solution we have two basic projects: Client and Server, communicating via WCF.&lt;br /&gt;&lt;br /&gt;When the Server components throw an exception the Server's WCF layer catches it, wraps it up as a FaultException and rethrows for the Client to catch.&lt;br /&gt;&lt;br /&gt;Even though the exception is handled the debugger signals an unhandled exception when running the Server though VS2008.&lt;br /&gt;&lt;br /&gt;From the Debug | Exceptions menu option I've turned the exception handling off for that one specific type: System.ServiceModel.FaultException`1&lt;br /&gt;&lt;br /&gt;It would appear that disabling this exception affects only the Server project.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_GfII9sSw1bY/SYBHrc9mmYI/AAAAAAAAAAM/vdpTIfT_t-Y/s1600-h/Debug_Exceptions.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 158px;" src="http://2.bp.blogspot.com/_GfII9sSw1bY/SYBHrc9mmYI/AAAAAAAAAAM/vdpTIfT_t-Y/s320/Debug_Exceptions.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5296311973622225282" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4622382517239067898?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4622382517239067898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4622382517239067898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4622382517239067898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4622382517239067898'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/unhandled-exceptions-in-vs2008.html' title='Unhandled Exceptions in VS2008'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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://2.bp.blogspot.com/_GfII9sSw1bY/SYBHrc9mmYI/AAAAAAAAAAM/vdpTIfT_t-Y/s72-c/Debug_Exceptions.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7059224265445023060.post-1537954911289766647</id><published>2009-01-27T07:05:00.000Z</published><updated>2009-01-27T07:26:30.979Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Sorting Generic Collections - Redux</title><content type='html'>Using LINQ it turns out to be quite easy to sort a generic Dictionary by either Key or Value.&lt;br /&gt;&lt;br /&gt;In these examples a list of sorted keys is returned in the 'keys' variable.&lt;br /&gt;&lt;br /&gt;Alternately the LINQ statement can used directly in a foreach loop.&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;br /&gt;Dictionary&amp;lt;string, string&amp;gt; dict = new Dictionary&amp;lt;string, string&amp;gt;();&lt;br /&gt;...&lt;br /&gt;&lt;p&gt;&lt;br /&gt;// Sort by Key&lt;br /&gt;var keys = from key in dict.Keys orderby key ascending select key;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;// Sort by Value&lt;br /&gt;var keys = from key in dict.Keys orderby dict[key] ascending select key;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;// Sort within foreach(...) by Key&lt;br /&gt;foreach(string aKey in (from key in dict.Keys orderby key ascending select key)){&lt;br /&gt;  ...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-1537954911289766647?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/1537954911289766647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=1537954911289766647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1537954911289766647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1537954911289766647'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/sorting-dictionary.html' title='Sorting Generic Collections - Redux'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-6712075544724871367</id><published>2009-01-22T16:52:00.000Z</published><updated>2009-01-27T07:05:42.956Z</updated><title type='text'>WCF Security and Certificates</title><content type='html'>It turns out, you can't do Message level authentication without a Certificate involved to identify the server as the server..&lt;br /&gt;and then because I don't have a bona-fide bought and paid for Certificate for my server, it still fails with arcane errors until you add a magic line to the config file on the client saying "trust any old certificate -- we're not fussy!"&lt;br /&gt;On the server config, I needed this line :&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" /&amp;gt;&lt;/pre&gt;&lt;/code&gt;so I'll need to tweak those values somehow and right now on the client to avoid the "trusted certificate" issue, I needed :&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;serviceCertificate&amp;gt; &lt;br /&gt;  &amp;lt;!--  &lt;br /&gt;  Setting the certificateValidationMode to PeerOrChainTrust means that if the certificate  &lt;br /&gt;  is in the user's Trusted People store, then it will be trusted without performing a &lt;br /&gt;  validation of the certificate's issuer chain. This setting is used here for convenience so that the  &lt;br /&gt;  sample can be run without having to have certificates issued by a certificate authority (CA). &lt;br /&gt;  This setting is less secure than the default, ChainTrust. The security implications of this  &lt;br /&gt;  setting should be carefully considered before using PeerOrChainTrust in production code.  &lt;br /&gt;  --&amp;gt; &lt;br /&gt;  &amp;lt;authentication certificateValidationMode="PeerOrChainTrust" /&amp;gt; &lt;br /&gt;&amp;lt;/serviceCertificate&amp;gt;&lt;/pre&gt;&lt;/code&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa702579.aspx"&gt;Certificate Validation Differences Between HTTPS, SSL over TCP, and SOAP Security&lt;/a&gt;&lt;br /&gt;You can use certificates in Windows Communication Foundation (WCF) with message-layer (SOAP) security in addition to transport-layer security (TLS) over HTTP (HTTPS) or TCP. This topic describes differences in the way such certificates are validated.&lt;br /&gt;When using HTTPS to communicate between a client and a service, the certificate that the server authenticates with must support chain trust by default. That is, it must chain to a trusted root certificate authority. No online check is performed to see whether the certificate has been revoked. You can override this behavior by registering a RemoteCertificateValidationCallback callback, as shown in the following code:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;ServicePointManager.ServerCertificateValidationCallback +=&lt;br /&gt;    new RemoteCertificateValidationCallback(ValidateServerCertificate);&lt;/pre&gt;&lt;/code&gt;where the signature for ValidateServerCertificate is as follows:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public static bool ValidateServerCertificate(&lt;br /&gt;  object sender,&lt;br /&gt;  X509Certificate certificate,&lt;br /&gt;  X509Chain chain,&lt;br /&gt;  SslPolicyErrors sslPolicyErrors)&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-6712075544724871367?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/6712075544724871367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=6712075544724871367' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6712075544724871367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6712075544724871367'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2009/01/wcf-security-and-certificates.html' title='WCF Security and Certificates'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-6641892291786136953</id><published>2008-12-10T17:11:00.001Z</published><updated>2008-12-10T17:16:15.062Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Universe SEQ function and .Net</title><content type='html'>Not really a WPF issue but I don't want to lose track of this reference.&lt;br /&gt;&lt;br /&gt;This blog has lots of useful info regarding using Universe from .Net&lt;br /&gt;&lt;a href="http://gigamegatech.com/"&gt;GigaMegaTech&lt;/a&gt;&lt;br /&gt;including this nugget about the SEQ() function.&lt;br /&gt;&lt;br /&gt;The strings returned from Universe are encoded in ANSI format. So the SEQ function in Universe doesn't return the same values in the extended character set as .Net does. Therefore the need to use:&lt;br /&gt;&lt;br /&gt;Encoding.Ansi.GetBytes();&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-6641892291786136953?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/6641892291786136953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=6641892291786136953' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6641892291786136953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/6641892291786136953'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/12/universe-seq-function-and-net.html' title='Universe SEQ function and .Net'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5619879893769299213</id><published>2008-11-26T09:38:00.000Z</published><updated>2008-11-26T11:38:35.553Z</updated><title type='text'>WCF and Custom Exceptions</title><content type='html'>From within the Server we throw custom exceptions which contain custom data that the client code can use. To transport these across WCF to the client we wrap them in a FaultException like this:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;catch (BlockBookingInvalidFloorsException ex)&lt;br /&gt;{&lt;br /&gt;  throw new FaultException&lt;BlockBookingInvalidFloorsException&gt;(ex);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;Despite the fact that both the custom exception and the contained classes are marked as [Serializable()] it results in a WCF CommunicationException.&lt;br /&gt;&lt;br /&gt;To resolve this we now add this new constructor:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public BlockBookingInvalidFloorsException(SerializationInfo serializationInfo, StreamingContext streamingContext)&lt;br /&gt;         : base(serializationInfo, streamingContext) { }&lt;/code&gt;&lt;/pre&gt;Martin found this blog with a fuller explanation: &lt;a href="http://blog.clauskonrad.net/2008/06/wcf-and-custom-exceptions.html"&gt;WCF and Custom Exceptions&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Claus suggests that custom exceptions should derive from either CommunicationException or System.Exception. Our's derive from ApplicationException with no problem, indeed the ApplicationException already includes this constructor (protected).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5619879893769299213?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5619879893769299213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5619879893769299213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5619879893769299213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5619879893769299213'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/wcf-and-custom-exceptions.html' title='WCF and Custom Exceptions'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8940970370853588321</id><published>2008-11-26T07:38:00.000Z</published><updated>2008-11-26T09:36:10.332Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Sub Classing Window and UserControl</title><content type='html'>I wanted to add a standard method (InjectModel) into our Windows and UserControls and the obvious technique was to subclass them with something like this:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public partial class PersonEditView : WindowBase&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class WindowBase : Window&lt;br /&gt;{&lt;br /&gt;...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;The xaml then needs to reference the WindowBase class like this:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;local:WindowBase x:Class="INPC2.PersonEditView"&lt;br /&gt;    ...&lt;br /&gt;    xmlns:local="clr-namespace:INPC2"&lt;br /&gt;    &amp;gt;&lt;br /&gt;   &amp;lt;local:WindowBase.Resources&amp;gt;&lt;br /&gt;   ...&lt;br /&gt;   &amp;lt;/local:WindowBase.Resources&amp;gt;&lt;br /&gt;...&lt;br /&gt;&amp;lt;/local:WindowBase&amp;gt;&lt;/code&gt;&lt;/pre&gt;There is no problem with the forward reference to xmlns:local&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8940970370853588321?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8940970370853588321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8940970370853588321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8940970370853588321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8940970370853588321'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/sub-classing-window-and-usercontrol.html' title='Sub Classing Window and UserControl'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3024544364684085000</id><published>2008-11-26T07:03:00.000Z</published><updated>2008-11-26T07:30:28.856Z</updated><title type='text'>ObjectDataProvider</title><content type='html'>To make UI design easier in Blend we want to provide dummy data at design time. Using an ObjectDataProvider with an ObjectType attribute achieves this (provided the bound datasource can provide dummy data). &lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;ObjectDataProvider x:Key="DesignTimeDataProvider" d:IsDataSource="True" ObjectType="{x:Type Dummy_Application:PeopleDataProvider}"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;However it is not possible to replace the ObjectType with an ObjectInstance at runtime.&lt;br /&gt;We got round that problem by using two ObjectDataProviders:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;ObjectDataProvider x:Key="DesignTimeDataProvider" d:IsDataSource="True" ObjectType="{x:Type Dummy_Application:PeopleDataProvider}"/&amp;gt;&lt;br /&gt;&amp;lt;ObjectDataProvider x:Key="InnerDataProvider" d:IsDataSource="true" ObjectInstance="{StaticResource DesignTimeDataProvider}"/&amp;gt;&lt;br /&gt;&amp;lt;ListBox ItemsSource="{Binding Path=DataProvider.PeopleList, Source={StaticResource InnerDataProvider}}"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;Then in the code behind we replace the ObjectInstance with our freshly minted data source:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;ObjectDataProvider odpWindow = (ObjectDataProvider)this.FindResource("InnerDataProvider");&lt;br /&gt;odpWindow.ObjectInstance= newPeopleDataProvider;&lt;/code&gt;&lt;/pre&gt;The problem with this approach is that at runtime a datasource is created (as part of InitializeComponent) that is then immediately discarded.&lt;br /&gt;&lt;br /&gt;To resolve this I created my own ObjectDataProvider which nulls the ObjectType at runtime. This is enough to allow the ODP to accept a change to the ObjectInstance without complaint.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class MyObjectDataProvider : ObjectDataProvider&lt;br /&gt;{&lt;br /&gt;   bool isInDesignMode = (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;&lt;br /&gt;   public new Type ObjectType&lt;br /&gt;   {&lt;br /&gt;      get { return base.ObjectType; }&lt;br /&gt;      set&lt;br /&gt;      {&lt;br /&gt;         if (!isInDesignMode) value = null;&lt;br /&gt;         base.ObjectType = value;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public partial class PersonEditView : Window&lt;br /&gt;{&lt;br /&gt;   public PersonEditView()&lt;br /&gt;   {&lt;br /&gt;      InitializeComponent();&lt;br /&gt;      ((ObjectDataProvider)this.FindResource("DataModel")).ObjectInstance = model;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;The xaml then becomes simpler and cleaner:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;local:MyObjectDataProvider x:Key="DataModel" d:IsDataSource="True" ObjectType="{x:Type local:PersonEditModel}" /&amp;gt;&lt;br /&gt;&amp;lt;TextBlock Text="{Binding Source={StaticResource DataModel}, Path=APerson.Surname}"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3024544364684085000?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3024544364684085000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3024544364684085000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3024544364684085000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3024544364684085000'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/objectdataprovider.html' title='ObjectDataProvider'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3721822815744047003</id><published>2008-11-26T06:43:00.000Z</published><updated>2008-11-26T06:56:06.659Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>INotifyPropertyChanged</title><content type='html'>I had a conversation with Martin about INotifyPropertyChanged and it made me realise there was an (other) aspect of Binding that I hadn't appreciated.&lt;br /&gt; &lt;br /&gt;So I created a little project to test my assumptions.&lt;br /&gt; &lt;br /&gt;&lt;strong&gt;1) Business Class implements INotifyPropertyChanged&lt;/strong&gt;&lt;br /&gt; &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class Person : INotifyPropertyChanged&lt;br /&gt;{&lt;br /&gt;  private string _surname = "";&lt;br /&gt;  public string Surname&lt;br /&gt;  {&lt;br /&gt;    get { return _surname; }&lt;br /&gt;    set&lt;br /&gt;    {&lt;br /&gt;      _surname = value;&lt;br /&gt;      OnPropertyChanged("Surname");&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  public event PropertyChangedEventHandler PropertyChanged;&lt;br /&gt;  protected void OnPropertyChanged(string propertyName)&lt;br /&gt;  {&lt;br /&gt;    if (PropertyChanged != null)&lt;br /&gt;    {&lt;br /&gt;      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;2) Model exposing two instances of Person. Model does not implement INPC&lt;/strong&gt;&lt;br /&gt; &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class Model&lt;br /&gt;{&lt;br /&gt;  public Person APerson { get; set; }&lt;br /&gt;  public Person AnotherPerson { get; set; }&lt;br /&gt;  public Model()&lt;br /&gt;  {&lt;br /&gt;    APerson = new Person();&lt;br /&gt;    AnotherPerson = new Person();&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;3) Bind to only one of the two instances of Person in the Model&lt;/strong&gt;&lt;br /&gt; &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;TextBlock Text="{Binding Model.APerson.Surname}"&amp;gt;&amp;lt;/TextBlock&amp;gt;&lt;br /&gt;&amp;lt;Button Click="Button_Click"&amp;gt;Go&amp;lt;/Button&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;4) Wire it all up&lt;/strong&gt;&lt;br /&gt; &lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public partial class Window2 : Window&lt;br /&gt;{&lt;br /&gt;  private Model _model = new Model();&lt;br /&gt;  public Model Model&lt;br /&gt;  {&lt;br /&gt;    get { return _model; }&lt;br /&gt;    set { _model = value; }&lt;br /&gt;  }&lt;br /&gt;  public Window2()&lt;br /&gt;  {&lt;br /&gt;    InitializeComponent();&lt;br /&gt;    DataContext = this;&lt;br /&gt;  }&lt;br /&gt;  private void Button_Click(object sender, RoutedEventArgs e)&lt;br /&gt;  {&lt;br /&gt;    Model.APerson.Surname = "Smith";&lt;br /&gt;    Model.AnotherPerson.Surname = "Jones";&lt;br /&gt;  }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;br /&gt;PropertyChanged is only hooked up for APerson and not for AnotherPerson because nothing is bound to AnotherPerson in the xaml.&lt;br /&gt; &lt;br /&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;br /&gt;I might need to revisit the changes I made to AbstractModel hooking up PropertyChanged and DataError. Currently they are hooked up when the Model is instantiated, regardless of whether there is any binding in the xaml.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3721822815744047003?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3721822815744047003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3721822815744047003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3721822815744047003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3721822815744047003'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/i-had-conversation-with-martin-about.html' title='INotifyPropertyChanged'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2128801206863183681</id><published>2008-11-26T06:32:00.000Z</published><updated>2008-11-26T06:35:53.568Z</updated><title type='text'>Quiz - guess the technology</title><content type='html'>&lt;strong&gt;Jeremiah says:&lt;/strong&gt;&lt;br /&gt;I've been vocal at work about how stupid I think &lt;em&gt;xxxxxx&lt;/em&gt; is.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Mike says:&lt;/strong&gt;&lt;br /&gt;Why is it stupid?&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Jeremiah says:&lt;br /&gt;&lt;/strong&gt;Because it looks snazzy 4 seconds after you've put in a feature but then 4 months later it still isn't quite right; takes forever to make minor tweaks; doesn't have anything to offer over simple HTML (other than the RAD) but has less features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2128801206863183681?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2128801206863183681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2128801206863183681' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2128801206863183681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2128801206863183681'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/quiz-guess-technology.html' title='Quiz - guess the technology'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8461467940719946650</id><published>2008-11-19T15:15:00.001Z</published><updated>2009-03-05T06:58:21.000Z</updated><title type='text'>Custom Control Part 2</title><content type='html'>In &lt;a href="http://mikestedman.blogspot.com/2008/11/custom-control.html"&gt;"Custom Control Part 1"&lt;/a&gt; we created a raw custom control that does nothing. In this post we'll change the control so it only does "one thing" - stores its original value and when the current value differs it sets the HasChanged property to true.&lt;br /&gt;&lt;br /&gt;This needs a couple of private member vars (OldText &amp; Initialised) to hold the state, a new DependencyProperty (HasChangedProperty), a standard CLR property (HasChanged) and some logic added to the TextPropertyChanged event handler.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; color=#557777"&gt;&lt;code&gt;public class DemoTextBox : TextBox&lt;br /&gt;{&lt;br /&gt;   static DemoTextBox()&lt;br /&gt;   {&lt;br /&gt;      // Create a callback for when the TextProperty changes&lt;br /&gt;      PropertyChangedCallback callback = new PropertyChangedCallback(TextPropertyChanged);&lt;br /&gt;&lt;br /&gt;      // Override the TextProperty metadata in order to link up the callback routine&lt;br /&gt;      TextProperty.OverrideMetadata(&lt;br /&gt;         typeof(DemoTextBox),&lt;br /&gt;         new FrameworkPropertyMetadata(callback));&lt;br /&gt;   }&lt;br /&gt;   static void TextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)&lt;br /&gt;   {&lt;br /&gt;      // Cast the Sender to an object of this class&lt;br /&gt;      DemoTextBox textBox = (DemoTextBox)sender;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="font-size: 12px;font-weight:bold;color:#000000"&gt;&lt;br /&gt;      // Store the OldText value when this event is&lt;br /&gt;      // fired for the first time&lt;br /&gt;&amp;nbsp;&lt;br /&gt;      if (!textBox.&lt;span style="color:green"&gt;Initialised&lt;/span&gt;)&lt;br /&gt;      {&lt;br /&gt;         textBox.&lt;span style="color:green"&gt;Initialised&lt;/span&gt; = true;&lt;br /&gt;         textBox.&lt;span style="color:green"&gt;OldText&lt;/span&gt; = textBox.Text;&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      // Set the HasChangedProperty to indicate whether the text has changed&lt;br /&gt;&lt;br /&gt;      textBox.SetValue(&lt;span style="color:red"&gt;HasChangedProperty&lt;/span&gt;, (textBox.&lt;span style="color:green"&gt;OldText&lt;/span&gt; != textBox.Text));&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   }&lt;br /&gt;&lt;span style="font-size: 12px;font-weight:bold;color:#000000"&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   private bool &lt;span style="color:green"&gt;Initialised&lt;/span&gt; = false;&lt;br /&gt;   private string &lt;span style="color:green"&gt;OldText&lt;/span&gt; = "";&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   // The new DependencyProperty&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   static readonly DependencyProperty &lt;span style="color:red"&gt;HasChangedProperty&lt;/span&gt; = DependencyProperty.Register(&lt;br /&gt;      "&lt;span style="color:blue"&gt;HasChanged&lt;/span&gt;",&lt;br /&gt;      typeof(bool),&lt;br /&gt;      typeof(DemoTextBox)&lt;br /&gt;      );&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   // The new CLR Property&lt;br /&gt;&amp;nbsp;&lt;br /&gt;   public bool &lt;span style="color:blue"&gt;HasChanged&lt;/span&gt;&lt;br /&gt;   {&lt;br /&gt;      get { return (bool)GetValue(&lt;span style="color:red"&gt;HasChangedProperty&lt;/span&gt;); }&lt;br /&gt;   }&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In the Generic.xaml we'll add a Trigger to turn the textbox background Red when the Text value has changed.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; color=#557777"&gt;&lt;code&gt;&amp;lt;ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;    xmlns:local="clr-namespace:DepProp"&amp;gt;&lt;br /&gt;   &amp;lt;Style TargetType="{x:Type local:DemoTextBox}"&amp;gt;      &lt;br /&gt;      &amp;lt;Style.Triggers&amp;gt;&lt;br /&gt;&lt;span style="font-size: 12px;font-weight:bold;color:#000000"&gt;&lt;br /&gt;         &amp;lt;Trigger  Property="&lt;span style="color:blue"&gt;HasChanged&lt;/span&gt;" Value="true"&amp;gt;&lt;br /&gt;            &amp;lt;Setter Property="Background" Value="Red"/&amp;gt;&lt;br /&gt;         &amp;lt;/Trigger&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;      &amp;lt;/Style.Triggers&amp;gt;&lt;br /&gt;   &amp;lt;/Style&amp;gt;&lt;br /&gt;&amp;lt;/ResourceDictionary&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8461467940719946650?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8461467940719946650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8461467940719946650' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8461467940719946650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8461467940719946650'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/custom-control-part-2.html' title='Custom Control Part 2'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4719558520814849656</id><published>2008-11-18T19:11:00.000Z</published><updated>2008-11-19T15:57:28.722Z</updated><title type='text'>Custom Control Part 1</title><content type='html'>I've struggled to find a really simple example of creating a custom control. So I created a simple control that did only "one thing" then removed the "one thing" to leave just the very least plumbing that I could.&lt;br /&gt;&lt;br /&gt;Starting with a new class that inherits from TextBox:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class &lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt; : TextBox&lt;br /&gt;{&lt;br /&gt;   static &lt;span style="color:red"&gt;DemoTextBox()&lt;/span&gt;&lt;br /&gt;   {&lt;br /&gt;      // Create a callback for when the TextProperty changes&lt;br /&gt;      PropertyChangedCallback callback = new PropertyChangedCallback(&lt;span style="color:blue"&gt;TextPropertyChanged&lt;/span&gt;);&lt;br /&gt;      // Override the TextProperty metadata in order to link up the callback routine&lt;br /&gt;      TextProperty.OverrideMetadata(&lt;br /&gt;         typeof(&lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt;),&lt;br /&gt;         new FrameworkPropertyMetadata(callback));&lt;br /&gt;   }&lt;br /&gt;   static void &lt;span style="color:blue"&gt;TextPropertyChanged&lt;/span&gt;(DependencyObject sender, DependencyPropertyChangedEventArgs args)&lt;br /&gt;   {&lt;br /&gt;      // Cast the Sender to an object of this class&lt;br /&gt;      &lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt; textBox = (&lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt;)sender;&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Add a ResourceDictionary called Generic.xaml:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;    xmlns:local="clr-namespace:DepProp&amp;gt;&lt;br /&gt;   &amp;lt;Style TargetType="{x:Type local:&lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt;}"&amp;gt;&lt;br /&gt;      &amp;lt;Style.Triggers&amp;gt;&lt;br /&gt;         &amp;lt;!-- create a trigger here --&amp;gt;&lt;br /&gt;      &amp;lt;/Style.Triggers&amp;gt;&lt;br /&gt;   &amp;lt;/Style&amp;gt;&lt;br /&gt;&amp;lt;/ResourceDictionary&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And a reference to the new control in the Window:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&amp;lt;Window x:Class="DepProp.Window2"&lt;br /&gt;    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;br /&gt;    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&lt;br /&gt;    xmlns:local="clr-namespace:DepProp"    &lt;br /&gt;    Title="Window2" Height="300" Width="300"&amp;gt;&lt;br /&gt;   &amp;lt;Window.Resources&amp;gt;&lt;br /&gt;      &amp;lt;ResourceDictionary Source="Generic.xaml"/&amp;gt;&lt;br /&gt;   &amp;lt;/Window.Resources&amp;gt;&lt;br /&gt;   &amp;lt;StackPanel&amp;gt;&lt;br /&gt;      &amp;lt;local:&lt;span style="color:red"&gt;DemoTextBox&lt;/span&gt; x:Name="TextBoxV1" Text="Original Value" /&amp;gt;&lt;br /&gt;   &amp;lt;/StackPanel&amp;gt;&lt;br /&gt;&amp;lt;/Window&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4719558520814849656?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4719558520814849656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4719558520814849656' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4719558520814849656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4719558520814849656'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/custom-control.html' title='Custom Control Part 1'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7893922505252648337</id><published>2008-11-18T17:33:00.000Z</published><updated>2008-11-18T18:29:42.673Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ActiveSharp and StackTrace speed</title><content type='html'>When implementing the StackTrace within ActiveSharp I did a few tests to check out the speed of the different techniques I could use to get the Property Name.&lt;br /&gt;&lt;br /&gt;All the following times are for one million iterations.&lt;br /&gt;&lt;br /&gt;&lt;table style="background-color: #fafac8;border: 1px dashed #999999;"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;Technique&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Milliseconds&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ActiveSharp&lt;/td&gt;&lt;td&gt;400&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;StackWalk&lt;/td&gt;&lt;td&gt;120000&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MethodBase.GetCurrentMethod()&lt;/td&gt;&lt;td&gt;2000&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;"string"&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;const string&lt;/td&gt;&lt;td&gt;10&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The speed of ActiveSharp is a little unrealistic because it caches the Property Name for each field in the class. A class with more properties or accessing many different objects would reduce the speed advantage.&lt;br /&gt;&lt;br /&gt;Since the StackWalk was so slow I decided to check whether it was my code (examining the stack) or the creation of the stack in the first instance.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private void Button_Click_2(object sender, RoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;   DateTime start = DateTime.Now;&lt;br /&gt;   for (int i = 0; i &lt;= 1000000; i++)&lt;br /&gt;   {&lt;br /&gt;      StackTrace trace = new StackTrace();&lt;br /&gt;   }&lt;br /&gt;   DateTime end = DateTime.Now;&lt;br /&gt;   MessageBox.Show(end.Subtract(start).TotalMilliseconds.ToString());&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;One million iterations took 118,000 milliseconds to complete. There is little point trying to improve my code further.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7893922505252648337?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7893922505252648337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7893922505252648337' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7893922505252648337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7893922505252648337'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/activesharp-and-stacktrace-speed.html' title='ActiveSharp and StackTrace speed'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5617644049107233689</id><published>2008-11-18T11:04:00.002Z</published><updated>2011-03-02T22:12:40.109Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='RememberThis'/><category scheme='http://www.blogger.com/atom/ns#' term='MultiBinding'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>MultiBinding</title><content type='html'>I stumbled across MultiBinding today. I have no immediate use for it but I mustn't forget that it is available.&lt;br /&gt;&lt;br /&gt;There is a nice simple example from MSDN here: &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.data.multibinding.aspx"&gt;MultiBinding Class&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5617644049107233689?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5617644049107233689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5617644049107233689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5617644049107233689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5617644049107233689'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/multibinding.html' title='MultiBinding'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3958533637650985897</id><published>2008-11-17T17:34:00.000Z</published><updated>2008-11-26T11:58:02.963Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ActiveSharp</title><content type='html'>ActiveSharp is an excellent piece of free software (&lt;a href="http://www.codeplex.com/ActiveSharp"&gt;ActiveSharp Home Page&lt;/a&gt;) written by John Rusk to implement the INotifyPropertyChanged interface.&lt;br /&gt;&lt;br /&gt;Since we already have a abstract class that implements INPC I simply used the PropertyMap.GetProperty(this, ref target) method to get the property name and avoid having to hardcode the name as a string in each Property.&lt;br /&gt;&lt;br /&gt;I ran into a slight problem because we have some classes that expose the same field in multiple properties (not necessarily the right thing to do but that's what we've got) and ActiveSharp can't deal with this situation.&lt;br /&gt;&lt;br /&gt;My proposed solution was to change ActiveSharp to walk the Stack when it encountered these duplicates. John was kind enough to explain the potential pitfalls and the alternative technique of using marking all Properties with this attribute:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;[System.Runtime.CompilerServices.MethodImpl(&lt;br /&gt;      System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The primary issue is around "inlining" methods when the Release code is built. This can result in fewer entries being available on the stack. Therefore a modified GetProperty might work during development but not live.&lt;br /&gt;&lt;br /&gt;I read that there are some situations that prevent inlining:&lt;UL&gt;&lt;br /&gt;&lt;li&gt;Methods that are greater than 32 bytes of IL will not be inlined.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Virtual functions are not inlined.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If any of the method's formal arguments are structs, the method will not be inlined.&lt;/li&gt;&lt;br /&gt;&lt;/UL&gt;A little experimentation showed that marking the SetValue and GetValue methods in my abstract base class as virtual was enough to get a consistent stack in both Debug and Release versions.&lt;br /&gt;&lt;br /&gt;For now this appears to be working OK but I might need to revisit when we move to 64bit Windows &lt;a href="http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx"&gt;Release IS NOT Debug: 64bit Optimizations and C# Method Inlining in Release Build Call Stacks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Important Note:&lt;/strong&gt;Running the Release version from within the IDE does not give the same results as running the application as a standalone .exe&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3958533637650985897?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3958533637650985897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3958533637650985897' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3958533637650985897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3958533637650985897'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/activesharp.html' title='ActiveSharp'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2627408596270399630</id><published>2008-11-17T17:25:00.001Z</published><updated>2008-11-18T17:48:23.876Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Speed of Exceptions</title><content type='html'>I wanted to check for duplicates as entries were being added to my Dictionary collection. I wasn't sure whether to use ContainsKey and check each and every time an item is added or simply sweep up after the Add method throws an Exception.&lt;br /&gt;&lt;br /&gt;In reality the best solution will depend on the likely hit rate of duplicates but I thought I'd write the following code to test the speed differential when the hit rate is 100%.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Using ContainsKey&lt;/strong&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private void Button_Click(object sender, RoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;   DateTime start = DateTime.Now;&lt;br /&gt;   for (int i = 0; i &lt;= 1000; i++)&lt;br /&gt;   {&lt;br /&gt;      if (dummy.ContainsKey("Sunday"))&lt;br /&gt;      {&lt;br /&gt;         dummy["Sunday"]++;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   DateTime end = DateTime.Now;&lt;br /&gt;   MessageBox.Show(end.Subtract(start).TotalMilliseconds.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Using Exceptions&lt;/strong&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private void Button_Click_1(object sender, RoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;   DateTime start = DateTime.Now;&lt;br /&gt;   for (int i = 0; i &lt;= 1000; i++)&lt;br /&gt;   {&lt;br /&gt;      try&lt;br /&gt;      {&lt;br /&gt;         dummy.Add("Sunday", 7);&lt;br /&gt;      }&lt;br /&gt;      catch&lt;br /&gt;      {&lt;br /&gt;         dummy["Sunday"]++;&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   DateTime end = DateTime.Now;&lt;br /&gt;   MessageBox.Show(end.Subtract(start).TotalMilliseconds.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;Results&lt;/strong&gt;&lt;br /&gt;Using ContainsKey: 2 milliseconds&lt;br /&gt;Using Exceptions: 5338 milliseconds&lt;br /&gt;&lt;br /&gt;The ContainsKey adds about 0.04 milliseconds for the 1000 iterations - the rest is the down to the increment of the Dictionary int value.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2627408596270399630?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2627408596270399630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2627408596270399630' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2627408596270399630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2627408596270399630'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/speed-of-exceptions.html' title='Speed of Exceptions'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2135690836156852276</id><published>2008-11-03T10:18:00.000Z</published><updated>2009-01-05T16:41:14.263Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><category scheme='http://www.blogger.com/atom/ns#' term='Routed Commands'/><title type='text'>DelegateCommand vs RoutedCommand vs EventHandler</title><content type='html'>I wanted to evaluate the difference between using the different types of Command mechanisms. The following code snippets aren't intended to be a working example, they simply highlight the code differences.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;DelegateCommand&lt;/strong&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimplePresenter.cs&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;public DelegateCommand&amp;lt;string&amp;gt; GetCustomerByDC { get; private set; }&lt;br /&gt;&lt;br /&gt;GetCustomerByDC = new DelegateCommand&lt;string&gt;(ExecuteGetCustomer, CanExecuteGetCustomer);&lt;br /&gt;&lt;br /&gt;private void ExecuteGetCustomer(string parameter)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    int customerId = int.Parse(parameter);&lt;br /&gt;    GetCustomer(customerId);&lt;br /&gt;  }&lt;br /&gt;  catch { }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;private bool CanExecuteGetCustomer(string parameter)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    int customerId = int.Parse(parameter);&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;  catch&lt;br /&gt;  {&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml.cs&lt;/strong&gt;&lt;br /&gt;ObjectDataProvider odpPresenter = (ObjectDataProvider)this.FindResource("MyPresenter");&lt;br /&gt;Presenter = (SimplePresenter)odpPresenter.ObjectInstance;&lt;br /&gt;Presenter.Model = newModel as SimpleModel;&lt;br /&gt;Presenter.View = this;&lt;br /&gt;private void txtCustomerId_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)&lt;br /&gt;{&lt;br /&gt;  Presenter.GetCustomerByDC.RaiseCanExecuteChanged();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;xmlns:Presenters="clr-namespace:Sandstorm.Documents.Patterns.Presenters"&lt;br /&gt;&amp;lt;ObjectDataProvider x:Key="MyPresenter" d:IsDataSource="True" ObjectType="{x:Type Presenters:SimplePresenter}"/&amp;gt;&lt;br /&gt;&amp;lt;Button &lt;br /&gt;  x:Name="btnGetByDC"&lt;br /&gt;  Command="{Binding Source={StaticResource MyPresenter}, Path=GetCustomerByDC}"&lt;br /&gt;  CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"&lt;br /&gt;  Width="170"&lt;br /&gt;  &amp;gt;Get By DelegateCommand&amp;lt;/Button&amp;gt;&lt;br /&gt;&amp;lt;TextBox&lt;br /&gt;  TextChanged="txtCustomerId_TextChanged"&lt;br /&gt;/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;RoutedCommand&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml.cs&lt;br /&gt;&lt;/strong&gt;private void GetCustomer_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;  if (e.Parameter != null)&lt;br /&gt;  {&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;      int customerId = int.Parse(e.Parameter as string);&lt;br /&gt;      Presenter.GetCustomer(customerId);&lt;br /&gt;    }&lt;br /&gt;    catch { }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;private void GetCustomer_CanExecute(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    int customerId = int.Parse(e.Parameter as string);&lt;br /&gt;    e.CanExecute = true;&lt;br /&gt;  }&lt;br /&gt;  catch&lt;br /&gt;  {&lt;br /&gt;    e.CanExecute = false;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml&lt;/strong&gt;&lt;br /&gt;&amp;lt;UserControl.CommandBindings&amp;gt;&lt;br /&gt;  &amp;lt;CommandBinding&lt;br /&gt;    Command="local:LeisureCommands.GetCustomerCommand"         &lt;br /&gt;    Executed="GetCustomer_Executed"&lt;br /&gt;    CanExecute="GetCustomer_CanExecute"&lt;br /&gt;  /&amp;gt;&lt;br /&gt;&amp;lt;/UserControl.CommandBindings&amp;gt;&lt;br /&gt;&amp;lt;Button &lt;br /&gt;  x:Name="btnGetByRC"&lt;br /&gt;  Command="local:LeisureCommands.GetCustomerCommand"&lt;br /&gt;  CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"         &lt;br /&gt;  Width="170"&lt;br /&gt;&amp;gt;Get By Routed Command&amp;lt;/Button&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;LeisureCommands.cs&lt;/strong&gt;&lt;br /&gt;public class LeisureCommands : RoutedUICommand&lt;br /&gt;{&lt;br /&gt;  public readonly static RoutedUICommand GetCustomerCommand;&lt;br /&gt;  static LeisureCommands()&lt;br /&gt;  {&lt;br /&gt;    GetCustomerCommand = new RoutedUICommand("Get Customer...", "GetCustomerCommand", typeof(LeisureCommands));&lt;br /&gt;    GetCustomerCommand.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Event&lt;/strong&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml.cs&lt;/strong&gt;&lt;br /&gt;private void btnGetByClick_Click(object sender, RoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    int customerId = int.Parse(txtCustomerId.Text);&lt;br /&gt;    Presenter.GetCustomer(customerId);&lt;br /&gt;  }&lt;br /&gt;  catch { }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;&lt;strong&gt;SimpleView.xaml&lt;/strong&gt;&lt;br /&gt;&amp;lt;Button &lt;br /&gt;  x:Name="btnGetByClick" &lt;br /&gt;  Click="btnGetByClick_Click"&lt;br /&gt;  CommandParameter="{Binding ElementName=txtCustomerId, Path=Text}"&lt;br /&gt;  Width="170"&lt;br /&gt;  &amp;gt;Get By Click Event&amp;lt;/Button&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Lines of code&lt;/strong&gt;&lt;br /&gt;&lt;table  style="background-color: #fafac8;border: 1px dashed #999999;"&gt;&lt;tr&gt;&lt;td&gt;Type&lt;/td&gt;&lt;td&gt;Raw&lt;/td&gt;&lt;td&gt;OneOff&lt;/td&gt;&lt;td&gt;Per Command&lt;/td&gt;&lt;td&gt;Can Execute&lt;/td&gt;&lt;td&gt;Total&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;DelegateCommand&lt;/td&gt;&lt;td&gt;40&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;34&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;22&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RoutedCommand&lt;/td&gt;&lt;td&gt;45&lt;/td&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;38&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;26&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Event&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;n/a&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;br /&gt;The RoutedCommand is a little more expensive in LOC terms than the DelegateCommand but the DelegateCommand does not support all the features of the RoutedCommand, in particular: Gestures.&lt;br /&gt;If the "CanExecute" facility is not required the Event is by far the cheapest / easiest to implement.&lt;br /&gt;I guess my conclusion was: "What are the DelegateCommands bringing to the party?"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2135690836156852276?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2135690836156852276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2135690836156852276' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2135690836156852276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2135690836156852276'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/11/delegatecommand-vs-routedcommand-vs.html' title='DelegateCommand vs RoutedCommand vs EventHandler'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3475952011625567498</id><published>2008-10-30T11:22:00.000Z</published><updated>2008-11-03T11:31:26.171Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><category scheme='http://www.blogger.com/atom/ns#' term='Routed Commands'/><title type='text'>Routed Commands</title><content type='html'>Although we have opted to use the DelegateCommand&amp;lt;T&amp;gt; class in our project, this article gives a good overview of the Command pattern used in WPF.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/belux/msdn/nl/community/columns/jdruyts/wpf_commandpattern.mspx"&gt;The Command Pattern In Windows Presentation Foundation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;DelegateCommand&amp;lt;T&amp;gt; class implements ICommand rather than subclassing RoutedCommand. The problem with this is that CanExecute is fired only once. RoutedCommands listen to a number of events and fire CanExecute quite frequently.&lt;br /&gt;DelegateCommand&amp;lt;T&amp;gt; offers the RaiseCanExecuteChanged() method which can be fired manually when some "significant" event happens.&lt;br /&gt;Alternatively a timer could be used to call RaiseCanExecuteChanged() at regular intervals. The following code sample uses a DispatcherTimer to raise the event on the UI thread.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;private void Window_Loaded(object sender, RoutedEventArgs e)&lt;br /&gt;{&lt;br /&gt;   _aTimer.Tick += new EventHandler(_aTimer_Tick);&lt;br /&gt;   _aTimer.Interval = new TimeSpan(0, 0, 1);&lt;br /&gt;   _aTimer.IsEnabled = false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void _aTimer_Tick(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;   _model.MyCommand.RaiseCanExecuteChanged();&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;These are the standard supplied commands:&lt;br /&gt;ApplicationCommands—Close, Copy, Cut, Delete, Find, Help, New, Open, Paste, Print, PrintPreview, Properties, Redo, Replace, Save, SaveAs, SelectAll, Stop, Undo, and more&lt;br /&gt;&lt;br /&gt;ComponentCommands—MoveDown, MoveLeft, MoveRight, MoveUp, ScrollByLine, ScrollPageDown, ScrollPageLeft, ScrollPageRight, ScrollPageUp, SelectToEnd, SelectToHome, SelectToPageDown, SelectToPageUp, and more&lt;br /&gt;&lt;br /&gt;MediaCommands—ChannelDown, ChannelUp, DecreaseVolume, FastForward, IncreaseVolume, MuteVolume, NextTrack, Pause, Play, PreviousTrack, Record, Rewind, Select, Stop, and more&lt;br /&gt;&lt;br /&gt;NavigationCommands—BrowseBack, BrowseForward, BrowseHome, BrowseStop, Favorites, FirstPage, GoToPage, LastPage, NextPage, PreviousPage, Refresh, Search, Zoom, and more&lt;br /&gt;&lt;br /&gt;EditingCommands—AlignCenter, AlignJustify, AlignLeft, AlignRight, CorrectSpellingError, DecreaseFontSize, DecreaseIndentation, EnterLineBreak, EnterParagraphBreak, IgnoreSpellingError, IncreaseFontSize, IncreaseIndentation, MoveDownByLine, MoveDownByPage, MoveDownByParagraph, MoveLeftByCharacter, MoveLeftByWord, MoveRightByCharacter, MoveRightByWord, and more&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3475952011625567498?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3475952011625567498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3475952011625567498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3475952011625567498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3475952011625567498'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/routed-commands.html' title='Routed Commands'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4044342725100873723</id><published>2008-10-28T11:12:00.000Z</published><updated>2008-10-28T11:14:53.930Z</updated><title type='text'>DM-V-VM</title><content type='html'>An interesting series from Dan Crevier's Blog&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/dancre/archive/2006/10/11/datamodel-view-viewmodel-pattern-series.aspx"&gt;DataModel-View-ViewModel Pattern Series&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4044342725100873723?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4044342725100873723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4044342725100873723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4044342725100873723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4044342725100873723'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/dm-v-vm.html' title='DM-V-VM'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8381670545870812394</id><published>2008-10-26T14:47:00.000Z</published><updated>2008-10-26T15:22:43.062Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Accessing Properties from abstract class</title><content type='html'>I wanted my abstract class to hook into the PropertyChanged event for any Property in the derived class that implements INotifyPropertyChanged.&lt;br /&gt;&lt;br /&gt;I use reflection to get all the properties of the derived class then check that they implement the INotifyPropertyChanged interface before adding the event handler.&lt;br /&gt;&lt;br /&gt;The Property must be defined in the "traditional" way rather than using the auto-property syntax otherwise the InitializeProperties method in the abstract class has no object to add the event handlers to.&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class Model : AbstractModel&lt;br /&gt;{&lt;br /&gt;   private Till _till = new Till();&lt;br /&gt;   public Till Till&lt;br /&gt;   {&lt;br /&gt;      get { return _till; }&lt;br /&gt;      set { _till = value; }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;public abstract class AbstractModel : INotifyPropertyChanged&lt;br /&gt;{&lt;br /&gt;  public AbstractModel()&lt;br /&gt;  {&lt;br /&gt;     InitializeProperties();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  private void InitializeProperties()&lt;br /&gt;  {&lt;br /&gt;     PropertyInfo[] propertyInfoList = this.GetType().GetProperties();&lt;br /&gt;&lt;br /&gt;     foreach (PropertyInfo propertyInfo in propertyInfoList)&lt;br /&gt;     {&lt;br /&gt;        object observedObject = propertyInfo.GetValue(this, null);&lt;br /&gt;        if (observedObject is INotifyPropertyChanged)&lt;br /&gt;        {&lt;br /&gt;           (observedObject as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(BusinessPropertyChanged);&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;  ...&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8381670545870812394?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8381670545870812394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8381670545870812394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8381670545870812394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8381670545870812394'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/accessing-properties-from-abstract.html' title='Accessing Properties from abstract class'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7505407199511153909</id><published>2008-10-25T23:23:00.002+01:00</published><updated>2011-03-21T07:02:30.935Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Generics'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Generic Constraints</title><content type='html'>&lt;table&gt;&lt;tr&gt;&lt;td width="200"&gt;&lt;b&gt;Constraint&lt;/b&gt;&lt;/td&gt;&lt;td&gt;&lt;b&gt;Meaning in Life&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;where T : struct&lt;/td&gt;&lt;td&gt;The type parameter &amp;lt;T&amp;gt; must have System.ValueType in its chain of inheritance.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;where T : class&lt;/td&gt;&lt;td&gt;The type parameter &amp;lt;T&amp;gt; must not have System.ValueType in its chain of inheritance (e.g., &amp;lt;T&amp;gt; must be a reference type).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;where T : new()&lt;/td&gt;&lt;td&gt;The type parameter &amp;lt;T&amp;gt; must have a default constructor. This is very helpful if your generic type must create an instance of the type parameter, as you cannot assume the format of custom constructors. Note that this constraint must be listed last on a multiconstrained type.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;where T : NameOfBaseClass&lt;/td&gt;&lt;td&gt;The type parameter &amp;lt;T&amp;gt; must be derived from the class specified by NameOfBaseClass.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;where T : NameOfInterface&lt;/td&gt;&lt;td&gt;The type parameter &amp;lt;T&amp;gt; must implement the interface specified by NameOfInterface.&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;The syntax for defining both inheritance and constraints is:&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;br /&gt;   class FSM&lt;TState, TEvent&gt; : AbstractFSM, INotifyPropertyChanged&lt;br /&gt;      where TState : struct&lt;br /&gt;      where TEvent : struct&lt;br /&gt;   {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;To define multiple constraints for a single type parameter separate them with commas. It seems like "new()" has to be the last in the list.&lt;br /&gt;&lt;div style="BORDER-RIGHT: #999999 1px dashed; PADDING-RIGHT: 5px; BORDER-TOP: #999999 1px dashed; PADDING-LEFT: 5px; BACKGROUND: #eee; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #999999; PADDING-BOTTOM: 5px; OVERFLOW: auto; BORDER-LEFT: #999999 1px dashed; LINE-HEIGHT: 14px; PADDING-TOP: 5px font-size:12px;color:#000000;"  &gt;&lt;pre style="MARGIN: 0px"&gt;&lt;br /&gt;      private void CollectionConstructorTest&lt;TVCollection, TVClass&gt;()&lt;br /&gt;         where TVCollection : VCollection&lt;TVClass&gt;, new()&lt;br /&gt;         where TVClass : VClass, new()&lt;br /&gt;      {&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7505407199511153909?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7505407199511153909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7505407199511153909' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7505407199511153909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7505407199511153909'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/generic-constraint.html' title='Generic Constraints'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8543630368307554676</id><published>2008-10-25T11:13:00.000+01:00</published><updated>2008-10-25T23:50:20.361+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>WPF Cross-Thread Collection Binding</title><content type='html'>From the rather excellent &lt;a href="http://blog.quantumbitdesigns.com/"&gt;QuantumBit Designs&lt;/a&gt; there are a series of articles about multithreading and collections.&lt;br /&gt;&lt;br /&gt;The "grand solution" can be found here: &lt;a href="http://blog.quantumbitdesigns.com/2008/07/22/wpf-cross-thread-collection-binding-part-4-the-grand-solution/"&gt;WPF Cross-Thread Collection Binding - Part 4 - The Grand Solution&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Features&lt;/strong&gt;&lt;br /&gt;-Allows WPF to bind to a collection that is modified from any thread&lt;br /&gt;-Allows WPF to bind to properties of items in the collection that are modified from any thread&lt;br /&gt;-No lock required if used from a single worker thread&lt;br /&gt;-Relatively simple (compared to some other attempts)&lt;br /&gt;-Non-blocking&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Downsides&lt;/strong&gt;&lt;br /&gt;-Requires two lists internally&lt;br /&gt;-The ObservableCollection list should not be modified&lt;br /&gt;-Disposable or DependencyObjects should not be used&lt;br /&gt;&lt;br /&gt;I've implemented the ObservableList in the test project InABind but we haven't confirmed the overhead involved of using ObservableList in place of ObservableCollection.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8543630368307554676?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8543630368307554676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8543630368307554676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8543630368307554676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8543630368307554676'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/wpf-cross-thread-collection-binding.html' title='WPF Cross-Thread Collection Binding'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-5882447699967364659</id><published>2008-10-25T10:16:00.000+01:00</published><updated>2008-10-26T12:03:52.536Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>Memory Usage</title><content type='html'>The Sandstorm client app is currently using about 83mb of RAM at runtime. It also consumes up to 25% of CPU time when idle. When the app is minimised the CPU usage drops to 0%. The CPU usage is regardless of whether Sandstorm is being run from within the VS2008 IDE.&lt;br /&gt;&lt;br /&gt;I ran a little test app and its RAM footprint topped out at 39mb when run inside the VS2008 IDE. Running as a standalone exe it used a more "modest" 23mb. Interestingly it used no CPU time when idle.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx"&gt;Finding memory leaks in WPF based applications&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/micmcd/archive/2008/03/07/avoiding-a-wpf-memory-leak-with-databinding-black-magic.aspx"&gt;Avoiding WPF Memory leak with Databinding&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/default.aspx/kb/938416"&gt;A memory leak may occur when you use data binding in Windows Presentation Foundation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Martin and I concluded that we need to implement INotifyPropertyChanged on any class that will be involved in Databinding. The most likely route will be to derive all the relevant classes from a base class that implements INPC.&lt;br /&gt;&lt;br /&gt;This tool has a "visual profiler" which shows a graph of CPU usage.&lt;br /&gt; &lt;br /&gt;&lt;a href="http://windowsclient.net/wpf/perf/wpf-perf-tool.aspx#profiler"&gt;WPF Performance Tool&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-5882447699967364659?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/5882447699967364659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=5882447699967364659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5882447699967364659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/5882447699967364659'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/memory-usage.html' title='Memory Usage'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2643612551081500877</id><published>2008-10-21T07:59:00.000+01:00</published><updated>2008-10-21T08:03:11.390+01:00</updated><title type='text'>INotifyPropertyChanged</title><content type='html'>We've had a problem with classes that implement this interface failing to serialize. The solution would appear to be this attribute:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;[field:NonSerialized]&lt;br /&gt;&lt;br /&gt;public event PropertyChangedEventHandler PropertyChanged;&lt;/code&gt;&lt;/pre&gt;That attribute prevents the delegate field which the compiler emits to implement the PropertyChanged event from being serialized.  Since a delegate internally stores hard references to its listeners, you need to prevent that delegate from being serialized.  If the delegate were serialized then it would attempt to serialize the objects to which it points.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2643612551081500877?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2643612551081500877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2643612551081500877' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2643612551081500877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2643612551081500877'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/inotifypropertychanged.html' title='INotifyPropertyChanged'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3364219159658543294</id><published>2008-10-21T07:55:00.000+01:00</published><updated>2008-10-21T07:57:03.472+01:00</updated><title type='text'>Expression Blend - with Diagnostics</title><content type='html'>There’s an interesting point in this post which states you can run Expression with the –diagnostics command line argument and it brings in a Debug menu with some interesting diagnostics/performance options&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/johngossman/archive/2008/10/16/expression-architecture.aspx"&gt;http://blogs.msdn.com/johngossman/archive/2008/10/16/expression-architecture.aspx&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3364219159658543294?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3364219159658543294/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3364219159658543294' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3364219159658543294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3364219159658543294'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/expression-blend-with-diagnostics.html' title='Expression Blend - with Diagnostics'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3868826338061007484</id><published>2008-10-19T10:45:00.001+01:00</published><updated>2008-10-21T07:25:16.601+01:00</updated><title type='text'>ObservableCollection&lt;T&gt;</title><content type='html'>Following on from the previous post where I noted that ObservableCollection&amp;lt;T&amp;gt;.CollectionChanged didn't do what I wanted, I've created my own version of ObservableCollection that exposes a new event ItemPropertyChanged. I then hook up to the PropertyChanged event of the business object as it is added to the collection. The new class adds a new property HasChanges which reflects the change status of any property in any business object in the collection.&lt;br /&gt;&lt;br /&gt;Caveats:&lt;br /&gt;The business object must implement INotifyPropertyChanged.&lt;br /&gt;There is no "undo" mechanism to set the HasChanges flag back to false&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class MyObservableCollection&lt;T&gt; : ObservableCollection&lt;T&gt;&lt;br /&gt;{&lt;br /&gt;   public new void Add(T item)&lt;br /&gt;   {&lt;br /&gt;      // If the class represented by T implements the INotifyPropertyChanged&lt;br /&gt;      // interface hook up the PropertyChanged event handler&lt;br /&gt;      if ((item as INotifyPropertyChanged) != null)&lt;br /&gt;      {&lt;br /&gt;         (item as INotifyPropertyChanged).PropertyChanged += new PropertyChangedEventHandler(OnItemPropertyChanged);&lt;br /&gt;      }&lt;br /&gt;      base.Add(item);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public bool HasChanges { get; set; }&lt;br /&gt;   public event PropertyChangedEventHandler ItemPropertyChanged;&lt;br /&gt;   public MyObservableCollection()&lt;br /&gt;   {&lt;br /&gt;      HasChanges = false;&lt;br /&gt;   }&lt;br /&gt;   protected void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)&lt;br /&gt;   {&lt;br /&gt;      HasChanges = true;&lt;br /&gt;      OnPropertyChanged("HasChanges");&lt;br /&gt;   }&lt;br /&gt;   protected void OnPropertyChanged(string propertyName)&lt;br /&gt;   {&lt;br /&gt;      if (ItemPropertyChanged != null)&lt;br /&gt;      {&lt;br /&gt;         ItemPropertyChanged(this, new PropertyChangedEventArgs(propertyName));&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;If an object of this type is bound directly to the DataContext (or ObjectDataProvider) the HasChanges property can be referenced directly in the xaml.&lt;br /&gt;&lt;br /&gt;If the collection object is intantiated by a Model class the Model will need to implement INotifyPropertyChanged and expose its own HasChanges property with its value set by wiring up the ItemPropertyChanged event:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public MyObservableCollection&lt;Till&gt; Abc { get; set; }&lt;br /&gt;&lt;br /&gt;public Model()&lt;br /&gt;{&lt;br /&gt;   Abc = new MyObservableCollection&lt;Till&gt;();&lt;br /&gt;   Abc.ItemPropertyChanged += new PropertyChangedEventHandler(BusinessPropertyChanged);&lt;br /&gt;}&lt;br /&gt;public bool HasChanges&lt;br /&gt;{&lt;br /&gt;   get { return Abc.HasChanges; }&lt;br /&gt;}&lt;br /&gt;protected void BusinessPropertyChanged(object sender, PropertyChangedEventArgs e)&lt;br /&gt;{&lt;br /&gt;   OnPropertyChanged("HasChanges");&lt;br /&gt;}&lt;br /&gt;public event PropertyChangedEventHandler PropertyChanged;&lt;br /&gt;protected void OnPropertyChanged(string propertyName)&lt;br /&gt;{&lt;br /&gt;   if (PropertyChanged != null)&lt;br /&gt;   {&lt;br /&gt;      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3868826338061007484?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3868826338061007484/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3868826338061007484' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3868826338061007484'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3868826338061007484'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/observablecollection.html' title='ObservableCollection&amp;lt;T&amp;gt;'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-3003070154483697329</id><published>2008-10-17T23:22:00.000+01:00</published><updated>2008-10-17T23:34:02.023+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><title type='text'>ObservableCollection&lt;T&gt;.CollectionChanged</title><content type='html'>According to the documentation: "This event occurs when an item is added, removed, changed, moved or the entire list is refreshed."&lt;br/&gt;&lt;br /&gt;However it does not occur if a property on an object in the collection changes, even if that object implements the INotifyPropertyChanged.&lt;br/&gt;&lt;br /&gt;The new value of the object's property is reflected in the UI automatically (as you would expect of an ObservableCollection).&lt;br/&gt;&lt;br /&gt;I wanted to know that something inside the collection had changed so that I could set a HasChanges property on the Model that the UI is bound to via its ObjectDataProvider. The intention was then to have a visual clue on the UI that was bound to the HasChanges property.&lt;br/&gt;&lt;br /&gt;This posting doesn't have a solution, its simply a reminder not to try to use this event for this purpose in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-3003070154483697329?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/3003070154483697329/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=3003070154483697329' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3003070154483697329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/3003070154483697329'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/observablecollection-collectionchanged.html' title='ObservableCollection&amp;lt;T&amp;gt;.CollectionChanged'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7839379551984457984</id><published>2008-10-14T16:19:00.000+01:00</published><updated>2008-10-15T07:29:01.273+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Event Handlers'/><category scheme='http://www.blogger.com/atom/ns#' term='VisualTree'/><title type='text'>Walking the VisualTree</title><content type='html'>This isn't all my own code but I thought it might be handy to keep track of some code that walks the VisualTree recursively and also does something with event handlers.&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;AddHandlers(this);&lt;br /&gt;  &lt;br /&gt;public void AddHandlers(DependencyObject dependencyObject)&lt;br /&gt;{&lt;br /&gt;  int childCount = VisualTreeHelper.GetChildrenCount(dependencyObject);&lt;br /&gt;  for (int childIndex = 0; childIndex &lt; childCount; childIndex++)&lt;br /&gt;  &lt;br /&gt;    DependencyObject childObject = VisualTreeHelper.GetChild(dependencyObject, childIndex);&lt;br /&gt;      &lt;br /&gt;    // In this example we're only interested in TextBoxes&lt;br /&gt;    if (childObject is TextBox)&lt;br /&gt;    {&lt;br /&gt;      if ((childObject as TextBox).GetBindingExpression(TextBox.TextProperty).ParentBinding.UpdateSourceTrigger == UpdateSourceTrigger.PropertyChanged)&lt;br /&gt;      {&lt;br /&gt;        (childObject as TextBox).TextChanged += new TextChangedEventHandler(TextBox_TextChanged);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    AddHandlers(childObject);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7839379551984457984?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7839379551984457984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7839379551984457984' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7839379551984457984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7839379551984457984'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/walking-visualtree.html' title='Walking the VisualTree'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2553262186647288576</id><published>2008-10-13T09:16:00.000+01:00</published><updated>2008-10-13T09:18:39.029+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Constructor'/><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><title type='text'>Page / Window Constructor</title><content type='html'>According to Rockford Lhotka:&lt;br /&gt;&lt;br /&gt;"Putting code in a Page/Window constructor is bad. Yes, I know it is the “C# way”, but it is bad. The “VB way” of putting code in the Loaded event handler is better.&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;Because any exceptions thrown in the constructor prevent the page/window from loading at all, and you have to catch those exceptions in the code that is creating the page/window. In many navigation scenarios you can’t catch them, so the user gets an ugly WPF exception dialog.&lt;br /&gt;&lt;br /&gt;However, if you do all your init work in the Loaded event handler, the page/window instance already exists. Navigation has already happened, so the “calling code” is no longer responsible for your page/window going haywire. Instead, you can actually handle the exception and show a nice dialog, explaining to the user what happened, and you can (if desired) navigate somewhere else or whatever."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2553262186647288576?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2553262186647288576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2553262186647288576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2553262186647288576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2553262186647288576'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/page-window-constructor.html' title='Page / Window Constructor'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4837889304067867858</id><published>2008-10-06T23:10:00.000+01:00</published><updated>2008-10-19T21:33:25.479+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Sorting a collection using Linq and 'SortExpression' string</title><content type='html'>&lt;div&gt;Bruce suggested that we use LINQ to sort collections. I found the following code on &lt;a href="http://mironabramson.com/blog/post/2008/05/Sorting-a-collection-using-sort-expression-string.aspx"&gt;Miron Abrahason's blog&lt;/a&gt; but haven't had the chance to try it out yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Already happened to you that you had a collection of object from type 'X' with some properties, and you had to sort it one time by property 'ID', and another time by property 'Name' ? You wished that you can sort it by just using a 'Sort Expression' ? If still not, I'm sure this moment will arrive sooner or later. Let me save you some time and an headache.&lt;br /&gt;&lt;br /&gt;This is how it can be done:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public static IEnumerable Sort(this IEnumerable source, string sortExpression)&lt;br /&gt;{&lt;br /&gt;    string[] sortParts = sortExpression.Split(' ');&lt;br /&gt;    var param = Expression.Parameter(typeof(T), string.Empty);&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        var property = Expression.Property(param, sortParts[0]);&lt;br /&gt;        var sortLambda = Expression.Lambda&gt;(Expression.Convert(property,         typeof(object)), param);&lt;br /&gt;        if (sortParts.Length &gt; 1 &amp;&amp; sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))&lt;br /&gt;        {&lt;br /&gt;            return source.AsQueryable().OrderByDescending(sortLambda);&lt;br /&gt;        }&lt;br /&gt;        return source.AsQueryable().OrderBy(sortLambda);&lt;br /&gt;    }&lt;br /&gt;    catch (ArgumentException)&lt;br /&gt;    {&lt;br /&gt;        return source;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Just drop it in a static class, and you will be able to sort any collection that implement the interface IEnumerable.&lt;br /&gt;&lt;br /&gt;Lets say you have a class 'User':&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;public class User&lt;br /&gt;{&lt;br /&gt;    public int ID { get; set; }&lt;br /&gt;    public string Name { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;and a List&lt;user&gt; collection: users. You can sort it however you want:&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;IEnumerable sortedUsersIEnumerable = users.Sort("ID desc");&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Or&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;List sortedUsersList = users.Sort("Name").ToList();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4837889304067867858?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4837889304067867858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4837889304067867858' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4837889304067867858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4837889304067867858'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/sorting-collection-using-linq-and.html' title='Sorting a collection using Linq and &apos;SortExpression&apos; string'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4150678861559877612</id><published>2008-10-05T14:11:00.001+01:00</published><updated>2008-10-05T17:33:47.630+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Focus'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>WPF Keyboard Focus</title><content type='html'>&lt;DIV&gt;Mark Smith posted a series of very practical series of three articles about this subject.&lt;/DIV&gt;&lt;br /&gt;&lt;A href="http://www.julmar.com/blog/mark/PermaLink,guid,2974164f-97c1-4e20-85f9-416cf6bed219.aspx"&gt;Part 1: It's Basically Focus&lt;/A&gt;&lt;br /&gt;&lt;A href="http://www.julmar.com/blog/mark/PermaLink,guid,6e4769e5-a0b3-47b2-a142-6dfefd0c028e.aspx"&gt;Part 2: Changing WPF Focus in Code&lt;/A&gt;&lt;br /&gt;&lt;A href="http://www.julmar.com/blog/mark/PermaLink,guid,03722678-882a-4bb4-928f-4fe0d35f051e.aspx"&gt;Part 3: Shifting focus to the first available element in WPF&lt;/A&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4150678861559877612?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4150678861559877612/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4150678861559877612' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4150678861559877612'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4150678861559877612'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/wpf-keyboard-focus.html' title='WPF Keyboard Focus'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-866122831670614936</id><published>2008-10-05T14:09:00.001+01:00</published><updated>2008-10-05T17:34:25.770+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Exceptions'/><category scheme='http://www.blogger.com/atom/ns#' term='.Net'/><title type='text'>Exceptions in Converters</title><content type='html'>Karl Shifflett says:&lt;br/&gt;&lt;br /&gt;It is vital that your value converters not throw or be allowed to bubble exceptions because the data binding pipeline does not catch, swallow or handle these exceptions. Instead your users will get those messy exceptions messages because there is no method to catch and handle exceptions in XAML markup. Ensure that if your converter fails that you gracefully handle this conversion or convert back operation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-866122831670614936?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/866122831670614936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=866122831670614936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/866122831670614936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/866122831670614936'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/exceptions-in-converters.html' title='Exceptions in Converters'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-4221483496255306595</id><published>2008-10-05T14:06:00.000+01:00</published><updated>2008-10-05T17:34:55.628+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Converters'/><category scheme='http://www.blogger.com/atom/ns#' term='Validation'/><title type='text'>Validation and Conversion</title><content type='html'>The default order is for the ValidationRule to be called before the ConvertBack method of the IValueConverter. This means that the ValidationRule may have to do the same conversion as the converter before it can do the validation.&lt;br /&gt;&lt;br /&gt;This order can be changed by specifying the ValidationStep.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&amp;lt;TextBox&lt;br /&gt;      MinWidth="100"&lt;br /&gt;      Style="{StaticResource tbStyle}"&lt;br /&gt;      &amp;gt;&lt;br /&gt;   &amp;lt;Binding Path="Dob" Converter="{StaticResource dateFormattingConverter}"&amp;gt;&lt;br /&gt;      &amp;lt;Binding.ValidationRules&amp;gt;&lt;br /&gt;         &amp;lt;app:DobValidationRule &lt;strong&gt;&lt;span style="font-size:110%;"&gt;ValidationStep="ConvertedProposedValue"&lt;/span&gt;&lt;/strong&gt;/&amp;gt;&lt;br /&gt;      &amp;lt;/Binding.ValidationRules&amp;gt;&lt;br /&gt;   &amp;lt;/Binding&amp;gt;&lt;br /&gt;&amp;lt;/TextBox&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-4221483496255306595?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/4221483496255306595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=4221483496255306595' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4221483496255306595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/4221483496255306595'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/validation-and-conversion.html' title='Validation and Conversion'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-465917662682144890</id><published>2008-10-05T14:05:00.001+01:00</published><updated>2008-10-05T17:35:26.121+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><title type='text'>Resource inheritance</title><content type='html'>&lt;DIV&gt;&lt;br /&gt;&lt;P dir=ltr&gt;&lt;FONT size=3&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;If dictionaries being merged have a duplicate key, the last one wins (unlike the case of having duplicate keys in a single dictionary).&amp;nbsp; Thus&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt; &lt;FONT face=Calibri&gt;inheritance can be handled by the order in which the MergeDictionaries are loaded in the ResourceDictionary section&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;…&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt; Start by loading the BASE, then the next down etc.. and it&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;’&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;ll override every time it meets a duplicate.&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/FONT&gt; &lt;br /&gt;&lt;P dir=ltr&gt;&lt;FONT size=3&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;For reference&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt; &lt;FONT face=Calibri&gt;–&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt; it&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;’&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN lang=en-us&gt;&lt;FONT face=Calibri&gt;s on page 250ish in Martin's Unleashed book&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-465917662682144890?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/465917662682144890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=465917662682144890' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/465917662682144890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/465917662682144890'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/resource-inheritance.html' title='Resource inheritance'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7319214239087027075</id><published>2008-10-05T14:03:00.000+01:00</published><updated>2008-10-05T17:35:47.698+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><title type='text'>Dynamic vs Static Resources :</title><content type='html'>SR means the resource is applied only once (the 1st time it’s needed).&lt;br/&gt;&lt;br /&gt;DR means the resource is reapplied every time it changes.&lt;br/&gt;&lt;br /&gt;The main difference between DR and SR is that any subsequent updates to the resource are reflected only to those elements that use DR.&lt;br/&gt;&lt;br /&gt;SR and DR have different performance characteristics.  DR requires more overhead than SR because of the extra overhead of tracking, while DR can potentially improve load time because SR are always loaded when the Window or Page loads, whereas the DR reference is only loaded when it’s actually used.&lt;br/&gt;&lt;br /&gt;DR can also only set dependency properties whereas SR can be used almost anywhere&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7319214239087027075?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7319214239087027075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7319214239087027075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7319214239087027075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7319214239087027075'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/dynamic-vs-static-resources.html' title='Dynamic vs Static Resources :'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-1680706391681202590</id><published>2008-10-05T14:01:00.000+01:00</published><updated>2008-10-05T17:36:11.211+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='Resources'/><title type='text'>How are StaticResource and DynamicResource different</title><content type='html'>&lt;DIV&gt;&lt;br /&gt;&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;This was copied from &lt;A href="http://wpfxaml.spaces.live.com/blog/cns!97DD5FD32788695B!142.entry"&gt;http://wpfxaml.spaces.live.com/blog/cns!97DD5FD32788695B!142.entry&lt;/A&gt;&amp;nbsp;for my own easy reference&lt;/FONT&gt;&lt;/SPAN&gt; &lt;br /&gt;&lt;P&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;Everyone one knows that StaticResource let’s one set&amp;nbsp;a property&amp;nbsp;of an element once.&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;If the Desktop Color is changed while the element’s application is running, the element keeps its original color:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt; &lt;br /&gt;&lt;P&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;br /&gt;&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button.Background&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;SolidColorBrush&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: red; FONT-FAMILY: Consolas"&gt;Color&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;=&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;FONT color=#000000&gt;"&lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt;{StaticResource {x:Static SystemColors.DesktopColorKey}}&lt;/SPAN&gt;&lt;FONT color=#000000&gt;"&lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt; /&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button.Background&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;FONT color=#000000&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Hello&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;/SPAN&gt; &lt;br /&gt;&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;FONT color=#000000&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;br /&gt;&lt;P&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;On the other hand, if the element’s color is set using a DynamicResource, it changes when the Desktop Color changes:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt; &lt;br /&gt;&lt;P&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button.Background&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;SolidColorBrush&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: red; FONT-FAMILY: Consolas"&gt;Color&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;=&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;FONT color=#000000&gt;"&lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt;{DynamicResource {x:Static SystemColors.DesktopColorKey}}&lt;/SPAN&gt;&lt;FONT color=#000000&gt;"&lt;/FONT&gt;&lt;SPAN style="COLOR: blue"&gt; /&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button.Background&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Consolas"&gt;&lt;FONT color=#000000&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Hello&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: Consolas"&gt;Button&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Consolas"&gt;&amp;gt;&lt;/SPAN&gt; &lt;br /&gt;&lt;P&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;Why is that? The answer comes from the way these two Resource finders work:&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt; &lt;br /&gt;&lt;P&gt;&lt;FONT color=#000000&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1.&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;StaticResource – Finds the resource given in by the ResourceDictionary key, and keeps the resource value;&lt;BR&gt;&lt;/SPAN&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;SPAN&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2.&lt;SPAN style="FONT: 7pt 'Times New Roman'"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;DynamicResource – Finds the resource in the ResourceDictionary and keeps the key.&lt;/SPAN&gt;&lt;/FONT&gt; &lt;br /&gt;&lt;P&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;So, it is simple, really. &lt;BR&gt;Since DynamicResource keeps the resource Key instead of the resource value, every event change fired from the resource lets the DynamicResource know that its value has changed.&lt;BR&gt;&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;B&gt;&lt;SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Segoe UI','sans-serif'"&gt;&lt;FONT color=#000000&gt;This is why the DynamicResource reacts to the resource changes, while the StaticResource can’t know the resource has changed, since it only keeps the resource’s final value.&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-1680706391681202590?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/1680706391681202590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=1680706391681202590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1680706391681202590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1680706391681202590'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/how-are-staticresource-and.html' title='How are StaticResource and DynamicResource different'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-1798190898134122199</id><published>2008-10-05T13:59:00.000+01:00</published><updated>2008-10-05T17:36:48.037+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Formatting'/><title type='text'>C# String Formatting</title><content type='html'>&lt;p&gt;This entry has been copied from SteveX (&lt;a href="http://blog.stevex.net/index.php/string-formatting-in-csharp/"&gt;http://blog.stevex.net/index.php/string-formatting-in-csharp/&lt;/a&gt;) for my own easy reference.&lt;br /&gt;&lt;p&gt;The text inside the curly braces is &lt;b&gt;{&lt;i&gt;index&lt;/i&gt;[,&lt;i&gt;alignment&lt;/i&gt;][:&lt;i&gt;formatString&lt;/i&gt;]}&lt;/b&gt;. If alignment is positive, the text is right-aligned in a field the given number of spaces; if it’s negative, it’s left-aligned.&lt;br /&gt;&lt;h3&gt;&lt;span style="font-family:Verdana;"&gt;Strings&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;There really isn’t any formatting within a string, beyond it’s alignment. Alignment works for any argument being printed in a String.Format call.&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Sample&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Generates&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;String.Format(”-&amp;gt;{1,10}&amp;lt;-”, “Hello”);&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;-&amp;gt; Hello&amp;lt;-&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;String.Format(”-&amp;gt;{1,-10}&amp;lt;-”, “Hello”);&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;-&amp;gt;Hello &amp;lt;-&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-family:Verdana;"&gt;Numbers&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Basic number formatting specifiers:&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Specifier&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Type&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Format &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Output (Passed Double 1.42)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Output (Passed Int -12400)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;c&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Currency&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:c}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;$1.42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-$12,400&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;d&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Decimal (Whole number)&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:d}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;System.FormatException&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-12400&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;e&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Scientific&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:e}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1.420000e+000&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-1.240000e+004&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;f&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Fixed point&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:f}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1.42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-12400.00&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;g&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;General&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:g}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1.42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-12400&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;n&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Number with commas for thousands&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:n}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1.42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-12,400&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;r&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Round trippable&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:r}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1.42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;System.FormatException&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;x&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Hexadecimal&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:x4}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;System.FormatException&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;cf90&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;Custom number formatting:&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Specifier&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Type&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Example &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Output (Passed Double 1500.42)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Note&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Zero placeholder&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:00.0000}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1500.4200&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Pads with zeroes.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;#&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Digit placeholder&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:(#).##}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;(1500).42&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Decimal point&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:0.0}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1500.4&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;,&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Thousand separator&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:0,0}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;1,500&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Must be between two zeroes.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;,.&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Number scaling&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;span style="font-family:Courier New;"&gt;{0:0,.}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Comma adjacent to Period scales by 1000.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;%&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Percent&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:0%}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;150042%&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Multiplies by 100, adds % sign.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;e&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Exponent placeholder&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:00e+0}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;15e+2&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Many exponent formats available.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Group separator&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;see below&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;The group separator is especially useful for formatting currency values which require that negative values be enclosed in parentheses. This currency formatting example at the bottom of this document makes it obvious:&lt;br /&gt;&lt;h3&gt;&lt;span style="font-family:Verdana;"&gt;Dates&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Note that date formatting is especially dependant on the system’s regional settings; the example strings here are from my local locale.&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Specifier&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Type&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Example (Passed System.DateTime.Now)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;d&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Short date&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10/12/2002&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;D&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Long date&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December 10, 2002&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;t&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Short time&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10:11 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;T&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Long time&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10:11:29 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;f&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Full date &amp;amp; time &lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December 10, 2002 10:11 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;F&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Full date &amp;amp; time (long)&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December 10, 2002 10:11:29 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;g&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Default date &amp;amp; time&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10/12/2002 10:11 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;G&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Default date &amp;amp; time (long)&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10/12/2002 10:11:29 PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;M&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Month day pattern&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December 10&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;r&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;RFC1123 date string&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Tue, 10 Dec 2002 22:11:29 GMT&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;s&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Sortable date string&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2002-12-10T22:11:29&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;u&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Universal sortable, local time&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2002-12-10 22:13:50Z&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;U&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Universal sortable, GMT&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December 11, 2002 3:13:50 AM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;Y&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Year month pattern&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December, 2002&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;The ‘U’ specifier seems broken; that string certainly isn’t sortable.&lt;br /&gt;&lt;p&gt;&lt;b&gt;Custom date formatting:&lt;/b&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Specifier&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Type&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Example &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Example Output&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;dd&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Day&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:dd}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;ddd&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Day name&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:ddd}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Tue&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;dddd&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Full day name&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:dddd}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Tuesday&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;f, ff, …&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Second fractions&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:fff}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;932&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;gg, …&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Era&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:gg}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;A.D.&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;hh&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2 digit hour&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:hh}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;HH&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2 digit hour, 24hr format&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:HH}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;22&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;mm&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Minute 00-59&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:mm}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;38&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;MM&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Month 01-12&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:MM}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;12&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;MMM&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Month abbreviation&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:MMM}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Dec&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;MMMM&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Full month name&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:MMMM}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;December&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;ss&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Seconds 00-59&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:ss}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;46&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;tt&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;AM or PM&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:tt}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;PM&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;yy&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Year, 2 digits&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:yy}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;02&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;yyyy&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Year&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:yyyy}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;2002&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;zz&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Timezone offset, 2 digits&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:zz}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-05&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;zzz&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Full timezone offset&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:zzz}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;-05:00&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Separator&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:hh:mm:ss}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10:43:20&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;/&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Separator&lt;/span&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;{0:dd/MM/yyyy}&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;10/12/2002&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-family:Verdana;"&gt;Enumerations&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Specifier&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;td align="middle" bg style="color:#c0c0c0;"&gt;&lt;b&gt;&lt;span style="font-size:85%;"&gt;Type&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;g&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Default (Flag names if available, otherwise decimal)&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;f&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Flags always&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;d&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Integer always&lt;/span&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td align="middle"&gt;&lt;span style="font-size:85%;"&gt;x&lt;/span&gt;&lt;br /&gt;&lt;td&gt;&lt;span style="font-size:85%;"&gt;Eight digit hex.&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;h3&gt;&lt;span style="font-family:Verdana;"&gt;Some Useful Examples&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;String.Format(”{0:$#,##0.00;($#,##0.00);Zero}”, value);&lt;/span&gt;&lt;br /&gt;&lt;blockquote style="margin-top:0;margin-bottom:0;"&gt;&lt;br /&gt;&lt;p&gt;This will output “$1,240.00″ if passed 1243.50. It will output the same format but in parentheses if the number is negative, and will output the string “Zero” if the number is zero.&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:Courier New;font-size:85%;"&gt;String.Format(”{0:(###) ###-####}”, 8005551212);&lt;/span&gt;&lt;br /&gt;&lt;blockquote style="margin-top:0;margin-bottom:0;"&gt;&lt;br /&gt;&lt;p&gt;This will output “(800) 555-1212″.&lt;/p&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-1798190898134122199?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/1798190898134122199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=1798190898134122199' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1798190898134122199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/1798190898134122199'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/c-string-formatting.html' title='C# String Formatting'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-8345866899213153598</id><published>2008-10-05T13:51:00.000+01:00</published><updated>2008-10-05T17:37:31.160+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WPF'/><category scheme='http://www.blogger.com/atom/ns#' term='ComboBox'/><category scheme='http://www.blogger.com/atom/ns#' term='Data Binding'/><title type='text'>WPF ComboBox Data Binding</title><content type='html'>Binding a enum property (&lt;span style="color:#ff9900;"&gt;BlockBookingData.Frequency&lt;/span&gt;) to a WPF ComboBox.&lt;br /&gt;&lt;br /&gt;This property provides the ItemsSource for the combobox by building a dictionary of enum (key) and enum.ToString (value).&lt;br /&gt;&lt;br /&gt;public IDictionary&lt;frequency,&gt; FrequencyList&lt;br /&gt;{&lt;br /&gt;get&lt;br /&gt;{&lt;br /&gt;IDictionary&lt;frequency,&gt; frequencyList = new Dictionary&lt;frequency,&gt;();&lt;br /&gt;frequencyList.Add(Frequency.DayOfPlay, Frequency.DayOfPlay.ToString());&lt;br /&gt;frequencyList.Add(Frequency.Monthly, Frequency.Monthly.ToString());&lt;br /&gt;frequencyList.Add(Frequency.None, Frequency.None.ToString());&lt;br /&gt;frequencyList.Add(Frequency.Quarterly, Frequency.Quarterly.ToString());&lt;br /&gt;frequencyList.Add(Frequency.Weekly, Frequency.Weekly.ToString());&lt;br /&gt;return frequencyList;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;The corresponding xaml:&lt;br /&gt;&amp;lt;ComboBox  &lt;br /&gt; ItemsSource="{Binding FrequencyList}"  &lt;br /&gt; SelectedValuePath="Key"  &lt;br /&gt; DisplayMemberPath="Value"  &lt;br /&gt; SelectedValue="{Binding BlockBookingData.Frequency}"&amp;gt;&lt;br /&gt;&amp;lt;/ComboBox&amp;gt;&lt;br /&gt;&lt;combobox itemssource="{Binding FrequencyList}" selectedvaluepath="Key" displaymemberpath="Value" selectedvalue="{Binding BlockBookingData.Frequency}"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/combobox&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-8345866899213153598?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/8345866899213153598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=8345866899213153598' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8345866899213153598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/8345866899213153598'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/binding-enum-property-blockbookingdata.html' title='WPF ComboBox Data Binding'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-7386178304329772102</id><published>2008-10-05T13:48:00.001+01:00</published><updated>2009-03-15T08:43:56.184Z</updated><title type='text'>CompareTo method</title><content type='html'>CompareTo() is very easy to understand but I just seem to have a blind spot about it.&lt;br /&gt;&lt;br /&gt;int result = instance.CompareTo(obj);&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Meaning&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Less than zero&lt;/td&gt;&lt;td&gt;instance is less than obj&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Zero&lt;/td&gt;&lt;td&gt;instance is equal to obj&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Greater than zero&lt;/td&gt;&lt;td&gt;instance is greater than obj&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;For this&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Use this&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;if (instance &lt; obj)&lt;/td&gt;&lt;td&gt;if (instance.CompareTo(obj) &lt; 0)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;if (instance &lt;= obj)&lt;/td&gt;&lt;td&gt;if (instance.CompareTo(obj) &lt;= 0)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;if (instance == obj)&lt;/td&gt;&lt;td&gt;if (instance.CompareTo(obj) == 0)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;if (instance &gt; obj)&lt;/td&gt;&lt;td&gt;if (instance.CompareTo(obj) &gt; 0)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;if (instance &gt;= obj)&lt;/td&gt;&lt;td&gt;if (instance.CompareTo(obj) &gt;= 0)&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-7386178304329772102?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/7386178304329772102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=7386178304329772102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7386178304329772102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/7386178304329772102'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/compareto-method.html' title='CompareTo method'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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-7059224265445023060.post-2308041480200729009</id><published>2008-10-05T13:42:00.000+01:00</published><updated>2009-01-27T07:29:31.251Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='Collections'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Sorting Generic Collections</title><content type='html'>You can simplify the sorting by using the anonymous delegate as shown below and you don't need to implement IComparable interface:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;(Note: For a simpler technique using LINQ see: &lt;a href="http://mikestedman.blogspot.com/2009/01/sorting-dictionary.html"&gt;Sorting Generic Collections - Redux)&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;pre style="font-family: Courier New, Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; "&gt;&lt;code&gt;List&lt;person&gt; persons = new List&lt;person&gt;();&lt;br /&gt;persons.Add( new Person("Tom",30) );&lt;br /&gt;persons.Add(new Person("Harry", 55));&lt;br /&gt;&lt;br /&gt;// sort in ascending order&lt;br /&gt;persons.Sort( delegate(Person person0, Person person1)&lt;br /&gt;{&lt;br /&gt;return&lt;br /&gt;person0.FirstName.CompareTo(person1.FirstName);&lt;br /&gt;} );&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// sort in descending order&lt;br /&gt;persons.Sort( delegate(Person person0, Person person1)&lt;br /&gt;{&lt;br /&gt;return&lt;br /&gt;person1.FirstName.CompareTo(person0.FirstName);&lt;br /&gt;} );&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7059224265445023060-2308041480200729009?l=mikestedman.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mikestedman.blogspot.com/feeds/2308041480200729009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7059224265445023060&amp;postID=2308041480200729009' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2308041480200729009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7059224265445023060/posts/default/2308041480200729009'/><link rel='alternate' type='text/html' href='http://mikestedman.blogspot.com/2008/10/sorting-generic-collections.html' title='Sorting Generic Collections'/><author><name>Mike Stedman</name><uri>http://www.blogger.com/profile/17164303750700071430</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></feed>
