<?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'><id>tag:blogger.com,1999:blog-12586772</id><updated>2010-03-14T12:38:50.427Z</updated><title type='text'>Architect or Cobbler?</title><subtitle type='html'>Good code starts with good design</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.jghd.co.uk/blogs/JamesWinters/atom.xml'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>45</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-12586772.post-2909228048345748964</id><published>2008-03-07T12:26:00.001Z</published><updated>2008-03-07T12:26:56.142Z</updated><title type='text'>Deleting objects</title><content type='html'>&lt;p&gt;Before I start to talk about the Clear method, a little correction to the code I published yesterday.&amp;#160; I am effectively obtaining and closing an ObjectContext with each DAO call.&amp;#160; This is extremely inefficient, and i probably want to change it in future so that the Context is opened once per thread, but I'm going to leave it as it is for now.&amp;#160; It does mean that I should Detach any entities from the ObjectContext before returning them, as an entity keeps a back pointer to it's ObjectContext, and it can't be attached to more than one at a time my DAO would start throwing exceptions the minute you started using it properly.&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;So why is deleting objects so difficult?&amp;#160;&amp;#160; Essentially it isn't if the object graph is attached and fully built, you issue a DeleteObject and the entity and the relationships are flagged as deleted, any related entities that have Cascade delete rules will also be flagged as deleted(and when you issue SaveChanges the rows will be removed from the underlying store).&amp;#160; But in our DAO the objects are being sent to is in a Detached state, which means you have to rebuild the object graph in order for the object to be deleted - If you don't you'll end up with either orphaned records in the database, or you'll throw Constraint exceptions.&lt;/p&gt;  &lt;p&gt;There are many approaches to building the Object Graph back up, for instance DannySimmons has a &lt;a href="http://blogs.msdn.com/dsimmons/archive/2007/12/08/computing-an-original-value-graph.aspx"&gt;blog&lt;/a&gt; posting about this.&amp;#160;&amp;#160; Unfortunately, while Danny's method is cool it doesn't work in a disconnected scenario very well (try to reason why.&amp;#160; Here's a big hint, will the ObjectSateManager contain values for detached objects?), or for my scenario, which is to work with any entity (I do have a generic DAO after all).&amp;#160; &lt;/p&gt;  &lt;p&gt;So I know to get hold of the relationship information for any entity, and while I'm sure there may be easier ways i just grabbed the attribute values from the EdmRelationshipAttribute which is added by the EDM generator.&amp;#160; This lists all the relationships across all Entity Containers and all Entity Sets, so i need to know which Entity container and Set I'm working with, so I've modified the constructor to pass these in.&lt;/p&gt;  &lt;p&gt;Once I have the attribute names it's a fairly straightforward matter to test if the entity I'm passing in is involved in the relationship.&amp;#160; I was even toying with writing a Linq query, then decided against it ;-)&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;p&gt;RelationshipManager rm = relations.RelationshipManager;   &lt;br /&gt;foreach (EdmRelationshipAttribute attr in attributes) 
&lt;br /&gt;{ 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // The relationship may not exist for this entity 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // as it may be for another entity set 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; try 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; rm.GetRelatedEnd(attr.RelationshipName, attr.Role2Name); 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; catch 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; // do nothing 
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;} 
&lt;br /&gt;re = rm.GetAllRelatedEnds();&lt;/p&gt;&lt;/pre&gt;

&lt;p&gt;Now all you have to do is load the related objects into the ObjectContext.&amp;#160; If you have these entities, you could simply attach them to the context, and then add them back in to the related end, in my case I went for the expensive option (but always guaranteed to work) of loading the object graph by issuing Load().&amp;#160; Now you can safely delete the object &lt;/p&gt;

&lt;pre&gt;foreach (IRelatedEnd related in re)  &lt;br /&gt;{  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; related.Load();
}&lt;/pre&gt;

&lt;p&gt;There is only one problem to solve now, how do I get every object in the EntitySet?&lt;/p&gt;

&lt;p&gt;I'll leave you with that little puzzle, but think Linq :-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-2909228048345748964?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/2909228048345748964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=2909228048345748964&amp;isPopup=true' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2909228048345748964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2909228048345748964'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2008/03/deleting-objects.html' title='Deleting objects'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-5475422427284724048</id><published>2008-03-05T23:13:00.001Z</published><updated>2008-03-05T23:13:08.960Z</updated><title type='text'>Generic DAO and the Entity Framework</title><content type='html'>&lt;p&gt;I've been a big Hibernate user over the years, and I've really got used to the ease of development and the way that Hibernate insulates me form the underlying database.&amp;#160; Over the years I've had a few occasions to port databases and the Data Access Object has always stood me in good stead, in particular the Generic DAO, which acts as the CRUD layer for all my queries.&amp;#160; Hibernate makes it incredibly easy to do, and the persistence ignorance and Session management mean I can really make the domain model completely unaware of the persistence scheme.&lt;/p&gt;  &lt;p&gt;So next week I'm talking about the Entity Framework and patterns at DevWeek, and as I use the DAO pattern so much I thought I'd implement it in the EF.&amp;#160; And after tearing my hair out for a few hours today, I can safely say that although there are some bits of the EF I really like, the context management and lack of persistence ignorance are real downers.&lt;/p&gt;  &lt;p&gt;Anyway here goes:&lt;/p&gt;  &lt;p&gt;I basically started off creating my usual CRUD interface, but there are a few wrinkles.&amp;#160; I really should have used IPOCO, and I probably will in the future, but for now I just made sure that all my generic types are constrained to be subtypes of EntityObject, giving an interface like:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;p&gt;public interface GenericDAO&amp;lt;TEntity&amp;gt; where TEntity : EntityObject 
  &lt;br /&gt;{&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TEntity Create(TEntity entity);&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TEntity Delete(TEntity entity);&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; TEntity Update(TEntity entity);&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; List&amp;lt;TEntity&amp;gt; FindAll();&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; void Clear(); 
&lt;br /&gt;}
&lt;/p&gt;&lt;/pre&gt;

&lt;p&gt;I'm a bit unhappy about exposing the EntityObject to the business layer, but I spent too many years with EJBs making Data Transfer Objects (DTOs) to even contemplate using them.&amp;#160; I started out using Microsoft's quaintly named IPOCOs.&amp;#160; But after I had to implement 3 interfaces and manually do all the change tracking, I nearly threw the laptop at the wall.&amp;#160; There are some efforts to make it a bit easier by using code generation and Postsharp and you can read Ruurd Boekes blog &lt;a href="http://www.sitechno.com/Blog/PostcompilingForEntityFrameworkPartIV.aspx"&gt;here&lt;/a&gt;.&amp;#160; But to be honest, you can't polish a ...&lt;/p&gt;

&lt;p&gt;The implementation of the CUD methods were fairly straightforward.&amp;#160; To illustrate I'll start by showing the constructor and the Create method.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;p&gt;public EFGenericDao(string containerName, string entitySet, string connectionString) &lt;br /&gt;{&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this._containerName = containerName;  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this._entitySet = entitySet;  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this._connectionString = connectionString;  &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; this._fullEntitySetName = containerName + &amp;quot;.&amp;quot; + entitySet;
} 

&lt;/p&gt;&lt;p&gt;public virtual TEntity Create(TEntity entity)
{&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;   using (ObjectContext ctx = new ObjectContext(_connectionString))&lt;br /&gt;&amp;#160;&amp;#160; {&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.AddObject(_fullEntitySetName, entity);&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.SaveChanges();&lt;br /&gt;&amp;#160;&amp;#160; } &lt;br /&gt;&amp;#160;&amp;#160; return entity;
}&lt;/p&gt;&lt;/pre&gt;

&lt;p&gt;As I'm going to use ObjectContext rather than the code generated context that the EDM designer gives me, you need to pass in the connection string, entity container name and the entity set that contains the entities you want to work with.&amp;#160; The Create is very straightforward, simply add the object to the context and then commit using SaveChanges.&lt;/p&gt;

&lt;p&gt;Delete and Update are a little more nasty, although you could avoid my nasty little refresh from the database if you set the EntityKey and called attach to add the object into the context.&amp;#160; I chose the easy way out, I simply load the object into the context from the database and then delete or update as appropriate.&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;p&gt;public TEntity Update(TEntity entity)  &lt;br /&gt;{
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; using (ObjectContext ctx = new ObjectContext(_connectionString))
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; object entityToUpdate = GetObjectByKey(entity.EntityKey);
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (entityToUpdate != null)
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ctx.ApplyPropertyChanges(_fullEntitySetName, entity);
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }
&lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; return entity;
&lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;
That's enough to whet the appetite. Tomorrow I'll look at how to do the Clear, because it's quite a tricky little bit of code, with reflection in a few places. (For a while I nearly just thought damn it, I'll write a stored proc, but I persevered)  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-5475422427284724048?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/5475422427284724048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=5475422427284724048&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5475422427284724048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5475422427284724048'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2008/03/generic-dao-and-entity-framework.html' title='Generic DAO and the Entity Framework'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-6347639775219689789</id><published>2008-03-05T19:43:00.003Z</published><updated>2008-03-05T19:49:33.601Z</updated><title type='text'>The end of an era</title><content type='html'>Or that's what it feels like. After 8 years I've decided it's time for me to move on, so I've left QA-IQ and branched out into the big bad world of freelancing. So my blog is moving as well, you'll now find it at &lt;a href="http://www.jghd.co.uk/blogs/JamesWinters"&gt;http://www.jghd.co.uk/blogs/JamesWinters&lt;/a&gt;.

For my loyal band of 2 readers, that means you'll have to update your bookmarks. It will also hopefully mean that I'll start blogging more (but previous evidence doesn't actively support me here)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-6347639775219689789?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/6347639775219689789/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=6347639775219689789&amp;isPopup=true' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/6347639775219689789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/6347639775219689789'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2008/03/end-of-era.html' title='The end of an era'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-8255509256967408225</id><published>2007-11-24T20:59:00.000Z</published><updated>2007-11-24T21:27:00.340Z</updated><title type='text'>Hubris ...</title><content type='html'>is a funny word, look it up &lt;a href="http://dictionary.reference.com/browse/hubris"&gt;here &lt;/a&gt;if you don't know it :-)

This afternoon's presentation on Facebook brought me to earth with a bang. My Internet connection crashed, then I attached to the wrong process , and finally I forgot how to code. The audience were kind, they clapped, but they should have booed.

And to top it all off, this is the presentation that got video'd.

Still, the slides are &lt;a href="http://www.wintersfamily.plus.com/files/Writing%20a%20Facebook%20App.ppt"&gt;here&lt;/a&gt;, and the source is &lt;a href="http://www.wintersfamily.plus.com/files/FaceBookCode.zip"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-8255509256967408225?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/8255509256967408225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=8255509256967408225&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/8255509256967408225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/8255509256967408225'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2007/11/hubris.html' title='Hubris ...'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-2986116517257342080</id><published>2007-11-24T13:35:00.000Z</published><updated>2007-11-24T13:49:28.185Z</updated><title type='text'>DDD6 - One down, one to go</title><content type='html'>Well that's the first talk on the Entity Framework done.  Had a full room, people sitting on the floor, and overflowing into the halls, so that was good.  The demos all worked, so that was even better.  And the practice at last week's user group was extremely useful, because I didn't even overrun.

The slides are &lt;a href="http://www.wintersfamily.plus.com/files/EntityFramework.ppt"&gt;here&lt;/a&gt;, and the source code with appropriate comments is &lt;a href="http://www.wintersfamily.plus.com/files/EFCode.zip"&gt;here&lt;/a&gt;.

If you have any questions, just ask them in the comments section.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-2986116517257342080?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/2986116517257342080/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=2986116517257342080&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2986116517257342080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2986116517257342080'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2007/11/ddd6-one-down-one-to-go.html' title='DDD6 - One down, one to go'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-7187346494513781914</id><published>2007-11-11T19:47:00.000Z</published><updated>2007-11-11T19:59:48.439Z</updated><title type='text'>Contrary to popular belief ...</title><content type='html'>I'm still here, and most of the time I'm even managing to architect, and not cobble.

It's been an exciting time recently, learning and applying new technologies (primarily .Net 3.5, but also the new Service Component Architecture and Service Data Objects stuff from the Java community) and creating new architecture courses for one of my major clients.

On Tuesday I'm doing a talk on the Entity Framework for the .Net Developer Network user group in Bristol.  More details &lt;a href="http://www.dotnetdevnet.com/"&gt;here&lt;/a&gt;, but Guy Smith-Ferrier will also be talking about Astoria.  So if you fancy an evening on data access technologies, then get yourself down.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-7187346494513781914?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/7187346494513781914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=7187346494513781914&amp;isPopup=true' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/7187346494513781914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/7187346494513781914'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2007/11/contrary-to-popular-belief.html' title='Contrary to popular belief ...'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-653268482144687497</id><published>2007-01-04T07:58:00.001Z</published><updated>2007-01-04T07:58:59.500Z</updated><title type='text'>DataContracts and VB - A warning</title><content type='html'>&lt;p&gt;We always write our .Net courses as dual language courses, which is kind of hard for me, because I'm not the world's best VB programmer.&amp;nbsp; So I always do all the exercises as C#, and then convert them to VB at some point.&amp;nbsp; Yesterday i wasted a whole day because of the way WCF generates proxies for DataContracts.&amp;nbsp; Let me explain :-)&lt;/p&gt; &lt;p&gt;Just like web services, you can specify namespaces on your code which will be reflected in the WSDL, there is one important differecne however, there are 3 types of contract on which you can specify namespaces:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;The Service Contract &lt;/li&gt; &lt;li&gt;The Message Contract&lt;/li&gt; &lt;li&gt;The Data Contract&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;If you leave the namespaces off then the service contract and the message contract get allocated the standard tempuri.org namespace we all know and love.&amp;nbsp; If you don't specify the data contract namespace then the framework allocates the namespace http://schemas.datacontract.org/2004/07&amp;nbsp;&amp;nbsp;+ the CLR type.&lt;/p&gt; &lt;p&gt;This is where it starts to go pear shaped, it works fine for C#, but in VB all namespaces belong to the rootnamespace, so instead of your types being serialized accross the wire with a namespace of something like http://schemas.datacontract.org/2004/07/LotteryService/&lt;/p&gt; &lt;p&gt;&amp;nbsp;they instead are transported accross the wire as &lt;/p&gt; &lt;p&gt;http://schemas.datacontract.org/2004/07/ConsoleApplication2.LotteryService&lt;/p&gt; &lt;p&gt;whereupon they are not deserialized correctly at the other end, and you therefore appear to always get null values sent over the wire.&lt;/p&gt; &lt;p&gt;This is infuriating to say the least, and there doesn't appear to be a great deal you can do to fix it.&amp;nbsp; Svcutil has a namespace switch which appears to be there to address the issue, so you can map a namespace to a CLR namespace, but it doesn't appear to do very much other than rename the generated proxy namespace.&amp;nbsp; What it should actually be doing is annotating the DataContractAttribute on the proxy type with the correct namespace, which is what I have to do to fix the problem.&lt;/p&gt; &lt;p&gt;So basically I dive into the&amp;nbsp;the proxy and change all of my DataContracts from&amp;nbsp;&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &amp;lt;System.CodeDom.Compiler.GeneratedCodeAttribute( _&lt;br&gt;       &lt;span class="str"&gt;"System.Runtime.Serialization"&lt;/span&gt;, &lt;span class="str"&gt;"3.0.0.0"&lt;/span&gt;),  _
     System.Runtime.Serialization.DataContractAttribute()&amp;gt;  _
    Partial &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; Entry
        &lt;span class="kwrd"&gt;Inherits&lt;/span&gt; &lt;span class="kwrd"&gt;Object&lt;/span&gt;
        &lt;span class="kwrd"&gt;Implements&lt;/span&gt; System.Runtime.Serialization.IExtensibleDataObject
&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &amp;lt;System.CodeDom.Compiler.GeneratedCodeAttribute( _&lt;br&gt;        &lt;span class="str"&gt;"System.Runtime.Serialization"&lt;/span&gt;, &lt;span class="str"&gt;"3.0.0.0"&lt;/span&gt;), _
     System.Runtime.Serialization.DataContractAttribute( _&lt;br&gt;       &lt;span class="kwrd"&gt;Namespace&lt;/span&gt;:=&lt;span class="str"&gt;"http://schemas.datacontract.org/2004/07/LotteryService"&lt;/span&gt;)&amp;gt; _
    Partial &lt;span class="kwrd"&gt;Public&lt;/span&gt; &lt;span class="kwrd"&gt;Class&lt;/span&gt; Entry&lt;/pre&gt;
&lt;p&gt;The only problem with that approach is that I lose the annotation whenever the proxy is regenerated.&lt;/p&gt;
&lt;p&gt;Of course I could always use namespaces like I'm supposed to :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-653268482144687497?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/653268482144687497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=653268482144687497&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/653268482144687497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/653268482144687497'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2007/01/datacontracts-and-vb-warning.html' title='DataContracts and VB - A warning'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-7016895494808485029</id><published>2006-12-24T12:40:00.001Z</published><updated>2006-12-24T12:46:34.774Z</updated><title type='text'>Merry Christmas ...</title><content type='html'>&lt;p&gt;To all, and especially my 3 subscribers, whoever you are.&amp;nbsp; And I thought I'd be reaching out to thousands when I started this blog.&amp;nbsp; I hope Santa brings you everything you're after, and I hope he brings me a Wii :-)&lt;/p&gt; &lt;p&gt;Although if previous form is anything to go by, it will be a comedy tie, some socks and a book that I bought at the airport 3 weeks ago anyway ;-)&lt;/p&gt; &lt;p&gt;So have fun, and to all the geeks out there, put the laptops (or desktops, PDAs or whatever else you use to keep connected) away until after Christmas, which is what I intend to do right now.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-7016895494808485029?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/7016895494808485029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=7016895494808485029&amp;isPopup=true' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/7016895494808485029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/7016895494808485029'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/12/merry-christmas.html' title='Merry Christmas ...'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-5182211338875727968</id><published>2006-12-23T18:14:00.001Z</published><updated>2006-12-23T18:15:29.428Z</updated><title type='text'>How to use BackgroundWorker properly ;-)</title><content type='html'>&lt;p&gt;Well, I've been looking at the problem a little more carefully, and it is definitely a race condition, however you can avoid it quite simply.&amp;nbsp; First a bit of code that demonstrates the problem more fully.&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; button1_Click(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)
        {
            backgroundWorker1 = &lt;span class="kwrd"&gt;new&lt;/span&gt; BackgroundWorker();
            backgroundWorker1.WorkerReportsProgress = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            backgroundWorker1.DoWork += DoWork;
            backgroundWorker1.ProgressChanged += ProgressChanged;
            backgroundWorker1.RunWorkerAsync();
        }
&lt;/pre&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DoWork(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, DoWorkEventArgs e)
        {
            &lt;span class="rem"&gt;// You need to call this in an invoke as you &lt;/span&gt;
            &lt;span class="rem"&gt;// are writing back to the UI thread&lt;/span&gt;
            BeginInvoke(&lt;span class="kwrd"&gt;new&lt;/span&gt; MethodInvoker(WriteHelloToTextBox));
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteHelloToTextBox()
        {
            textBox1.Text = &lt;span class="str"&gt;"Hello"&lt;/span&gt;;
            Thread.Sleep(100);
            backgroundWorker1.ReportProgress(100);
            
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ProgressChanged(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;The problem stems from the fact that DoWork is run in a separate thread, so if you have to write to the GUI then you have to marshal it via Invoke.&amp;nbsp; So naturally in my eagerness to improve performance I use BeginInvoke, which simply spawns a thread and then continues.&amp;nbsp; The spawned thread then sleeps for a bit (just to make the race condition more apparent - even without the sleep this code will occasionally fail) writes to a textbox and then reports progress.&amp;nbsp; By the time the ReportProgress call is marshaled to the right thread, the thread has completed as DoWork will have finished.&amp;nbsp; The solution is simple, never use BeginInvoke (or indeed spawning a new thread by any other means) from the DoWork handler, so to fix the code above, just change BeginInvoke to Invoke - it works every time now, and is certainly better than my cludgy sleep I was using earlier&amp;nbsp; :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-5182211338875727968?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/5182211338875727968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=5182211338875727968&amp;isPopup=true' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5182211338875727968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5182211338875727968'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/12/how-to-use-backgroundworker-properly.html' title='How to use BackgroundWorker properly ;-)'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-5968886392479687318</id><published>2006-12-23T16:29:00.001Z</published><updated>2006-12-23T16:29:57.203Z</updated><title type='text'>BackgroundWorker race condition bug?</title><content type='html'>&lt;p&gt;As I said the other day, I'm writing a new course (actually updating an existing one), and I've been writing practicals for the delegates.&amp;nbsp; As part of this I wrote an exercise that used BackgroundWorker to spawn a thread that searches for files on the file system.&amp;nbsp; Occasionally the program would fail with a System.InvalidOperationException with the message "This operation has already had OperationCompleted called on it and further calls are illegal."&amp;nbsp; I realised straight away that my call to ReportProgress was causing the ProgressChanged event to be raised after the BackgroundWorker had raised the RunWorkerCompleted event.&amp;nbsp; I suspected my code and banged around for ages trying to find the problem, but it actually appears to be a bug in the implementation.&amp;nbsp; If you raise a ReportProgress at roughly the same time the thread completes, you have a race, and one that the RunWorkerCompleted will nearly always win, as it doesn't have to issue a BeginInvoke.&amp;nbsp; In my case I was reporting progress every 23 files (don't ask it seemed a good number), and in cases where the search returns multiples of 23, then the RunWorkerCompleted would be raised at the same time as the ReportProgress and I'd get a race condition.&lt;/p&gt; &lt;p&gt;For now I've added a sleep at the end of my DoWork event handler to prevent it from finishing before my last ReportProgress has been actioned.&amp;nbsp; Does anyone have any better ideas?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-5968886392479687318?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/5968886392479687318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=5968886392479687318&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5968886392479687318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5968886392479687318'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/12/backgroundworker-race-condition-bug.html' title='BackgroundWorker race condition bug?'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-1370402678730890137</id><published>2006-12-20T12:37:00.001Z</published><updated>2006-12-20T12:37:34.820Z</updated><title type='text'>Coming up for air</title><content type='html'>&lt;p&gt;December is always the busiest month for those in the training community, and this month hasn't been any different.&amp;nbsp; I've just come off teaching a graduate program, and as always it was great to be challenged by so many bright, new and &amp;nbsp;confident people.&amp;nbsp; Of course it's meant I've had to go back to basics for a month or so, so I haven't been concentrating on my development during this time.&lt;/p&gt; &lt;p&gt;All that changes now, I'm writing new exercises and material for our .Net 3 curriculum, so I'll be sitting down over the next few weeks with Reflector and some coffee trying to really get to grips with WCF, WPF and WF.&amp;nbsp; So I'll probably be blogging about interesting little nuggets as I find them.&lt;/p&gt; &lt;p&gt;And of course always bear in mind I get it wrong as often as I get it right.&amp;nbsp; As Rob pointed out in a comment below, WPF windows should only have one Menu attached and then you should use child MenuItem structures to arrange the Menus.&amp;nbsp; I've fixed my copy of Scribble and you can download it &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/Samples/WPFScribble1.zip" target="_blank"&gt;here&lt;/a&gt;&lt;/p&gt; &lt;p&gt;OK, I'm off to play with SafeHandles now.&amp;nbsp; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-1370402678730890137?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/1370402678730890137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=1370402678730890137&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1370402678730890137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1370402678730890137'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/12/coming-up-for-air.html' title='Coming up for air'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-3608644534812934696</id><published>2006-11-26T13:23:00.001Z</published><updated>2006-11-26T13:23:06.765Z</updated><title type='text'>Scribble is Done</title><content type='html'>&lt;p&gt;Or as done as it's going to get.&amp;nbsp; Adding the file functionality was one of the easiest bits to do as the StrokeCollection has a Save method which will serialize the Strokes to&amp;nbsp;the ISF (Ink Serialized Format) format.&amp;nbsp; To recreate the StrokeCollection you simply use a constructor that takes a Stream.&amp;nbsp; I made a binary file that also included how many Scribble Canvases are open and saved to that.&lt;/p&gt; &lt;p&gt;So now that I'm done, how do I feel about WPF?&lt;/p&gt; &lt;p&gt;There are some pretty cool new features, and binding is excellent, but there are some glaring problems that really need to be fixed.&lt;/p&gt; &lt;p&gt;Lack of support for basic dialogs is not great, although you can use Window Forms dialogs there are some issues with interop, particularly when graphics are involved as there is vector/raster conversion needed.&lt;/p&gt; &lt;p&gt;VS2005 needs better design time support - I suppose this will come pretty quickly as Cider gets improved, and there's always Expression if you really want better design tools.&amp;nbsp; Or wait for VS Orcas :-)&lt;/p&gt; &lt;p&gt;The IntelliSense is patchy at best, every time you import a custom class the IntelliSense stops working (which isn't surprising as the schema is then broken).&amp;nbsp; Speaking to Adam at TechEd he was mentioning that there's a new metalanguage being created behind the scenes which means that IntelliSense won't have to use the schemas to generate context sensitive help.&amp;nbsp; I can't wait.&lt;/p&gt; &lt;p&gt;As usual you can download the code &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/Samples/WPFScribble.zip"&gt;here&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;For the next couple of weeks I'm going to busy with a graduate training program - so it may well be a bit quiet on here.&amp;nbsp; After that I'm into a round of new course development, so I'll be blogging about cool new stuff (or even old stuff) that interests me then.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-3608644534812934696?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/3608644534812934696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=3608644534812934696&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/3608644534812934696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/3608644534812934696'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/scribble-is-done.html' title='Scribble is Done'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-493528674376894665</id><published>2006-11-25T16:23:00.001Z</published><updated>2006-11-25T16:23:48.452Z</updated><title type='text'>Printing</title><content type='html'>&lt;p&gt;I decided to bite the bullet and just use the PrintPreviewDialog - so my app now has printing support.&amp;nbsp; You may recall from earlier that I used a Command attribute for the Print menus rather than a Click attribute.&amp;nbsp; There are several benefits to using the Command attribute:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;In many of the WPF controls these commands are already coded fro you so you don't have to code it.&lt;/li&gt; &lt;li&gt;There is a standard mechanism for seeing if the command can be executed so the menu is automatically enabled.&lt;/li&gt; &lt;li&gt;The menus will automatically get Keyboard shortcuts added.&lt;/li&gt; &lt;li&gt;You can override the standard behaviour in a CommandBindings section&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;So as the Print and PrintPreview don't seem to be wired up, I need to wire&amp;nbsp;up the commands using CommandBindings like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.CommandBindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CommandBinding&lt;/span&gt; &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;="Print"&lt;/span&gt; &lt;span class="attr"&gt;Executed&lt;/span&gt;&lt;span class="kwrd"&gt;="OnPrint"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;CanExecute&lt;/span&gt;&lt;span class="kwrd"&gt;="CanPrint"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CommandBinding&lt;/span&gt; &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;="PrintPreview"&lt;/span&gt; &lt;span class="attr"&gt;Executed&lt;/span&gt;&lt;span class="kwrd"&gt;="OnPrintPreview"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;CanExecute&lt;/span&gt;&lt;span class="kwrd"&gt;="CanPrint"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.CommandBindings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now I need to provide the Code for the CanPrint method, this method is a simple switch that indicates whether or not the menu can be enabled.&amp;nbsp; In my case, I've decided that if there are no active Scribble windows then you won't be able to print, and the code is self explanatory.&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; CanPrint(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, CanExecuteRoutedEventArgs  args)
        {
            args.CanExecute =  (ActiveCanvas != &lt;span class="kwrd"&gt;null&lt;/span&gt;);
        }&lt;/pre&gt;
&lt;p&gt;The Print functionality involves creating a PrintDialog, and allowing this to manage the printing, while the PrintPreview is a bit trickier.&amp;nbsp; I need to use a RenderTargetBitmap and a BmpBitmapEncoder to convert the Vector information into a raster bitmap that can be used in the Print Page handler for the PrintPreviewDialog.&amp;nbsp; There is one obvious disadvantage to this approach - the print quality will be lower going through the PrintPreview dialog compared to just printing directly.&amp;nbsp; The printing itself is just a matter of getting the Strokes collection from the active InkCanvas, and then invoking the Draw method for each Stroke in that collection.&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPrint(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs args)
        {
            PrintDialog pd = &lt;span class="kwrd"&gt;new&lt;/span&gt; PrintDialog();
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (pd.ShowDialog().GetValueOrDefault())
            {
                DrawingVisual dv = RenderSinglePage();
                pd.PrintVisual(dv, &lt;span class="str"&gt;"Scribble Canvas Print Job"&lt;/span&gt;);

            }
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; DrawingVisual RenderSinglePage()
        {
            DrawingVisual dv = &lt;span class="kwrd"&gt;new&lt;/span&gt; DrawingVisual();
            DrawingContext dc = dv.RenderOpen();
            ScribbleCanvas sc = ActiveCanvas;
            StrokeCollection strokes = sc.Strokes;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Stroke stroke &lt;span class="kwrd"&gt;in&lt;/span&gt; strokes)
            {
                stroke.Draw(dc);
            }
            dc.Close();
            &lt;span class="kwrd"&gt;return&lt;/span&gt; dv;
        }

        &lt;span class="kwrd"&gt;void&lt;/span&gt; OnPrintPreview(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs args)
        {
            PrintDocument pd = &lt;span class="kwrd"&gt;new&lt;/span&gt; PrintDocument();
            pd.PrintPage += &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Drawing.Printing.PrintPageEventHandler(&lt;br&gt;                                  &lt;span class="kwrd"&gt;this&lt;/span&gt;.ScribblePrintPage);
            System.Windows.Forms.PrintPreviewDialog prevDlg = &lt;br&gt;                        &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Windows.Forms.PrintPreviewDialog();
            prevDlg.Document = pd;
            prevDlg.ShowDialog();

        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ScribblePrintPage(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, PrintPageEventArgs ev)
        {
            
            ScribbleCanvas sc = ActiveCanvas;
            RenderTargetBitmap rtb = &lt;span class="kwrd"&gt;new&lt;/span&gt; RenderTargetBitmap((&lt;span class="kwrd"&gt;int&lt;/span&gt;)sc.ActualWidth,&lt;br&gt;                                                            (&lt;span class="kwrd"&gt;int&lt;/span&gt;)sc.ActualHeight,&lt;br&gt;                                                             96d, 96d,&lt;br&gt;                                                            PixelFormats.Default);
            rtb.Render(sc);
            MemoryStream ms = &lt;span class="kwrd"&gt;new&lt;/span&gt; MemoryStream();
            BmpBitmapEncoder encoder = &lt;span class="kwrd"&gt;new&lt;/span&gt; BmpBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));
            encoder.Save(ms);
            ev.Graphics.DrawImage(&lt;span class="kwrd"&gt;new&lt;/span&gt; System.Drawing.Bitmap(ms),&lt;br&gt;                                  0f,0f,&lt;br&gt;                                  (&lt;span class="kwrd"&gt;float&lt;/span&gt;)sc.ActualWidth,(&lt;span class="kwrd"&gt;float&lt;/span&gt;)sc.ActualHeight);
            ms.Close();
            ev.HasMorePages = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
        }
&lt;/pre&gt;
&lt;p&gt;As usual you can download the source code &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/Samples/WPFScribblePart4.zip"&gt;here&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-493528674376894665?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/493528674376894665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=493528674376894665&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/493528674376894665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/493528674376894665'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/printing.html' title='Printing'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-3568269129679489874</id><published>2006-11-23T00:23:00.001Z</published><updated>2006-11-23T00:26:53.905Z</updated><title type='text'>A little printing difficulty</title><content type='html'>&lt;p&gt;I was going to add the Print functionality to my Scribble app next, and the printing side was a piece of old rope - the printing support is excellent.  Then I came to do the PrintPreview, and after 2 days I'm still a little stumped - although I have a working solution it feels Kludgy.  There are 2 options that I can see (and which I have tested), both of them a little dodgy.  The first is to take my InkCanvas and create an XPSDocument, and then encapsulate a DocumentViewer within a Dialog page, as DocumentViewers are WSYISWYG.  The second is to use Windows Forms Interop, use the existing WinForms PrintPreviewDialog and use the RenderTargetbitmap class to turn the Vector graphic DrawingVisual into a raster Bitmap, which I can display in the WinForms dialog.&lt;/p&gt;&lt;p&gt;I almost can't believe this oversight, particularly as Microsoft have added PrintPreview as one of the standard ApplicationCommands and made it available via a property.&lt;/p&gt;&lt;p&gt;So I'm probably going to skip printing for a few days and concentrate on the File save/Open dialog.  &lt;/p&gt;&lt;p&gt;If anyone can show me how to do a PrintPreview dialog in the meantime, then that would be cool&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-3568269129679489874?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/3568269129679489874/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=3568269129679489874&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/3568269129679489874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/3568269129679489874'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/little-printing-difficulty.html' title='A little printing difficulty'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-271214586145035393</id><published>2006-11-19T18:00:00.001Z</published><updated>2006-11-19T18:00:09.750Z</updated><title type='text'>Style</title><content type='html'>&lt;p&gt;I've already blogged about style earlier in my blog, but styles are absolutely essential to the success of any Xaml app, particularly when you have many controls that share behaviour.&amp;nbsp; In the PenWidthDialog we've got two text boxes that we want to style the same.&amp;nbsp; I'd like their background to turn red, and a tooltip to appear with the error message returned from the ValidatorRule.&amp;nbsp; To do this you need to add a Resources section to the Xaml, give your style a key. like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt; &lt;span class="attr"&gt;x:Key&lt;/span&gt;&lt;span class="kwrd"&gt;="MyTextBoxStyle"&lt;/span&gt; &lt;span class="attr"&gt;TargetType&lt;/span&gt;&lt;span class="kwrd"&gt;="{x:Type TextBox}"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Validation.HasError"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="ToolTip"&lt;/span&gt;
            &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="{Binding RelativeSource={RelativeSource Self},
          Path=(Validation.Errors)[0].ErrorContent}"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Setter&lt;/span&gt; &lt;span class="attr"&gt;Property&lt;/span&gt;&lt;span class="kwrd"&gt;="Background"&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;="Red"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Trigger&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style.Triggers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Style&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Window.Resources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This probably needs a little bit of explaining.&amp;nbsp; The style has to know the types which it can be applied to , and the Triggers collection is a collection that contains Triggers.&amp;nbsp; Triggers are objects which are activated in response to either a property changing or an event being fired.&amp;nbsp; In our case the Trigger is fired when the property Validation.HasError changes to true.&amp;nbsp; At that time two properties of the TextBox are changed - the Tooltip property is set so that it displays the first error message in the Validation.Errors collection and the Background is set to red.&amp;nbsp; The RelativeSource property allows you to specify a source for the binding, instead of walking the control tree.&lt;/p&gt;
&lt;p&gt;Now all you have to do is apply these styles to your textbox, and when you get a validation error, then it will look something like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/Style_FD34/DialogWithError1.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="120" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/Style_FD34/DialogWithError.png" width="240" border="0"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;We're nearly done.&amp;nbsp; All we have to do is sort out the printing, and saving and restoring the state.&amp;nbsp; I'm sure I'll get a chance next week to finish this off.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-271214586145035393?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/271214586145035393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=271214586145035393&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/271214586145035393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/271214586145035393'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/style.html' title='Style'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-1734967885369957215</id><published>2006-11-18T15:43:00.001Z</published><updated>2006-11-18T15:43:28.781Z</updated><title type='text'>Adding some Dialogs to Scribble</title><content type='html'>&lt;p&gt;I'm going to add a dialog to the Scribble app so I can change the thicknesses of the pen lines.&amp;nbsp; The dialog will look like this&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/AddingsomeDialogstoScribble_DD27/ThicknessDialog1.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="120" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/AddingsomeDialogstoScribble_DD27/ThicknessDialog.png" width="240" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;To do this you need a Window to represent the GUI, so I created a new Xaml file PenWidthDialog.xaml, gave it a border, a 4X4 grid, two text boxes and two buttons.&amp;nbsp; The only work at this stage is to set the IsDefault and IsCancel properties on the appropriate buttons.&amp;nbsp; I've also set the TabIndex and IsTabStop properties as you need to be able to tab through a dialog properly.&lt;/p&gt;&lt;pre class="csharpcode"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Border&lt;/span&gt; &lt;span class="attr"&gt;BorderThickness&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="LightGray"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="20"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="100"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="80"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ColumnDefinition&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid.ColumnDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="30"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="30"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="30"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RowDefinition&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid.RowDefinitions&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Label&lt;/span&gt;  &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Thin Pen Width&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Label&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Thick Pen Width&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt; &lt;span class="kwrd"&gt;="0,2,0,6"&lt;/span&gt; 
               &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; 
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt; &lt;span class="kwrd"&gt;="0,2,0,6"&lt;/span&gt; 
               &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="3"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="25"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="70"&lt;/span&gt; &lt;br&gt;              &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="OKButton"&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="OnOkButtonClicked"&lt;/span&gt; &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;br&gt;              &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;IsDefault&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;OK&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="3"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="25"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="70"&lt;/span&gt; &lt;br&gt;              &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="CancelButton"&lt;/span&gt; &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="3"&lt;/span&gt; &lt;br&gt;              &lt;span class="attr"&gt;IsCancel&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Cancel&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Grid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Border&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Now I want to add the data bindings for the Pen Width, and immediately I realise I need a bit of refactoring, so I create a Pen class with 3 properties, ThinWidth, ThickWidth and InkColor.&amp;nbsp; In my ScribbleCanvas class I create a new Pen and attach it to the canvas, and remove the old int properties that described thick and thin pens.&lt;/p&gt;
&lt;p&gt;Now change Scribble.Xaml to add an event handler for the menu PenWidths, by adding a Click property.&amp;nbsp; The implementation of the event handler is a doddle, create a new PenWidth dialog object and show it using the ShowDialog method.&amp;nbsp; This returns a bool? , so it is important you handle the null value that is returned if the user closed the dialog with the X.&amp;nbsp; The simplest way to do this is to use the GetValueOrDefault method, which will convert a null to false.&amp;nbsp; If you clicked OK then simply call the ChangePenWidths() method to propagate the changes to all canvases.&amp;nbsp; Before you do this you have to set the static Pen property to the new Pen from the dialog.&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; OnChangePenWidths(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e){
            PenWidthDialog pwd = &lt;span class="kwrd"&gt;new&lt;/span&gt; PenWidthDialog();
            pwd.Owner = &lt;span class="kwrd"&gt;this&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (pwd.ShowDialog().GetValueOrDefault())
            {
                ScribbleCanvas.ChangePen();
                ChangePenWidths();
            }
        }&lt;/pre&gt;
&lt;p&gt;You can compile and run this, and though the dialog works, nothing will happen yet.&amp;nbsp; The reason is obvious, we haven't bound the text boxes to any data, so we'll fix that right now.&amp;nbsp; In WPF a control attempts to bind to a DataContext, and it will simply search up it's control tree till it finds a non-null DataContext and use this as the data source.&amp;nbsp; Then you use the Binding element to attach to this context. The binding has a Path property, which describes the property in the context that you wish to bind against. In our case this will be the ThinWidth and ThickWidth properties of the Pen object that belongs to the ScribbleCanvas.&amp;nbsp; To set up this data context I'm going to add an initialisation method that is invoked by adding the Loaded property to my Xaml, I'm also going to take the opportunity to add my WPFScribble namespace into the Xaml as I know&amp;nbsp;I&amp;nbsp;need it just now,&amp;nbsp;as in:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Window&lt;/span&gt; &lt;span class="attr"&gt;x:Class&lt;/span&gt;&lt;span class="kwrd"&gt;="WPFScribble.PenWidthDialog"&lt;/span&gt;
    &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;
    &lt;span class="attr"&gt;xmlns:x&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;
    &lt;span class="attr"&gt;xmlns:src&lt;/span&gt;&lt;span class="kwrd"&gt;="clr-namespace:WPFScribble"&lt;/span&gt; 
    &lt;span class="attr"&gt;Title&lt;/span&gt;&lt;span class="kwrd"&gt;="Pen Widths"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="150"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="300"&lt;/span&gt; &lt;span class="attr"&gt;ResizeMode&lt;/span&gt;&lt;span class="kwrd"&gt;="NoResize"&lt;/span&gt;
    &lt;span class="attr"&gt;Loaded&lt;/span&gt;&lt;span class="kwrd"&gt;="OnInit"&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;In the OnInit method I'm going to&amp;nbsp;load the DataContext with the Pen object that I want to bind to.&lt;/p&gt;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OnInit(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
        {
            &lt;span class="kwrd"&gt;this&lt;/span&gt;.DataContext = ScribbleCanvas.ScribblePen;
        }&lt;/pre&gt;
&lt;p&gt;Finally you add the binding that will bind the properties to the text boxes.&amp;nbsp; To do this you&amp;nbsp; need to add either a Binding element to the Text property or&amp;nbsp; attach a {Binding} statement directly to the text box.&amp;nbsp;&amp;nbsp; Both syntaxes are shown below.&lt;/p&gt;&lt;pre class="csharpcode"&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt; &lt;span class="kwrd"&gt;="0,2,0,6"&lt;/span&gt; 
               &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox.Text&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Binding&lt;/span&gt; &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;="ThinWidth"&lt;/span&gt; 
                   &lt;span class="attr"&gt;UpdateSourceTrigger&lt;/span&gt;&lt;span class="kwrd"&gt;="LostFocus"&lt;/span&gt; /&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TextBox.Text&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; 
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TextBox&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Column&lt;/span&gt; &lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="attr"&gt;Margin&lt;/span&gt; &lt;span class="kwrd"&gt;="0,2,0,6"&lt;/span&gt; 
               &lt;span class="attr"&gt;IsTabStop&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="attr"&gt;TabIndex&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;&lt;/span&gt;&lt;span class="html"&gt;&lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;="{Binding Path=ThickWidth}" /&lt;/span&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can run your application now, and changing Pen widths will work, well to a point.&amp;nbsp; Open up the dialog and make the thin width 3 and the thick width a.&amp;nbsp; Clearly this is a nonsensical value, but the GUI is quite happy to accept this.&amp;nbsp; Oops, we need to add validation.&amp;nbsp; WPF only comes with one validator the ExceptionValidationRule, which fires if an exception is thrown when updating the binding.&amp;nbsp; This isn't good enough for our needs, so we need to create our own validator.&amp;nbsp; To do this you subclass ValidationRule, provide any properties you need, such as a minimum and maximum value, and override the Validate method.&amp;nbsp; This returns a ValidationResult, as shown in the code below.&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PenWidthRule : ValidationRule
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _min;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _max;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; PenWidthRule()
        {
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Min
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _min; }
            set { _min = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Max
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _max; }
            set { _max = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; ValidationResult Validate(&lt;span class="kwrd"&gt;object&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;, CultureInfo cultureInfo)
        {
            &lt;span class="kwrd"&gt;int&lt;/span&gt; age = 0;

            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (((&lt;span class="kwrd"&gt;string&lt;/span&gt;)&lt;span class="kwrd"&gt;value&lt;/span&gt;).Length &amp;gt; 0)
                    age = Int32.Parse((String)&lt;span class="kwrd"&gt;value&lt;/span&gt;);
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ValidationResult(&lt;span class="kwrd"&gt;false&lt;/span&gt;, &lt;span class="str"&gt;"Illegal characters"&lt;/span&gt;);
            }

            &lt;span class="kwrd"&gt;if&lt;/span&gt; ((age &amp;lt; Min) || (age &amp;gt; Max))
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ValidationResult(&lt;span class="kwrd"&gt;false&lt;/span&gt;,
                  &lt;span class="str"&gt;"Please enter an age in the range: "&lt;/span&gt; + Min + &lt;span class="str"&gt;" - "&lt;/span&gt; + Max + &lt;span class="str"&gt;"."&lt;/span&gt;);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ValidationResult(&lt;span class="kwrd"&gt;true&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);
            }
        }
    }&lt;/pre&gt;
&lt;p&gt;You want the GUI to invoke the validation, so you need to add the validation rules to the Binding, as shown in the Xaml fragment below.&amp;nbsp; If the validation fails, then the WPF framework will surround the text box with a red surround.&amp;nbsp; &lt;/p&gt;&lt;pre class="csharpcode"&gt;         &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Binding&lt;/span&gt; &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;="ThinWidth"&lt;/span&gt; 
                   &lt;span class="attr"&gt;UpdateSourceTrigger&lt;/span&gt;&lt;span class="kwrd"&gt;="LostFocus"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Binding.ValidationRules&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;src:PenWidthRule&lt;/span&gt; &lt;span class="attr"&gt;Min&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="attr"&gt;Max&lt;/span&gt;&lt;span class="kwrd"&gt;="30"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Binding.ValidationRules&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Binding&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;   &lt;/pre&gt;
&lt;p&gt;You may want to have a custom validation message, to do this you need to change the style of the text box.&amp;nbsp; We'll leave this till tomorrow :-)&amp;nbsp; For now you can download the source for the project from &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/Samples/WPFScribblePart3.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-1734967885369957215?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/1734967885369957215/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=1734967885369957215&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1734967885369957215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1734967885369957215'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/adding-some-dialogs-to-scribble.html' title='Adding some Dialogs to Scribble'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-2280259940636885341</id><published>2006-11-16T21:05:00.001Z</published><updated>2006-11-16T21:05:43.406Z</updated><title type='text'>Thick Pens .. or is that thick coders</title><content type='html'>&lt;p&gt;This morning on the train,&amp;nbsp;I thought I'd add the Pen functionality to my application, and I immediately jumped in the deep end, but after a few minutes I started to get the feel that my code was getting distinctly whiffy.&amp;nbsp; I was adding all sorts of functionality to the Window that wasn't the window's responsibility, and I had to stop and refactor ... See this is a design blog after all :-)&lt;/p&gt; &lt;p&gt;I really needed to extract the Pen width and colour&amp;nbsp;setting into it's own class.&amp;nbsp; So I decided to create a UserControl.&amp;nbsp; To do this is fairly straightforward, simply create a Xaml file that is either a UserControl or has a root element that is the control you want to subclass.&amp;nbsp; In my case I want an InkCanvas object, so I'm going to create the following Xaml&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;InkCanvas&lt;/span&gt; &lt;span class="attr"&gt;x:Class&lt;/span&gt;&lt;span class="kwrd"&gt;="WPFScribble.ScribbleCanvas"&lt;/span&gt;
    &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;
    &lt;span class="attr"&gt;xmlns:x&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;InkCanvas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;This is pretty straightforward, it simply hooks up a code-behind file ScribbleCanvas, which must be a subclass of InkCanvas. It looks something like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; partial &lt;span class="kwrd"&gt;class&lt;/span&gt; ScribbleCanvas : InkCanvas
{&lt;br&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; ScribbleCanvas()
     {
         InitializeComponent();
     }&lt;br&gt;}&lt;/pre&gt;
&lt;p&gt;The last thing to do is to change the Scribble.xaml to include our user control.&amp;nbsp; Since this is an XML file you have to use namespaces to define ownership, so you begin by defining a new namespace, in my case I decided to call it scribble, as follows&lt;/p&gt;&lt;pre class="csharpcode"&gt;    xmlns:scribble="clr-namespace:WPFScribble"
&lt;/pre&gt;
&lt;p&gt;Now you can replace references to the InkCanvas with references to your UserControl ScribbleCanvas like this&lt;/p&gt;&lt;pre class="csharpcode"&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TabItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Window1"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;scribble:ScribbleCanvas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;scribble:ScribbleCanvas.DefaultDrawingAttributes&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DrawingAttributes&lt;/span&gt;  
                  &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; 
                  &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;scribble:ScribbleCanvas.DefaultDrawingAttributes&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;scribble:ScribbleCanvas&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TabItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;  &lt;/pre&gt;
&lt;p&gt;And if you run it there should be no difference in functionality.&amp;nbsp; Of course if I was doing the refactoring properly, there would be some tests to ensure the behaviour is identical, but I never claimed to be perfect.&lt;/p&gt;
&lt;p&gt;So, a short little posting tonight, but I'm cream crackered.&amp;nbsp; Tomorrow I'll add the menus to do the pen width and colour settings.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-2280259940636885341?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/2280259940636885341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=2280259940636885341&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2280259940636885341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/2280259940636885341'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/thick-pens-or-is-that-thick-coders.html' title='Thick Pens .. or is that thick coders'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-62366597863635666</id><published>2006-11-15T18:47:00.001Z</published><updated>2006-11-15T19:14:13.273Z</updated><title type='text'>MDI - or not</title><content type='html'>&lt;p&gt;Today I thought I'd do the windows, and then I found out that WPF doesn't support MDI (actually I knew it didn't, I was hoping that somehow MDI had sneaked into RTM).  I could of course just use Windows Forms Integration and simply drag a Windows Forms Window in and use that through Forms interop, but I really wanted a XAML only solution.  The alternative is to create your own window manager and to do it that way, but that's just way too much work :-)&lt;/p&gt;&lt;p&gt;So I've decided to use the TabControl, after all it's topical seeing as IE7 is out with it's own tabs, so that's what we're going to do in this session - hook up a TabControl to the form and then make it respond to the Window Open and Window Close menu commands.&lt;/p&gt;&lt;p&gt;Firstly I've had to modify the menu, as Window tile and cascade make no sense with a tab option.  So I've altered the XAML so that my Window menu is now:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Window"&lt;/span&gt;  &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="New Window"&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="NewTab"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt; &lt;span class="kwrd"&gt;="Close Window"&lt;/span&gt; &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="CloseTab"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;    
     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;Notice I've hooked the click events to the methods NewTab and CloseTab, we won't implement them yet, as I need to add the TabControl to my XAML at this point.  I'm going to add it to the MainWindow DockPanel that was created earlier, and it looks something like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="DockPanel_MainDisplay"&lt;/span&gt;
            &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="DarkGray"&lt;/span&gt;
            &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TabControl&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="MainWindow_TabPanel"&lt;/span&gt; &lt;span class="attr"&gt;TabStripPlacement&lt;/span&gt;&lt;span class="kwrd"&gt;="Top"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TabItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Window1"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TabItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; 
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TabControl&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;A TabControl is simply a collection of TabItems. Each TabItem has a header which is it's title, and some visual content - for now we'll simply leave the visual content out.&lt;/p&gt;&lt;p&gt;If you build and run the application, then you'll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/MDIornot_10817/TabbedApp2.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="287" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/MDIornot_10817/TabbedApp_thumb.png" width="287" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Now, to hook the events up, you need to implement the NewTab and CloseTab methods in the code behind file Scribble.xaml.cs.  The logic is fairly straightforward, I create a new TabItem and then I add it to the TabControl's Items collection.  The TabControl is visible to me because I gave it a Name attribute in the XAML.  I then grab the focus, and that's it.  &lt;/p&gt;&lt;p&gt;If you do significant actions with a RoutedEvent such as changing the layout or drawing to screen, you should indicate this by setting the Handled attribute to true.  This prevents any other handler between you and the root node from dealing with the event. &lt;/p&gt;&lt;p&gt;The CloseTab functionality is equally straightforward, simply remove the selected TabItem from the Items collection (I've also made some logic to rename the tabs, it's probably not necessary, I just wanted to see if it worked)&lt;/p&gt;&lt;pre class="csharpcode"&gt;     &lt;span class="kwrd"&gt;void&lt;/span&gt; NewTab(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
     {
            WindowCount++;
            TabItem item = &lt;span class="kwrd"&gt;new&lt;/span&gt; TabItem();
            item.Header=&lt;span class="str"&gt;"Window"&lt;/span&gt;+WindowCount.ToString();
            MainWindow_TabPanel.Items.Add(item);
            item.Focus();
            e.Handled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
     }


     &lt;span class="kwrd"&gt;void&lt;/span&gt; CloseTab(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
     {
            MainWindow_TabPanel.Items.Remove(MainWindow_TabPanel.SelectedItem);
            WindowCount--;
            &lt;span class="rem"&gt;// because of my simple naming scheme I need to rename the tabs&lt;/span&gt;
            RenameTabs();
            e.Handled = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
      }&lt;/pre&gt;&lt;p&gt;You can build and run , and you can now add and remove tabs to the application.  Of course you could (if you weren't as lazy as me) add a context sensitive menu to each tab to add and close tabs.&lt;/p&gt;&lt;p&gt;So far this isn't very exciting, I still can't scribble on the application, but before I went messing around creating mouse handlers, I noticed there was this Canvas class called the InkCanvas, so I wondered what functionality it offered.  &lt;/p&gt;&lt;p&gt;So I simply added it to the XAML hierarchy, and bingo I got full Scribble functionality.  I was that excited I could have kissed someone from the WPF team (except Rob, I've met him and the moustache would tickle).  To add the functionality involved 2 changes, one to the XAML and one to the code as outlined below:&lt;/p&gt;&lt;pre class="csharpcode"&gt; &amp;lt;TabControl Name=&lt;span class="str"&gt;"MainWindow_TabPanel"&lt;/span&gt; TabStripPlacement=&lt;span class="str"&gt;"Top"&lt;/span&gt;&amp;gt;
       &amp;lt;TabItem Header=&lt;span class="str"&gt;"Window1"&lt;/span&gt;&amp;gt;
          &amp;lt;InkCanvas /&amp;gt;
       &amp;lt;/TabItem&amp;gt; 
  &amp;lt;/TabControl&amp;gt;&lt;/pre&gt;&lt;pre class="csharpcode"&gt;...item.Content = &lt;span class="kwrd"&gt;new&lt;/span&gt; InkCanvas();&lt;/pre&gt;
&lt;p&gt;My GUI is very nearly complete, I need functionality for Pen Thicknesses, and I may even add Pen Colour as well, just to really push the boat out, but that will have to wait till tomorrow, for now here's my Scribble app doing its stuff. &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/MDIornot_10817/CoolScribble2.png" atomicselection="true"&gt;&lt;img style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height="265" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/MDIornot_10817/CoolScribble_thumb.png" width="329" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;You can download my VS2005 project &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/Samples/WPFScribblePart2.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-62366597863635666?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/62366597863635666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=62366597863635666&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/62366597863635666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/62366597863635666'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/mdi-or-not.html' title='MDI - or not'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-5667583565507477390</id><published>2006-11-14T17:01:00.001Z</published><updated>2006-11-14T19:42:42.018Z</updated><title type='text'>Still broken</title><content type='html'>&lt;p&gt;I thought I'd found the problem, but not yet :-)&lt;/p&gt;&lt;p&gt;Update - I appear to have it fixed now, fingers crossed, my archive settings disappeared when moving from the original to the beta.  A quick delete of all the archive files, reset of the settings and its back to normal.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-5667583565507477390?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/5667583565507477390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=5667583565507477390&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5667583565507477390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5667583565507477390'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/still-broken.html' title='Still broken'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-8826877700372748992</id><published>2006-11-14T16:39:00.000Z</published><updated>2006-11-14T16:41:38.269Z</updated><title type='text'>Beta Blogger Broken?</title><content type='html'>That'll teach me to move to a beta product.   My archives are temporarily stuffed, and the Publish feature is completely off the wall.  Since I've made a template change I get extremely erratic publishing, and most of the time a rather cryptic error message: org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.

Any ideas?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-8826877700372748992?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/8826877700372748992/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=8826877700372748992&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/8826877700372748992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/8826877700372748992'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/beta-blogger-broken.html' title='Beta Blogger Broken?'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-1509132796617652384</id><published>2006-11-14T16:18:00.001Z</published><updated>2006-11-14T18:27:28.484Z</updated><title type='text'>WPF Scribble - Part 1 The GUI</title><content type='html'>&lt;p&gt;Someone asked me why there wasn't a Scribble sample app for WPF.&amp;nbsp; Maybe there is, but I thought it would be a great opportunity for me to play more with the technology, so if time allows (and time is in very short supply at this time of year) I'm going to build a Scribble app over a few days.&amp;nbsp; I'll make the code available as I go through the exercise.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;The first step is to make sure you can write WPF apps.&amp;nbsp; If you have Vista and VS2005 then you're laughing.&amp;nbsp; If you don't you need to head off to MS, download the .Net framework 3.0, the Windows SDK and the VS 2005 extensions for WPF and WCF.&amp;nbsp; Don't worry it's only a few hundred Megs, should only take a few minutes on that super connection of yours.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Now to create a WPF application is fairly straightforward &amp;gt; Simply create a new project based on the Windows Application (WPF) template that the extensions have added for you.&amp;nbsp; &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/WPFScribblePart1TheGUI_CC3C/NewProject10.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="312" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/WPFScribblePart1TheGUI_CC3C/NewProject_thumb8.png" width="432" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;This will create two XAML files , App.xaml and Window1.xaml along with their code behind files.&amp;nbsp; At this point I usually either delete Window1.xaml or rename it.&amp;nbsp;&amp;nbsp; Rename Window1.xaml to Scribble.xaml and then open App.xaml.&amp;nbsp; You will notice it is simply a holder for resources, but for now all you have to do is change the StartupUri attribute to be Scribble.xaml.&lt;/p&gt; &lt;p&gt;For the rest of this session you'll be working in either Scribble.xaml or the code behind file Scribble.xaml.cs, and all we're going to do in this session is create the basic GUI. For those of you have never seen the Scribble application, it's a simple MDI (multiple Document Interface) app where you can scribble stuff and save and retrieve it.&amp;nbsp; It looks a bit like&lt;/p&gt; &lt;p&gt;&lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/WPFScribblePart1TheGUI_CC3C/App5.png" atomicselection="true"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="347" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/WPFScribblePart1TheGUI_CC3C/App_thumb3.png" width="391" border="0"&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;The basic GUI is a window, so Scribble.xaml currently has a Window root entry.&amp;nbsp; It also has a Grid container, which is exactly as its name suggests a grid where you can place components.&amp;nbsp; Our grid is fairly straightforward, it has 4 rows (1 for the menu, 1 for the toolbar, 1 for the main window and 1 for the status bar) so to start you will define this grid like this:&lt;/p&gt; &lt;p&gt;&lt;code&gt;&amp;lt;grid background="White" name="DocumentRoot"&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;grid.rowdefinitions&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rowdefinition height="Auto"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- Menu --&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rowdefinition height="Auto"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- Tool Bar --&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rowdefinition height="*"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- Content Area --&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;rowdefinition height="Auto"&amp;gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;!-- Status Bar --&amp;gt;&lt;br&gt;&amp;nbsp; &amp;lt;/grid.rowdefinitions&amp;gt;&lt;br&gt;&amp;lt;/grid&amp;gt;&lt;br&gt;&lt;br&gt;&lt;/code&gt;&lt;/p&gt; &lt;p&gt;You can see this is fairly straightforward, the 3 rows with embedded controls are all set to automatic height adjustment, while the row preserved for the content is scaled to fill the rest of the window. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Before I show you the completed XAML for the GUI, just a brief mention about layout controls.&amp;nbsp; You won't add items into the grid directly, rather you will use layout controls like DockPanels, which dock to the grid element, StackPanels which stack on top of each other or Panels which you can place anywhere.&amp;nbsp; This gives the most flexibility to control the layout, so you are going to add 4 DockPanels to the grid, like this:&lt;/p&gt;&lt;code&gt;&lt;pre&gt;&lt;p&gt;&amp;lt;!-- Menu Bar --&amp;gt;&lt;br&gt;&amp;lt;DockPanel&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Name="DockPanel_Menu" &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Grid.Row="0" /&amp;gt;&lt;br&gt;&amp;lt;!-- Tool Bar --&amp;gt;&lt;br&gt;&amp;lt;DockPanel&lt;br&gt;&amp;nbsp;&amp;nbsp; Name="DockPanel_Toolbar" &lt;br&gt;&amp;nbsp;&amp;nbsp; Grid.Row="1"&amp;gt;&lt;br&gt;&amp;lt;DockPanel Name="DockPanel_MainDisplay"&lt;br&gt;&amp;nbsp;&amp;nbsp; Background="DarkGray"&lt;br&gt;&amp;nbsp;&amp;nbsp; Grid.Row="2"&amp;gt;&lt;br&gt;&amp;lt;/DockPanel&amp;gt;&lt;br&gt;&amp;lt;DockPanel Name="DockPanel_StatusBar"&lt;br&gt;&amp;nbsp;&amp;nbsp; Grid.Row="3"&amp;gt;&lt;br&gt;&amp;lt;/DockPanel&amp;gt; &lt;/p&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all you have to do is add the menu, the toolbar and the status bar.&amp;nbsp; The menus are self explanatory, and the status bar is fairly straightforward too.&amp;nbsp; The toolbar no longer needs an ImageStrip, simply add an image to the button.&amp;nbsp; For now that image will be stored on the file system, but later in the project you'll turn them into resources.&amp;nbsp; The XAML now looks like: 
&lt;p&gt;&amp;nbsp; &lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;
      &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="DockPanel_Menu"&lt;/span&gt; 
      &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White" &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="File" &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="NotImplementedMsg&lt;/span&gt;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="New" &lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Open..."&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Close"&lt;/span&gt; &lt;span class="kwrd"&gt;"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Save"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Save As..."&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Separator&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Print"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Print Preview"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Exit"&lt;/span&gt; &lt;span class="attr"&gt;InputGestureText&lt;/span&gt;&lt;span class="kwrd"&gt;="Alt-F4"&lt;/span&gt; 
            &lt;span class="attr"&gt;Click&lt;/span&gt;&lt;span class="kwrd"&gt;="ExitApplication"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem.ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                Click here to exit
              &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem.ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Edit"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Clear All"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Pen"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Thick Pen"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Pen Widths..."&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="View"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Toolbar"&lt;/span&gt; &lt;span class="attr"&gt;IsCheckable&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;Checked&lt;/span&gt;&lt;span class="kwrd"&gt;="SetToolBarVisibility"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;Unchecked&lt;/span&gt;&lt;span class="kwrd"&gt;="SetToolBarVisibility"&lt;/span&gt; &lt;span class="attr"&gt;IsChecked&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;br&gt;&lt;/span&gt;          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Status Bar"&lt;/span&gt; &lt;span class="attr"&gt;IsCheckable&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;Checked&lt;/span&gt;&lt;span class="kwrd"&gt;="SetStatusBarVisibility"&lt;/span&gt; &lt;br&gt;                    &lt;span class="attr"&gt;Unchecked&lt;/span&gt;&lt;span class="kwrd"&gt;="SetStatusBarVisibility"&lt;/span&gt; &lt;span class="attr"&gt;IsChecked&lt;/span&gt;&lt;span class="kwrd"&gt;="True"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Window"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="New Window"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Separator&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Tile"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Cascade"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt; &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="White"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Help"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="Help"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Separator&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt; &lt;span class="attr"&gt;Header&lt;/span&gt;&lt;span class="kwrd"&gt;="About WPFScribble"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MenuItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Menu&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="rem"&gt;&amp;lt;!-- Tool Bar --&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;
      &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="DockPanel_Toolbar"&lt;/span&gt; 
      &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ToolBar&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="toolBar" Button.Click=&lt;span class="kwrd"&gt;="NotImplementedMsg&lt;/span&gt;" &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="New"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\new.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Open"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\open.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Save"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\save.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt; &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;="ApplicationCommands.PrintPreview"&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Print Preview"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\preview.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;  &lt;span class="attr"&gt;Command&lt;/span&gt;&lt;span class="kwrd"&gt;="ApplicationCommands.Print"&lt;/span&gt; &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Print"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\print.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;  &lt;span class="attr"&gt;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;="Help"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Image&lt;/span&gt; &lt;span class="attr"&gt;Source&lt;/span&gt;&lt;span class="kwrd"&gt;="Images\help.bmp"&lt;/span&gt; &lt;span class="attr"&gt;Height&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="attr"&gt;Width&lt;/span&gt;&lt;span class="kwrd"&gt;="16"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Button&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ToolBar&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="DockPanel_MainDisplay"&lt;/span&gt;
               &lt;span class="attr"&gt;Background&lt;/span&gt;&lt;span class="kwrd"&gt;="DarkGray"&lt;/span&gt;
               &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="DockPanel_StatusBar"&lt;/span&gt;
               &lt;span class="attr"&gt;Grid&lt;/span&gt;.&lt;span class="attr"&gt;Row&lt;/span&gt;&lt;span class="kwrd"&gt;="3"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;StatusBar&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="statusBar"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;StatusBarItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
          Press F1 for Help
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;StatusBarItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;StatusBar&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DockPanel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; 
&lt;p&gt;The MenuItem click events are simply being routed to a NotImplementedMsg method in the code behind.&amp;nbsp; This is coded up as: 
&lt;p&gt;&amp;nbsp;&lt;pre class="csharpcode"&gt;        &lt;span class="kwrd"&gt;void&lt;/span&gt; NotImplementedMsg(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
        {
            MessageBox.Show(&lt;span class="str"&gt;"This function is not yet implemented"&lt;/span&gt;, &lt;span class="str"&gt;"Patience"&lt;/span&gt;);
        }&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&amp;nbsp;&lt;/pre&gt;
&lt;p&gt;This is a fairly standard event wiring up model, except for the EventArgs object which is a RoutedEventArgs object.&amp;nbsp; WPF routes events (So does Windows Forms, it just routes them differently) up a tree hierarchy, so if an event is not handled it bubbles up the tree until it finds a handler.&amp;nbsp; You can also use a tunneling strategy, where the event goes to the tree root first, and then via the children.&amp;nbsp; You can of course still use a direct strategy, analogous to Windows Forms where only the listener registered for events gets the chance to handle the event.&amp;nbsp; in the next installment you'll find out how to deal with RoutedEvents properly.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you'd like the code for this then you can download a &lt;a href="Samples/WPFScribblePart1.zip"&gt;zip&lt;/a&gt; from here.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-1509132796617652384?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/1509132796617652384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=1509132796617652384&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1509132796617652384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/1509132796617652384'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/wpf-scribble-part-1-gui.html' title='WPF Scribble - Part 1 The GUI'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-4361733018505062803</id><published>2006-11-11T17:13:00.001Z</published><updated>2006-11-11T17:15:49.730Z</updated><title type='text'>Styling WPF Buttons</title><content type='html'>&lt;p&gt;I was at TechEd last week and I was asked several times how to customize buttons.  The answer is pretty straightforward, you use styles.  If you're an ASP.Net developer that won't scare you, but if you're a Windows Forms developer then you may need a quick refresher.&lt;/p&gt;&lt;p&gt;You can apply a style to any control, and give default values for properties, so for instance you could create a style template that always coloured your buttons red, something like this:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;p&gt;&amp;lt;Window.Resources&amp;gt;
&amp;lt;Style x:Key="MyRedButtonStyle" TargetType="{x:Type Button}"&amp;gt;
&amp;lt;Setter Property="Background" Value="Red" /&amp;gt;
&amp;lt;/Style&amp;gt;
&amp;lt;/Window.Resources&amp;gt;&lt;/p&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use this style in your button is fairly  trivial, you simply reference the key you created as in the following code:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;Button Style="{StaticResource MyRedButtonStyle}"&amp;gt; Hello&amp;lt;/Button&amp;gt;&lt;/p&gt;&lt;/code&gt;
&lt;p&gt;Of course this simply allows you to change the basic properties, what if I want to change the entire look and feel of the Button control - well in that case you need to provide a control template.  At first glance this appears more complex, but it isn't really that bad. &lt;/p&gt;&lt;pre&gt;&lt;code&gt;
&lt;p&gt;&amp;lt;Window.Resources&amp;gt;
&amp;lt;Style x:Key="MyButtonStyle" TargetType="{x:Type Button}"&amp;gt;
  &amp;lt;Setter Property="Template"&amp;gt;
  &amp;lt;Setter.Value&amp;gt;
    &amp;lt;ControlTemplate TargetType="{x:Type Button}"&amp;gt;
    &amp;lt;Grid&amp;gt;
      &amp;lt;Ellipse Name="EllipseButton" &lt;/p&gt;&lt;p&gt;               Width="{TemplateBinding Width}" &lt;/p&gt;&lt;p&gt;               Height="{TemplateBinding Height}" &amp;gt;
        &amp;lt;Ellipse.BitmapEffect&amp;gt;
           &amp;lt;BevelBitmapEffect BevelWidth="3" &lt;/p&gt;&lt;p&gt;                              Relief=".6" &amp;gt;&lt;/p&gt;&lt;p&gt;           &amp;lt;/BevelBitmapEffect&amp;gt;
        &amp;lt;/Ellipse.BitmapEffect&amp;gt; &lt;/p&gt;&lt;p&gt;        &amp;lt;Ellipse.Fill&amp;gt;
           &amp;lt;LinearGradientBrush StartPoint="0,0" EndPoint="0,1"&amp;gt;
              &amp;lt;GradientStop Color="Aqua" Offset="0" /&amp;gt;
              &amp;lt;GradientStop Color="Gray" Offset=".9" /&amp;gt;
           &amp;lt;/LinearGradientBrush&amp;gt;
        &amp;lt;/Ellipse.Fill&amp;gt;
&lt;p&gt;      &amp;lt;/Ellipse&amp;gt;
      &amp;lt;ContentPresenter TextElement.FontSize="{TemplateBinding FontSize}"
                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /&amp;gt;
    &amp;lt;/Grid&amp;gt;     &lt;p&gt;   &amp;lt;/ControlTemplate&amp;gt;
  &amp;lt;/Setter.Value&amp;gt;
 &amp;lt;/Setter&amp;gt;
&amp;lt;/Style&amp;gt; &lt;/p&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you provide a control template you need to do all the redrawing, as it currently stands your button UI doesn't change when the button is clicked, so you need to provide a trigger to update the template as the user clicks on the button, as shown below: &lt;/p&gt;&lt;pre&gt;&lt;code&gt;
&lt;p&gt;&amp;lt;Window.Resources&amp;gt;
&amp;lt;Style x:Key="MyButtonStyle" TargetType="{x:Type Button}"&amp;gt;
&lt;/p&gt;&lt;p&gt;. . .&lt;/p&gt;&lt;p&gt;  &amp;lt;/Grid&amp;gt;
  &amp;lt;ControlTemplate.Triggers&amp;gt;
    &amp;lt;MultiTrigger&amp;gt;
      &amp;lt;MultiTrigger.Conditions&amp;gt;
        &amp;lt;Condition Property="IsMouseOver" Value="True" /&amp;gt;
        &amp;lt;Condition Property="IsPressed" Value="True" /&amp;gt;
      &amp;lt;/MultiTrigger.Conditions&amp;gt;
      &amp;lt;Setter TargetName="EllipseButton" Property="Ellipse.Fill" &amp;gt;
       &amp;lt;Setter.Value&amp;gt;
         &amp;lt;LinearGradientBrush StartPoint="0,1" EndPoint="0,0"&amp;gt;
            &amp;lt;GradientStop Color="Aqua" Offset="0" /&amp;gt;
            &amp;lt;GradientStop Color="Gray" Offset=".9" /&amp;gt;
         &amp;lt;/LinearGradientBrush&amp;gt;
       &amp;lt;/Setter.Value&amp;gt;
      &amp;lt;/Setter&amp;gt;
      &amp;lt;Setter TargetName="EllipseButton" Property="Ellipse.BitmapEffect" &amp;gt;
        &amp;lt;Setter.Value&amp;gt;
          &amp;lt;BevelBitmapEffect BevelWidth="1" Relief=".1" &amp;gt;&amp;lt;/BevelBitmapEffect&amp;gt;
        &amp;lt;/Setter.Value&amp;gt;
      &amp;lt;/Setter&amp;gt; &lt;/p&gt;&lt;p&gt;     &amp;lt;/MultiTrigger&amp;gt;
    &amp;lt;/ControlTemplate.Triggers&amp;gt;
&lt;p&gt;   &amp;lt;/ControlTemplate&amp;gt;
  &amp;lt;/Setter.Value&amp;gt;
 &amp;lt;/Setter&amp;gt;
&amp;lt;/Style&amp;gt;
&lt;/code&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;p&gt;You can customise any control in this way and the flexibility is incredible.  Of course you could also do all of this through source code if you are completely set against XAML.&lt;/p&gt;
&lt;p&gt; You should notice the TemplateBinding directives, these simply specify that the values in the XAML will be passed through to the template, as the example below shows, the height and width attributes are passed to the underlying template:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
&lt;p&gt;&amp;lt;Button Name ="myButton"
           Style="{StaticResource MyButtonStyle}"
           Height="80" Width="80" Click="OnClick"&amp;gt;
Button&amp;lt;/Button&amp;gt;&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running this gives you the following button , and clicking it changes the GUI, so all in all a great 10 minutes work.
&lt;p&gt;
&lt;p&gt; &lt;a href="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/StylingWPFButtons_F239/button10.png" atomicselection="true"&gt;&lt;img style="BORDER-TOP-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height="84" src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/StylingWPFButtons_F239/button_thumb8.png" width="91" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-4361733018505062803?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/4361733018505062803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=4361733018505062803&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/4361733018505062803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/4361733018505062803'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/styling-wpf-buttons.html' title='Styling WPF Buttons'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-5796391545656252380</id><published>2006-11-11T16:13:00.001Z</published><updated>2006-11-11T16:13:41.603Z</updated><title type='text'>Windows Live Writer</title><content type='html'>&lt;p&gt;I'm trying out the new writer and it certainly beats Notepad :-)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-5796391545656252380?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/5796391545656252380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=5796391545656252380&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5796391545656252380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/5796391545656252380'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/11/windows-live-writer.html' title='Windows Live Writer'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-114942584636725879</id><published>2006-06-04T13:37:00.000+01:00</published><updated>2006-11-11T16:06:08.241Z</updated><title type='text'>Developer Day Review</title><content type='html'>Well, Developer Day has come and gone, and it was a very good day, with some interesting talks. As usual, some of the talks I really wanted to see clashed with my presentation. My talk on Workflow suffered form the usual timeflow management problems I seem to suffer from, so I didn't manage to finish everything, so didn't demo some of the really cool features.  The presentation and demos are available &lt;a href="http://www.wintersfamily.plus.com/applications/DeveloperDay.zip"&gt;here&lt;/a&gt;, obviously you need to install WF beta 2 if you wantto run them.

One thing I didn't get to demonstrate is the workflow debugger, which allows you to put breakpoints in the visual editor and then break into the workflow.  It's simplicity itself, however it doesn't work if your workflow is in a workflow library, as debugging the workflow host doesn't trigger the "Ah, you're a workflow, so I'll load the workflow debugger" moment for VS20005.  To fix it simply set the workflow library as the startup project, open up the project properties and navigate to the Debug pane.  Make sure you select your workflow host application as the external process to start up (unless you're hosting the workflow in an ASP.Net application, then you should specify the URL of the starting page)

&lt;img src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/DebugProperties-711791.JPG" border="0" alt="DebugProperties" align="middle" /&gt;

Now you can set breakpoints in the designer, and they will be hit during debug.  You can move through the workflow using F10 and F11 as normal, and you can still set breakpoints in the code.  The call stack window shows activities rather than call stacks (unless it breaks in code)

&lt;img src="http://www.wintersfamily.plus.com/blogs/JamesWinters/uploaded_images/Breakpoint-701701.JPG" border="0" alt="Breakpoints" /&gt;

Go ahead, give it a try.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-114942584636725879?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.developerday.co.uk' title='Developer Day Review'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/114942584636725879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=114942584636725879&amp;isPopup=true' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/114942584636725879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/114942584636725879'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/06/developer-day-review.html' title='Developer Day Review'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12586772.post-114676368957593694</id><published>2006-05-04T18:15:00.000+01:00</published><updated>2006-11-11T16:06:08.158Z</updated><title type='text'>XML and £ symbols</title><content type='html'>I post quite a bit on the ASP.NET forums, and occasionally I get asked a question via private message.  One I was asked with today was how to deal with the £ symbol in an XML file that has been saved in Windows.

The problem here is that if you edit and save something in Windows it typically saves it with an ANSI encoding.  Now ANSI encoding doesn't actually mean anything, what this actually means is that the file is saved using an ANSI standard Windows code page.  For Western Europe and the USA this is typically CP1252, which is essentially the same as ISO-8859-1, except for some control characters in the range 128-152.  Unfortunately this includes the Euro symbol, so you can't just say encoding="ISO-8859-1" in the xml declaration, I believe you can say encoding="windows-1252", but haven't actually tried this.  Usually what I do is simply open the file in Notepad and then save it as UTF-8 using the little dropdown.

What about doing it via code though?

Well usually I do something like this:
&lt;pre&gt;&lt;code&gt;
StreamReader reader = new StreamReader("..\\..\\pound.xml", System.Text.Encoding.Default);
XmlDocument doc1 = new XmlDocument();
doc1.Load(reader);
XmlTextWriter tw = new XmlTextWriter("..\\..\\pound2.xml", Encoding.UTF8); 
doc1.WriteContentTo (tw);
tw.Close();
&lt;/code&gt;&lt;/pre&gt;

Of course if your default Windows encoding isn't CP1252 this won't work :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12586772-114676368957593694?l=www.jghd.co.uk%2Fblogs%2FJamesWinters' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/114676368957593694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=12586772&amp;postID=114676368957593694&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/114676368957593694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12586772/posts/default/114676368957593694'/><link rel='alternate' type='text/html' href='http://www.jghd.co.uk/blogs/JamesWinters/2006/05/xml-and-symbols.html' title='XML and £ symbols'/><author><name>James</name><uri>http://www.blogger.com/profile/01232316028350920312</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03744502423411745886'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry></feed>