tag:blogger.com,1999:blog-71693995307358334372024-03-08T22:13:35.996+00:00Code Flow 49John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-7169399530735833437.post-42605772501038355912010-08-07T19:12:00.000+01:002010-08-07T19:12:15.814+01:00Resizable WPF Windows without Minimize and Maximize buttons<p>When I first started looking at WPF, one of the attractions was the ease with which WPF layout options can be used to create windows with resizable content. I pretty quickly got the idea that resizable windows should be the rule, rather than the exception.</p><p>The ability to resize a window is controlled by the Window’s ResizeMode property. When you set ResizeMode to CanResize or CanResizeWithGrip you get a window that can be resized. You also get minimize and maximize buttons in the window’s title bar. </p><p>Setting a Window’s WindowStyle property to ToolWindow creates a window with a thin title bar, a close button and no minimized or maximize buttons. However, (in addition to looking a bit odd) this still allows access to the minimize and maximize commands from the system menu:</p><p> <a href="http://lh5.ggpht.com/_BIamsXoZuOw/TFhu-9At3qI/AAAAAAAAAI8/G3rxqvTHq1A/s1600-h/toolwindow%5B2%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="toolwindow" border="0" alt="toolwindow" src="http://lh6.ggpht.com/_BIamsXoZuOw/TFhu_btY54I/AAAAAAAAAJA/r1FvohIqEuA/toolwindow_thumb.png?imgmax=800" width="329" height="178" /></a> </p><p>WPF’s Window class does not provide any way to create a resizable window that cannot be minimized.</p><p>You might think that’s fair enough for a top level window, but it’s not so good for secondary windows, especially modal dialogs.</p><p>Modal dialogs should never minimize. When a modal dialog is displayed, the owner window is disabled until the dialog is closed. If the modal dialog is minimized, the owner window remains disabled – to the user it looks like the application just locked up.</p><h2>The Solution</h2><p>WPF windows are just like any other as far as the operating system is concerned. The window’s title bar and borders are provided by the operating system. When you set the WindowStyle and ResizeMode properties, WPF uses the SetWindowLong Windows API call to modify the style and extended style flags for the window. </p><p>As far as the operating system is concerned, the appearance of the minimize and maximize buttons is controlled by the WS_MINIMIZEBOX and WS_MAXIMIZEBOX flags in the <a href="http://msdn.microsoft.com/en-us/library/ms632600.aspx">window style</a>. If we want to control the appearance of these buttons for ourselves, we can set and clear these two flags with a combination of calls to the GetWindowLong and SetWindowLong functions.</p><p>To implement this behaviour, I created the <a href="http://sites.google.com/site/codeflow49/files/ExtraWindowStyles.cs">ExtraWindowStyles class</a>. This class provides attached properties CanMinimize and CanMaximize which can be applied to a window to hide (or show) the minimize and maximize buttons.</p><p>Example usage:</p><pre class="code"><span style="color: blue"><</span><span style="color: #a31515">Window </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Class</span><span style="color: blue">="ExtraWindowStyles.TestWindow"</span>
<span style="color: red">xmlns</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
</span> <span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">x</span><span style="color: blue">="http://schemas.microsoft.com/winfx/2006/xaml"
</span> <span style="color: red">xmlns</span><span style="color: blue">:</span><span style="color: red">ews</span><span style="color: blue">="clr-namespace:ExtraWindowStyles"
</span> <span style="color: red">Title</span><span style="color: blue">="TestWindow"
</span> <span style="color: red">ResizeMode</span><span style="color: blue">="CanResizeWithGrip"
</span> <span style="color: red">ews</span><span style="color: blue">:</span><span style="color: red">ExtraWindowStyles.CanMinimize</span><span style="color: blue">="false"
</span> <span style="color: red">ews</span><span style="color: blue">:</span><span style="color: red">ExtraWindowStyles.CanMaximize</span><span style="color: blue">="false"
</span> <span style="color: red">Height</span><span style="color: blue">="300"
</span> <span style="color: red">Width</span><span style="color: blue">="300"
>
</span></pre><p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/TF2er3RFxoI/AAAAAAAAAJE/IksZh9uWhs0/s1600-h/testwindow%5B2%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="testwindow" border="0" alt="testwindow" src="http://lh3.ggpht.com/_BIamsXoZuOw/TF2estjT-rI/AAAAAAAAAJI/wSiPMUc7KUE/testwindow_thumb.png?imgmax=800" width="300" height="300" /></a> </p><p>Implementing this behaviour using attached properties makes it straightforward to use with styles:</p><pre class="code"><span style="color: blue"><</span><span style="color: #a31515">Style </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Key</span><span style="color: blue">="myDialogStyle" </span><span style="color: red">TargetType</span><span style="color: blue">="Window">
<</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="ews:ExtraWindowStyles.CanMinimize"
</span> <span style="color: red">Value</span><span style="color: blue">="false"
/>
<</span><span style="color: #a31515">Setter </span><span style="color: red">Property</span><span style="color: blue">="ews:ExtraWindowStyles.CanMaximize"
</span> <span style="color: red">Value</span><span style="color: blue">="false"
/>
</</span><span style="color: #a31515">Style</span><span style="color: blue">>
</span></pre><p>Download the source here: <a href="http://sites.google.com/site/codeflow49/files/ExtraWindowStyles.cs">ExtraWindowStyles.cs</a></p>John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com1tag:blogger.com,1999:blog-7169399530735833437.post-15125249128273866652010-06-17T19:02:00.001+01:002010-06-17T19:02:56.277+01:00Data binding to Fields with a DynamicObject Proxy<p>WPF data binding only works with properties, not fields. If you have an existing type with fields that you want to bind to, you need some kind of wrapper to expose the fields as properties. That can lead to a lot of replication, wouldn’t it be nice if there was an automatic way to do this?</p> <p>Enter FieldToPropertyProxy. This class is a slight variation on <a href="http://codeflow49.blogspot.com/2010/06/automatic-inotifypropertychanged-with.html">my previous post</a>, again derived from DynamicObject.</p> <p>The implementation is almost identical to <a href="http://codeflow49.blogspot.com/2010/06/automatic-inotifypropertychanged-with.html">NotifyPropertyChangedProxy</a>, except that references to GetProperty and PropertyInfo are replaced with GetField and FieldInfo.</p> <p>As well as converting fields into properties, NotifyPropertyChangedProxy includes an implementation of INotifyPropertyChanged.</p> <p>Download the code here: <a href="http://sites.google.com/site/codeflow49/files/FieldToPropertyProxy.cs">FieldToPropertyProxy.cs</a></p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-77924265685064880482010-06-08T20:12:00.007+01:002010-06-09T19:11:18.217+01:00Automatic INotifyPropertyChanged with DynamicObject<p>Implementing the <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx">INotifyPropertyChanged</a> interface is Microsoft’s recommended mechanism for providing notifications to update WPF data bindings.</p><p>Normally, I like to use <a href="http://codeflow49.blogspot.com/2009/10/code-snippets-for-inotifypropertychange.html">my code snippets</a> to implement INotifyPropertyChanged on classes I’m writing, but what if I want to use data binding on a class that I didn’t write and which doesn’t support INotifyPropertyChanged?</p><p>In this post, I show how to use the <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx">DynamicObject</a> class introduced in .Net 4 to create a proxy that wraps access to another object’s properties while adding automatic support for INotifyPropertyChanged.</p><a name='more'></a> <p>My class NotifyPropertyChangedProxy is derived from DynamicObject and overrides three methods to dynamically provide access to the properties of a wrapped object.</p><p>I think this example shows that DynamicObject has huge potential for dynamically generating many different types of proxies.</p><p>There is a caveat when implementing INotifyPropertyChanged using a proxy like this. The PropertyChanged event will only be raised if a property is set through the proxy. Setting the property using the wrapped object directly won’t produce any notification event.</p><p>Download the source code here: <a href="http://sites.google.com/site/codeflow49/files/NotifyPropertyChangedProxy.cs">NotifyPropertyChangedProxy.cs</a></p><h2>Using NotifyPropertyChangedProxy </h2><p>As an example, let’s take a simple class with automatically implemented properties:</p><pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">Person
</span>{
<span style="color: blue">public string </span>LastName { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
<span style="color: blue">public string </span>FirstName { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
<span style="color: blue">public int </span>Age { <span style="color: blue">get</span>; <span style="color: blue">set</span>; }
}</pre><p>To create a proxy for this class, simply construct an instance of NotifyPropertyChangedProxy, passing the constructor a reference to the Person instance to be wrapped:</p><pre class="code"><span style="color: blue">dynamic </span>myPerson = <span style="color: blue">new </span><span style="color: #2b91af">NotifyPropertyChangedProxy</span>( <span style="color: blue">new </span><span style="color: #2b91af">Person</span>() );</pre><p>The most likely use for NotifyPropertyChangedProxy is as a data binding source:</p><pre class="code">personGrid.DataContext = myPerson;</pre><p>Having set the proxy object as the DataContext, we can create bindings using the property names of the wrapped object:</p><pre class="code"><span style="color: blue"><</span><span style="color: #a31515">TextBox </span><span style="color: red">Text</span><span style="color: blue">="{</span><span style="color: #a31515">Binding </span><span style="color: red">Path</span><span style="color: blue">=FirstName}"/>
</span></pre><p>Using the new dynamic C# keyword (see the declaration of myPerson above), we can also set the properties in code via the proxy:</p><pre class="code">myPerson.FirstName = <span style="color: #a31515">"John-Martin"</span>;
myPerson.LastName = <span style="color: #a31515">"Malone"</span>;
myPerson.Age = 39;</pre><p>These property changes will cause the PropertyChanged event to be raised, and the data bound UI elements will be updated.</p><h2>A walk through NotifyPropertyChangedProxy </h2><br />
<pre class="code"><span style="color: blue">public class </span><span style="color: #2b91af">NotifyPropertyChangedProxy </span>: <span style="color: #2b91af">DynamicObject</span>, <span style="color: #2b91af">INotifyPropertyChanged
</span>{
<span style="color: blue">public object </span>WrappedObject { <span style="color: blue">get</span>; <span style="color: blue">private set</span>; }
<span style="color: blue">public </span>NotifyPropertyChangedProxy(<span style="color: blue">object </span>wrappedObject)
{
<span style="color: blue">if </span>(wrappedObject == <span style="color: blue">null</span>)
<span style="color: blue">throw new </span><span style="color: #2b91af">ArgumentNullException</span>(<span style="color: #a31515">"wrappedObject"</span>);
WrappedObject = wrappedObject;
}</pre><p>The class inherits from DynamicObject and implements INotifyPropertyChanged.</p><p>The WrappedObject property is automatically implemented and has a private setter which is used in the constructor.</p><pre class="code"><span style="color: blue">#region </span>INotifyPropertyChanged support
<span style="color: blue">protected virtual void </span>OnPropertyChanged(<span style="color: blue">string </span>propertyName)
{
<span style="color: blue">var </span>handler = PropertyChanged;
<span style="color: blue">if </span>(handler != <span style="color: blue">null</span>)
{
handler(<span style="color: blue">this</span>, <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedEventArgs</span>(propertyName));
}
}
<span style="color: blue">public event </span><span style="color: #2b91af">PropertyChangedEventHandler </span>PropertyChanged;
<span style="color: blue">#endregion
</span></pre><p>The boilerplate OnPropertyChanged method and PropertyChanged event were generated with <a href="http://codeflow49.blogspot.com/2009/10/code-snippets-for-inotifypropertychange.html">my code snippets</a>.</p><pre class="code"><span style="color: blue">public override </span><span style="color: #2b91af">IEnumerable</span><<span style="color: blue">string</span>> GetDynamicMemberNames()
{
<span style="color: blue">return from </span>f <span style="color: blue">in </span>WrappedObject.GetType().GetProperties(<span style="color: #2b91af">BindingFlags</span>.Instance | <span style="color: #2b91af">BindingFlags</span>.Public)
<span style="color: blue">select </span>f.Name;
}</pre><p>The override of GetDynamicMemberNames is called by the Visual Studio debugger. The implementation calls the GetProperties method on the wrapped object’s Type and uses a straightforward LINQ query to supply the member names.</p><pre class="code"><span style="color: blue">public override bool </span>TryGetMember(<span style="color: #2b91af">GetMemberBinder </span>binder, <span style="color: blue">out object </span>result)
{
<span style="color: green">// Locate property by name
</span> <span style="color: blue">var </span>propertyInfo = WrappedObject.GetType().GetProperty(binder.Name, <span style="color: #2b91af">BindingFlags</span>.Instance | <span style="color: #2b91af">BindingFlags</span>.Public | (binder.IgnoreCase ? <span style="color: #2b91af">BindingFlags</span>.IgnoreCase : 0));
<span style="color: blue">if </span>(propertyInfo == <span style="color: blue">null </span>|| !propertyInfo.CanRead)
{
result = <span style="color: blue">null</span>;
<span style="color: blue">return false</span>;
}
result = propertyInfo.GetValue(WrappedObject, <span style="color: blue">null</span>);
<span style="color: blue">return true</span>;
}</pre><p>The TryGetMember override calls the GetProperty method on the wrapped object’s Type. If no property is found with a matching name, or if the property doesn’t have a get accessor, the parameter ‘result’  is set to null, and the method returns false. If an appropriate PropertyInfo object is found, its GetValue method is used to set result and the method returns true.</p><pre class="code"><span style="color: blue">public override bool </span>TrySetMember(<span style="color: #2b91af">SetMemberBinder </span>binder, <span style="color: blue">object </span>value)
{
<span style="color: green">// Locate property by name
</span> <span style="color: blue">var </span>propertyInfo = WrappedObject.GetType().GetProperty(binder.Name, <span style="color: #2b91af">BindingFlags</span>.Instance | <span style="color: #2b91af">BindingFlags</span>.Public | (binder.IgnoreCase ? <span style="color: #2b91af">BindingFlags</span>.IgnoreCase : 0));
<span style="color: blue">if </span>(propertyInfo == <span style="color: blue">null </span>|| !propertyInfo.CanWrite)
<span style="color: blue">return false</span>;
<span style="color: blue">object </span>newValue = value;
<span style="color: green">// Check the types are compatible
</span> <span style="color: #2b91af">Type </span>propertyType = propertyInfo.PropertyType;
<span style="color: blue">if </span>(!propertyType.IsAssignableFrom(value.GetType()))
{
newValue = <span style="color: #2b91af">Convert</span>.ChangeType(value, propertyType);
}
propertyInfo.SetValue(WrappedObject, newValue, <span style="color: blue">null</span>);
OnPropertyChanged(binder.Name);
<span style="color: blue">return true</span>;
}</pre><p>The TrySetMember override starts in a similar way to TryGetMember, returning false if a PropertyInfo object cannot be retrieved for the specified name, or if the property found doesn’t have a set accessor. Next, we check whether the Type of the value parameter is compatible with the Type of the property. If not, Convert.ChangeType is used to convert to the required type. Finally, PropertyInfo.SetValue is used to apply the new value, OnPropertyChanged is called to fire the PropertyChanged event, and the method returns true.</p><p>Convert.ChangeType will throw an exception if the conversion cannot be performed. The documentation for DynamicObject.TrySetMember states that the method should return false if the operation is unsuccessful, so my first draft of this override caught these exceptions and returned false from within the exception handler. With this approach, WPF’s data binding reports (via the Visual Studio debug output):</p><p><font face="Courier New">Property path is not valid. 'System.Dynamic.DynamicObject+MetaDynamic' does not have a public property named 'Age'.</font></p><p>That’s not a very helpful message, since the property <strong>does</strong> exist. The code shown above allows any exceptions thrown by ChangeType to be handled further up the stack, in which case a more useful message appears in the debugger.</p>John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com2tag:blogger.com,1999:blog-7169399530735833437.post-55937367314375241392010-06-02T19:00:00.001+01:002010-06-02T19:00:40.444+01:00Snoop is on CodePlex<p>Snoop is an essential tool for understanding and debugging WPF applications.</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/TAacRHlz08I/AAAAAAAAAI0/V7gQPjuGowE/s1600-h/snoop%5B6%5D.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="snoop" border="0" alt="snoop" src="http://lh6.ggpht.com/_BIamsXoZuOw/TAacR_fA6iI/AAAAAAAAAI4/3X-SOOPZ5ic/snoop_thumb%5B4%5D.png?imgmax=800" width="405" height="265" /></a> </p> <p>Originally created by <a href="http://blois.us/blog/">Pete Blois</a>, Snoop is now maintained by <a href="http://www.cplotts.com/">Cory Plott</a>, who has made it available <a href="http://snoopwpf.codeplex.com/">on CodePlex</a>, and added WPF 4.0 compatibility.</p> <p>Simply put, Snoop displays the visual tree of a running WPF application in the left pane, and the properties of the selected element in the right pane. Read a more detailed description from Pete Blois at <a title="http://blois.us/Snoop/" href="http://blois.us/Snoop/">http://blois.us/Snoop/</a></p> <p>Download the latest Snoop from <a title="http://snoopwpf.codeplex.com/releases" href="http://snoopwpf.codeplex.com/releases">http://snoopwpf.codeplex.com/releases</a></p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-82445886603466862552010-03-03T20:18:00.001+00:002010-03-23T20:39:54.649+00:00Four Free XAML Editors Reviewed<p>I like to type XAML.</p> <p>It’s an extremely flexible and expressive way to work when sketching out the logical structure of a new piece of UI.</p> <p>A graphical design tool like Blend is best for some things, like creating a non-trivial gradient brush, but at some point it all comes down to the code.</p> <p>To satisfy my need for speed and create a sense of flow I need a fast editor that can provide instant feedback.</p> <p>XAML editors exist on a continuum from the fast and lightweight to the more powerful but cumbersome. The professional tools (Visual Studio and Blend) occupy the heavyweight end, but there are also a number of free tools that provide a more basic but responsive experience.</p> <p>In this post, I’ll look in detail at four free XAML editors all of which are quick to start up and responsive as you type.</p> <a name='more'></a> <h3>The Pro Tools versus the free stuff</h3> <p>The XAML editor in Visual Studio 2008 has excellent IntelliSense support, but it’s way too slow to be really useful, and fails to understand code that other editors can take in their stride. Better things are promised with the designer in VS2010.</p> <p>Of course, Expression Blend is just a glorified a XAML editor, and you can type XAML straight into Blend’s editor window. Blend 3 also has XAML IntelliSense, but as a straight-out text editor it’s not the most responsive.</p> <p>The free XAML editors I’m looking at here all have some basics in common. Each has a text area where you can edit your XAML. That XAML is parsed by the editor and the objects created are then hosted in a content control. These are live UI objects that respond to mouse and keyboard events, so you can click buttons, type into text boxes and even test out state transitions.</p> <h3>XAML Cruncher</h3> <p><a title="http://www.charlespetzold.com/wpf/" href="http://lh5.ggpht.com/_BIamsXoZuOw/S6km_7dE2KI/AAAAAAAAAH4/9Rc8ftM4HvQ/s1600-h/XAMLCruncher%5B5%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XAMLCruncher" border="0" alt="XAMLCruncher" src="http://lh3.ggpht.com/_BIamsXoZuOw/S6kkRy-a8gI/AAAAAAAAAH8/Z2FTzI58A2I/XAMLCruncher_thumb%5B2%5D.png?imgmax=800" width="405" height="230" /> </a></p> <p>Created by the legendary Charles Petzold, XAML Cruncher was originally a sample program featured in Petzold’s book ‘<a href="http://www.amazon.co.uk/Applications-Code-Markup-Presentation-Foundation/dp/0735619573%3FSubscriptionId%3D0JTCV5ZMHMF7ZYTXGFR2%26tag%3Dstressmanagem057%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0735619573">Applications = Code + Markup</a>’. The downloadable version 2.0 (available from <a href="http://www.charlespetzold.com/wpf/">http://www.charlespetzold.com/wpf/</a>) has some extra features not seen in the book.</p> <p>XAML Cruncher is the most barebones XAML editor. It’s essentially a Notepad clone, with the addition of a large pane to the right which displays the result of parsing the XAML entered int0 text pane.</p> <p>XAML Cruncher feels very fast and responsive. It automatically re-parses the XAML as you type. It has a tendency to lock up if you start doing complicated things with triggers, but mostly it works.</p> <p>One killer feature that keeps this program on my desktop: the ‘Load Assembly’ command. XAML Cruncher allows you to add references to external assemblies – useful for testing out your own controls. Crucially this list is saved, so you don’t have to re-add your assemblies every time you start the program.</p> <h3>XamlPad</h3> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/S47D9zh-C7I/AAAAAAAAAIA/NiVBs_vcCJs/s1600-h/XamlPad%5B1%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XamlPad" border="0" alt="XamlPad" src="http://lh6.ggpht.com/_BIamsXoZuOw/S47D_LpjyWI/AAAAAAAAAIE/qdSnpvOD2IE/XamlPad_thumb%5B1%5D.png?imgmax=800" width="405" height="312" /></a> </p> <p>XamlPad is a tool produced by Microsoft and distributed (sporadically) as part of the Windows SDK. Unfortunately, it was not included with the SDK version that shipped with VS2008.</p> <p>You can download it with the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=F26B1AA4-741A-433A-9BE5-FA919850BDBF&displaylang=en">February 2008 Windows SDK for Windows Server 2008 and .NET Framework 3.5</a></p> <p>XamlPad is pretty basic. It significantly lacks any facility to open or save XAML files - you just type your XAML into the text box. It does, however, remember previous content when closed and restarted.</p> <p>Notable features include the Visual Tree Explorer which displays the visual tree of your creation. Select an item on this tree and its dependency properties are displayed in the Property Tree Explorer.</p> <h3>XamlPadX</h3> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/S47EAi2MKlI/AAAAAAAAAIQ/ShtU_2Pbv2o/s1600-h/XamlPadX%5B2%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XamlPadX" border="0" alt="XamlPadX" src="http://lh6.ggpht.com/_BIamsXoZuOw/S47EBu_RixI/AAAAAAAAAIY/5jT6HKr4-3A/XamlPadX_thumb%5B1%5D.png?imgmax=800" width="405" height="355" /></a> </p> <p>XamlPadX is the editor I use most frequently outside of Visual Studio. It was created by Lester Lobo and can be downloaded from <a href="http://blogs.msdn.com/llobo/archive/2008/08/25/xamlpadx-4-0.aspx">this entry on his blog</a>.</p> <p>This is another fast and lightweight tool, but this one packs a few more features.</p> <p>The text editor features XML syntax highlighting, can collapse tags and will automatically create closing tags as you type. If your XAML can’t be parsed, the error message displayed on the status bar includes a hyperlink to jump straight to the offending code.</p> <p>The Visual Tree Explorer and Property Tree Explorer are similar to XamlPad. I tend not to use these, I prefer to point <a href="http://blois.us/Snoop/">Snoop</a> at the rendered content.</p> <p>Toolbar buttons include options to print the rendered content, or to save a snapshot as a jpeg.</p> <p>There are a number of useful features hidden away on the editor’s context menu. These include the ability to correctly indent selected XAML, or to comment out the selection.</p> <p>Also available via the context menu is a collection of XAML snippets – handy when you can’t recall the correct syntax for setting up a gradient brush. The collection of snippets is customisable so you can change the supplied snippets or add your own.</p> <p>XamlPadX supports plugins and comes with 3 of them: a clipboard viewer, a path designer and most usefully a colour picker. The colour picker includes the ability to right-click any point on another program to grab an RGB value, and then paste it into your XAML.</p> <p>XamlPadX can load and reference external assemblies, but annoyingly it doesn’t remember these references when you close the program and restart it.</p> <h3>Kaxaml</h3> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/S6kkTecNhBI/AAAAAAAAAIg/ujRqQW5umTg/s1600-h/Kaxaml%5B2%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Kaxaml" border="0" alt="Kaxaml" src="http://lh6.ggpht.com/_BIamsXoZuOw/S6kkUzDJH8I/AAAAAAAAAIo/wbUJhIXhax8/Kaxaml_thumb%5B1%5D.png?imgmax=800" width="405" height="343" /></a> </p> <p>This one is another favourite. Available from <a title="http://www.kaxaml.com/" href="http://www.kaxaml.com">http://www.kaxaml.com</a>, Kaxaml is the creation of devsigner guru Robby Ingebretsen. I highly recommend checking out <a href="http://blog.nerdplusart.com/">Robby’s blog</a>, and his <a href="http://videos.visitmix.com/MIX09/02W">Design Fundamentals for Developers</a> workshop from last year’s MIX conference.</p> <p></p> <p></p> <p></p> <p>Kaxaml is the easily best looking XAML editor, with a subtle colour palette, well laid-out UI and animated transitions. For example, if your XAML contains errors, the rendered content fades to grey and the error message slides in smoothly from above.</p> <p>Kaxaml sports a tab-based interface to handle multiple XAML files at the same time. Both WPF and Silverlight are supported.</p> <p>Like XamlPadX, the Kaxaml editor includes syntax highlighting and can collapse XML tags (they both use the <a href="http://www.icsharpcode.net/OpenSource/SD/Default.aspx">SharpDevelop</a> editor control). Unlike the other free editors, Kaxaml features IntelliSense code completion.</p> <p>The left part of the window features a number of expandable panels which expose different functions.</p> <p>The Snippets panel has a sizeable collection of default snippets, and the collection is easily extendable. Snippets can be dragged onto the editor window, or new snippets can be added by dragging text from the editor onto the snippets panel.</p> <p>The Colour Picker panel includes a customisable palette, the ability to copy the selected colour onto the clipboard (as an ARGB hex string) or to ‘synchronise with selected text’. This last option allows you to select a colour property in the XAML editor and then drag the mouse cursor around the colour picker to see the colour immediately updated in the editor and the rendered content (no typing required).</p> <p>The snapshot panel allows you to copy an image of the rendered content to the clipboard or save it as a PNG file.</p> <p>The XAML Scrubber panel can automatically tidy up your code, with options to move attributes onto separate lines,  re-order attributes by importance, remove common default values and control indentation and numeric precision.</p> <p>I have one gripe with Kaxaml. By default there is a 2 second delay before the XAML you type is parsed and rendered. This makes the program feel less responsive than the other editors reviewed here. This delay can be reduced to 1 second through the Parser tab on the Settings panel.</p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-12166925011551181062009-10-29T21:18:00.001+00:002009-10-29T21:18:17.730+00:00Code Snippets for INotifyPropertyChanged<p>The <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx">INotifyPropertyChanged</a> interface is one of the mechanisms available to update WPF bindings when a property value changes.</p> <p>If you work with the Model-View-ViewModel pattern, you probably implement INotifyPropertyChanged in your ViewModel classes.</p> <p>To help myself create properties with support for INotifyPropertyChanged, I created a couple of simple code snippets with literal replacements for the property name and type.</p> <p><a href="http://sites.google.com/site/codeflow49/files/inpc.vsi">Click here</a> to download and install the snippets.</p> <a name='more'></a> <h2>The snippets</h2> <p>The first snippet (shortcut inpc) provides a barebones implementation of INotifyPropertyChanged:</p> <pre class="code"><span style="color: blue">#region </span>INotifyPropertyChanged support<br /><br /><span style="color: blue">protected virtual void </span>OnPropertyChanged(<span style="color: blue">string </span>propertyName)<br />{<br /> <span style="color: blue">var </span>handler = PropertyChanged;<br /> <span style="color: blue">if </span>(handler != <span style="color: blue">null</span>)<br /> {<br /> handler(<span style="color: blue">this</span>, <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedEventArgs</span>(propertyName));<br /> }<br />}<br /><br /><span style="color: blue">public event </span><span style="color: #2b91af">PropertyChangedEventHandler </span>PropertyChanged;<br /><br /><span style="color: blue">#endregion</span></pre><br /><br /><p>You’d probably want to put the above into a base class to save repetition. You don’t have to use this implementation, but the second snippet calls OnPropertyChanged,  so you need a compatible function available.</p><br /><br /><p>If you want to add some validation on the propertyName parameter, remember that null and String.Empty are legitimate values.</p><br /><br /><p>The second snippet (shortcut propn)  implements a property with a backing field and a call to OnPropertyChanged when the value of the property is set:</p><br /><br /><pre class="code"><span style="color: blue">public int </span>MyProperty<br />{<br /> <span style="color: blue">get<br /> </span>{<br /> <span style="color: blue">return </span>m_MyProperty;<br /> }<br /> <span style="color: blue">set<br /> </span>{<br /> m_MyProperty = <span style="color: blue">value</span>;<br /> OnPropertyChanged(<span style="color: #a31515">"MyProperty"</span>);<br /> }<br />}<br /><span style="color: blue">int </span>m_MyProperty;</pre> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-42318189150475749452009-10-06T20:32:00.001+01:002009-10-06T20:32:02.677+01:00Step-by-step Shiny Button Template with Expression Blend 3 – Part 3<h2>Introduction</h2> <p>This is the third of three posts showing how to use <a href="http://www.microsoft.com/expression/">Expression Blend 3</a> to create a shiny button template for WPF and <a href="http://silverlight.net/">Silverlight</a>.</p> <p><a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">Part 1 Creating the static template (WPF and Silverlight)</a></p> <p><a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with_20.html">Part 2 Adding transitions using triggers (WPF only)</a></p> <p>Part 3 Adding transitions with the Visual State Manager (Silverlight and WPF)</p> <p>In part 1 we created a static template that was applied to the button shown below:</p> <p><a href="http://lh3.ggpht.com/_BIamsXoZuOw/SsubD3oU58I/AAAAAAAAAF4/bbVAp5ny4WU/s1600-h/finalstaticbutton3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="final static button" border="0" alt="final static button" src="http://lh4.ggpht.com/_BIamsXoZuOw/SsubEYSr9NI/AAAAAAAAAF8/0kj8NPDR1yg/finalstaticbutton_thumb1.png?imgmax=800" width="40" height="40" /></a> </p> <p>In this part I’ll walkthrough adding different visual states and animated transitions using the Visual State Manager (VSM). I’ll be working with a Silverlight project, but the same steps should apply using the VSM with WPF.</p> <a name='more'></a> <p>If you haven’t worked through <a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">part 1</a>, you can download the Silverlight version of the static template <a href="http://sites.google.com/site/codeflow49/files/static_shiny_button_silverlight.zip">here</a> and use it as the starting point for what follows.</p> <p>You can download <a href="http://sites.google.com/site/codeflow49/files/shiny_button_silverlight.zip">the finished project for part three</a>, or just <a href="http://sites.google.com/site/codeflow49/files/ShinyRoundButtonSilverlight.xaml">the XAML file containing the finished template</a>.</p> <h3>Part 3 Adding transitions with the Visual State Manager (Silverlight and WPF)</h3> <p>Controls like Button change their visual appearance to indicate different states. In this post, we’ll give our button template different looks when the button is disabled, when it is pressed and when the mouse is over the button.</p> <p>If you’re working with a WPF project, check out my <a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with_20.html#more">previous post</a> regarding the availability of the VSM for WPF.</p> <h2>Get Started</h2> <p>Fire up Blend and open the project from <a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">part one</a>.</p> <p>Right-click on the button, and select ‘Edit Template/Edit Current’. The ‘Objects and Timeline’ panel switches to show the content of the template.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubEzjF2OI/AAAAAAAAAGA/IG8wcFZRjAQ/s1600-h/ObjectsandTimelineeditingtemplate5.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Objects and Timeline editing template" border="0" alt="Objects and Timeline editing template" src="http://lh6.ggpht.com/_BIamsXoZuOw/SsubFZHJznI/AAAAAAAAAGE/gvotEyZcGEM/ObjectsandTimelineeditingtemplate_th.png?imgmax=800" width="275" height="337" /></a> </p> <p> </p> <h2>Add the MouseOver State</h2> <p>Select the States panel and select the MouseOver state.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubFzgpbbI/AAAAAAAAAGI/JrYztM4kL5E/s1600-h/statespanel13.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="states panel" border="0" alt="states panel" src="http://lh6.ggpht.com/_BIamsXoZuOw/SsubGVJ1oiI/AAAAAAAAAGM/-987pCeclI0/statespanel_thumb7.png?imgmax=800" width="350" height="198" /></a> </p> <p>The artboard is now surrounded by a red border to show that it is in recording mode.</p> <h2><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubGy1lQ1I/AAAAAAAAAGQ/n4XbZO4GyD0/s1600-h/staterecordingon4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="state recording on" border="0" alt="state recording on" src="http://lh3.ggpht.com/_BIamsXoZuOw/SsubHGDnlfI/AAAAAAAAAGU/GbnOnRKiv1Q/staterecordingon_thumb2.png?imgmax=800" width="218" height="42" /></a> </h2> <p>In this mode, any properties we change will be recorded as changes to be applied when the selected state is activate.</p> <p>Use the ‘Objects and Timeline’ panel to select the ellipse named ‘lightener’. On the Properties panel, set the ellipse’s Opacity to 20%.</p> <p>Select the ellipse named ‘outer_glow’ and set its Opacity to 100%.</p> <p>The button should now look like this:</p> <p><a href="http://lh3.ggpht.com/_BIamsXoZuOw/SsubHqF5iGI/AAAAAAAAAGY/qqTewaQKIHE/s1600-h/mouseoverbutton2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="mouseover button" border="0" alt="mouseover button" src="http://lh3.ggpht.com/_BIamsXoZuOw/SsubH19Y4cI/AAAAAAAAAGc/u-c8vfymGrc/mouseoverbutton_thumb.png?imgmax=800" width="45" height="45" /></a> </p> <h2>Add the MouseOver Transitions</h2> <p>We want the changes between the MouseOver and Normal visual states to be animated, we achieve this using Transitions.</p> <p>Click the ‘Add Transition’ button next to the Normal state and select <a href="http://lh5.ggpht.com/_BIamsXoZuOw/SsubIVVo_mI/AAAAAAAAAGg/jRfa3SS-xbM/s1600-h/NormalMouseOver3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Normal-MouseOver" border="0" alt="Normal-MouseOver" src="http://lh6.ggpht.com/_BIamsXoZuOw/SsubIjg4G3I/AAAAAAAAAGk/CBUgKC5XxLk/NormalMouseOver_thumb1.png?imgmax=800" width="131" height="22" /></a>  to add the transition.</p> <p>Then enter 0.5 for the ‘Transition Duration’.</p> <p> <a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubJLFE2MI/AAAAAAAAAGo/Ey3mxZuZxAc/s1600-h/transitionduration2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="transition duration" border="0" alt="transition duration" src="http://lh5.ggpht.com/_BIamsXoZuOw/SsubJTKomGI/AAAAAAAAAGs/hsXeQ0_lIMQ/transitionduration_thumb.png?imgmax=800" width="350" height="46" /></a> </p> <p>Click the ‘Add Transition’ button next to the MouseOver state and select <a href="http://lh3.ggpht.com/_BIamsXoZuOw/SsubJ55stgI/AAAAAAAAAGw/H-YXfWVPVfA/s1600-h/mouseovernormal2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="mouseover-normal" border="0" alt="mouseover-normal" src="http://lh6.ggpht.com/_BIamsXoZuOw/SsubKKSCtmI/AAAAAAAAAG0/AfCQtTF3RiM/mouseovernormal_thumb.png?imgmax=800" width="118" height="18" /></a>   to add another transition.</p> <p>Enter 0.5 again for the ‘Transition Duration’.</p> <h2>Add the Pressed State</h2> <p>On the States panel, select the Pressed state.</p> <p>On the ‘Objects and Timeline’ panel, select the grid named ‘shine_grid’.</p> <p>Set the grid’s Opacity property to 70%.</p> <p>Select the ellipse named ‘lower_highlight’ and set its Visibility property to Collapsed.</p> <p>Select the ellipse named ‘upper_highlight’ and set its Opacity property to 60%.</p> <p>Select the ellipse named ‘darkener’ and set its Opacity to 50%.</p> <p>Select the ellipse named ‘outer_glow’ and set its Opacity to 100%.</p> <p>Your pressed button should now look like this:</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubKuxKZzI/AAAAAAAAAG4/T2LlTP_2oyQ/s1600-h/pressedbuttonsl2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="pressed button-sl" border="0" alt="pressed button-sl" src="http://lh3.ggpht.com/_BIamsXoZuOw/SsubKyZIysI/AAAAAAAAAG8/114cqh-wtv8/pressedbuttonsl_thumb.png?imgmax=800" width="46" height="45" /></a> </p> <h2>Add the Disabled State</h2> <p>On the States panel, select the Disabled state.</p> <p>On the ‘Objects and Timeline’ panel, select the grid named ‘main_grid’. On the Properties panel set the grid’s Opacity to 50%.</p> <p>Select the ellipse named ‘inner_glow’ and set its Visibility property to Collapsed. Do the same for the ellipse named ‘upper_highlight’.</p> <p>Select the ellipse named ‘lower_highlight’. Under the Brushes category of the Properties panel, select the Stroke brush.</p> <p>The yellow box around the brush editor indicates that this property is bound with a TemplateBinding. Click the ‘Advanced property options’ button next to the Stroke brush and select ‘Convert to Local Value’. The ‘solid color brush’ editor should now be selected. In the ‘Hex value’ box enter ‘White’ and hit return.</p> <p>Select the ellipse named ‘background’. Click the ‘Advanced property options’ button next to the Fill brush. Select ‘Convert to Local Value’. In the ‘Hex value’ box enter ‘#7F000000’ and hit return.</p> <p>Select the Stroke brush and the ‘Solid color brush’ editor. Set the colour to black.</p> <p>Your disabled button should now look like this:</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SsubLQGHiRI/AAAAAAAAAHA/nfXcOoaqjGQ/s1600-h/disabledbutton2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="disabled button" border="0" alt="disabled button" src="http://lh6.ggpht.com/_BIamsXoZuOw/SsubLhvUKcI/AAAAAAAAAHE/xkoOjZdRH6c/disabledbutton_thumb.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Extract the Template</h2> <p>The template is now complete!</p> <p>The final step is to move the template into a separate XAML file.</p> <p>Select the resources tab and click the ‘Create new resource dictionary’ button.</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/SsubL-ceUNI/AAAAAAAAAHI/tPZbS79emyU/s1600-h/resourcestabsl2.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="resources tab-sl" border="0" alt="resources tab-sl" src="http://lh3.ggpht.com/_BIamsXoZuOw/SsubMR3SqzI/AAAAAAAAAHM/GOZxtWWbmBs/resourcestabsl_thumb.png?imgmax=800" width="350" height="138" /></a> </p> <p>The ‘New Item’ dialog is displayed. Name the new file ‘ShinyRoundButton.xaml’ and click the OK button.</p> <p>Click the triangle to the left of the UserControl element and ‘ShinyRoundButtonTemplate’ should be displayed.</p> <p>Click on‘ShinyRoundButtonTemplate’ and drag it onto ‘ShinyRoundButton.xaml’ to move the template into the resource dictionary.</p> <h2>Run the Project</h2> <p>We’re all done!</p> <p>Hit the F5 button to run the project and test the shiny button in your web browser. </p> <h2>Final Thoughts-Customising the colours</h2> <p>My goal for this series of posts was to create a template that could be applied to a standard button control, defined entirely in XAML without requiring any code behind.</p> <p>I also wanted to allow simple customisation of the colours, which is achieved using TemplateBindings on the Background and Foreground properties of the Button class.</p> <p>The template uses alpha blending with white and black ellipses to lighten and darken the background colour. Using alpha blending like this reduces the saturation of colours, moving everything towards shades of black, white and grey. This is noticeable in the MouseOver state; ideally we want a brighter blue, not a whiter blue.</p> <p>We could set specific colour values for the MouseOver state, but this would mean foregoing the ability to customise the colours using the Foreground and Background properties.</p> <p>A more satisfactory result might be achieved using a ShaderEffect to lighten the colour, or possibly a Binding with a value converter.</p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-68414519071814080012009-09-20T20:35:00.000+01:002009-10-06T20:35:46.401+01:00Step-by-step Shiny Button Template with Expression Blend 3 – Part 2<h2>Introduction</h2> <p>This is the second of three posts showing how to use <a href="http://www.microsoft.com/expression/">Expression Blend 3</a> to create a shiny button template for WPF and <a href="http://silverlight.net/">Silverlight</a>.</p> <p><a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">Part 1 Creating the static template (WPF and Silverlight)</a></p> <p>Part 2 Adding transitions using triggers (WPF only)</p> <p><a href="http://codeflow49.blogspot.com/2009/10/step-by-step-shiny-button-template-with.html">Part 3 Adding transitions with the Visual State Manager (Silverlight and WPF)</a></p> <p>In part 1 we created a static template that was applied to the button shown below:</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/SrOT_QZVs4I/AAAAAAAAAEo/1IiXwv0LZTw/s1600-h/finalstaticbutton3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="final static button" border="0" alt="final static button" src="http://lh4.ggpht.com/_BIamsXoZuOw/SrOT_9IxKDI/AAAAAAAAAEs/Sn-psIYA61E/finalstaticbutton_thumb1.png?imgmax=800" width="40" height="40" /></a> </p> <p>In this part we’ll be creating different appearances for various button states, and animating some of the transitions between states.</p> <a name='more'></a> <p>If you haven’t worked through <a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">part 1</a>, you can download the WPF version of the static template <a href="http://sites.google.com/site/codeflow49/files/static_shiny_button_wpf.zip">here</a> and use it as the starting point for what follows.</p> <p>You can download <a href="http://sites.google.com/site/codeflow49/files/shiny_button_wpf.zip">the finished project for part two</a>, or just <a href="http://sites.google.com/site/codeflow49/files/ShinyRoundButtonWPF.xaml">the XAML file containing the finished template</a>.</p> <p></p> <h3>Part 2 Adding transitions using triggers (WPF only)</h3> <p>Controls like Button change their visual appearance to indicate different states. In this post, we’ll give our button template different looks when the button is disabled, when it is pressed and when the mouse is over the button.</p> <h2>Triggers versus The Visual State Manager</h2> <p>The traditional way to implement control states and transitions in WPF 3.0/3.5 is to use triggers.</p> <p>For Silverlight, Microsoft created the Visual State Manager (VSM)with the goal of making it easier to build interactive control templates.</p> <p>The Visual State Manager will be included in WPF 4 and is currently available for WPF 3.5 through the <a href="http://wpf.codeplex.com/">WPF Toolkit</a>. You can use Expression Blend 3 to add VSM states and transitions to a WPF project and Blend will automatically update your project to include a reference to WPFToolkit.dll.</p> <p>In this post I’ll cover using triggers to change the buttons appearance for different states. </p> <p>In part 3, I’ll show how to create the same effects using states and transitions with the Visual State Manager.</p> <h2>About Triggers</h2> <p>Like other WPF controls, Button indicates its states and transitions with properties (such as IsEnabled and IsPressed) and events (such as MouseEnter and MouseLeave).</p> <p>In this post, we’ll be using two types of triggers:</p> <p>A regular Trigger is activated by a specific property value and contains Setters that instantly apply values to other properties.</p> <p>An EventTrigger is activated by a RoutedEvent and has a collection of actions (such as starting an animation) that are performed when the trigger is activated.</p> <p>It’s something of an aesthetic choice whether to animate a particular transition. Instant changes create a more responsive feeling and seem appropriate for indicating that a button has been clicked. Animated transitions can be smoother, and create more subtle effects.</p> <h2>Get Started</h2> <p>Fire up Blend and open the project from <a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with.html">part one</a>.</p> <p>Right-click on the button, and select ‘Edit Template/Edit Current’. The ‘Objects and Timeline’ panel switches to show the content of the template.</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/SrOUARCgIpI/AAAAAAAAAEw/U_7RlNPzZSk/s1600-h/ObjectsandTimelineeditingtemplate4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Objects and Timeline editing template" border="0" alt="Objects and Timeline editing template" src="http://lh6.ggpht.com/_BIamsXoZuOw/SrOUAwIjraI/AAAAAAAAAE0/3OHgo9pPWSE/ObjectsandTimelineeditingtemplate_th.png?imgmax=800" width="275" height="337" /></a> </p> <h2>Add the Disabled state</h2> <p>Select the Triggers panel and click the ‘+Property’ button to add a property trigger.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SrOUBmi-dOI/AAAAAAAAAE4/TvOC_OcHB7U/s1600-h/triggers%20panel%5B14%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="triggers panel" border="0" alt="triggers panel" src="http://lh6.ggpht.com/_BIamsXoZuOw/SrOUCEgeOPI/AAAAAAAAAE8/MJSLv9UvKFs/triggers%20panel_thumb%5B8%5D.png?imgmax=800" width="350" height="364" /></a> </p> <p></p> <p>The Trigger is initially created to be activated by the IsCancel property. Use the drop down box to change the property from IsCancel to IsEnabled.</p> <p>The artboard is now surrounded by a red border to show that it is in recording mode.</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/SrOUCu7gN9I/AAAAAAAAAFA/W061U_ThnDI/s1600-h/trigger%20recording%20on%5B4%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="trigger recording on" border="0" alt="trigger recording on" src="http://lh3.ggpht.com/_BIamsXoZuOw/SrOUC410U-I/AAAAAAAAAFE/q-yomXdF6fg/trigger%20recording%20on_thumb%5B2%5D.png?imgmax=800" width="252" height="55" /></a> </p> <p>In this mode, any properties we change will be recorded in the Trigger’s Setters collection, to be applied when the Trigger is activated.</p> <p>Use the ‘Objects and Timeline’ panel to select the grid named ‘main_grid’. On the Properties panel set the grid’s Opacity to 50%.</p> <p>Select the ellipse named ‘inner_glow’ and set its Visibility property to Hidden. Do the same for the ellipse named ‘upper_highlight’.</p> <p>Select the ellipse named ‘lower_highlight’. Under the Brushes category of the Properties panel, select the Stroke brush.</p> <p>The yellow box around the brush editor indicates that this property is bound with a TemplateBinding. Click the ‘Advanced property options’ button next to the Stroke brush and select ‘Convert to Local Value’. The ‘solid color brush’ editor should now be selected. In the ‘Hex value’ box enter ‘White’ and hit return.</p> <p>Select the ellipse named ‘background’. Click the ‘Advanced property options’ button next to the Fill brush. Select ‘Convert to Local Value’. In the ‘Hex value’ box enter ‘#7F000000’ and hit return.</p> <p>Select the Stroke brush and the ‘Solid color brush’ editor. Set the colour to black.</p> <p>Your disabled button should now look like this:</p> <p><a href="http://lh3.ggpht.com/_BIamsXoZuOw/SrOUDSciyjI/AAAAAAAAAFI/glSIK3GcVxQ/s1600-h/disabled%20button%5B8%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="disabled button" border="0" alt="disabled button" src="http://lh3.ggpht.com/_BIamsXoZuOw/SrOUDjhBtwI/AAAAAAAAAFM/2_e02uE9H5k/disabled%20button_thumb%5B6%5D.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Add the Pressed state</h2> <p>On the Triggers panel and click the ‘+Property’ button to add another property trigger.</p> <p>Use the drop-down box below the ‘Activated when’ heading to change the Trigger’s property to ‘IsPressed’.</p> <p>Click the value drop-down box, type ‘True’ and press enter.</p> <p>Select the ellipse named ‘darkener’ and set its Opacity to 50%.</p> <p>Select the ellipse named ‘lower_highlight’ and set its Visibility to Hidden.</p> <p>Select the grid named ‘shine_grid’ and set its Opacity to 70%.</p> <p>Select the ellipse named ‘upper_highlight’ and set its Opacity to 60%.</p> <p>Select the ellipse named ‘inner_glow’ and select its OpacityMask brush. Click the ‘Show advanced properties’ expander below the brush editor.</p> <p>Set the brush’s RadiusX property to 0.5 and its Opacity to 80%.</p> <p>Your pressed button should now look like this:</p> <p><a href="http://lh3.ggpht.com/_BIamsXoZuOw/SrOUEJjHTeI/AAAAAAAAAFQ/lk0gbeARXIk/s1600-h/pressed%20button%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="pressed button" border="0" alt="pressed button" src="http://lh3.ggpht.com/_BIamsXoZuOw/SrOUErAFLFI/AAAAAAAAAFU/JTS48X1HU1o/pressed%20button_thumb%5B1%5D.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Add the MouseEnter animation</h2> <p>On the Triggers panel and click the ‘+Event’ button to add an EventTrigger.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SrZe4P3JVsI/AAAAAAAAAFY/ZMVz44ODAoA/s1600-h/triggerspanelevent14.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="triggers panel event" border="0" alt="triggers panel event" src="http://lh6.ggpht.com/_BIamsXoZuOw/SrZe4l3ZLQI/AAAAAAAAAFc/QWCenUJwBLk/triggerspanelevent_thumb10.png?imgmax=800" width="350" height="198" /></a> </p> <p>The EventTrigger is created for the Loaded event. Select the new trigger and use the drop-down box to select the MouseEnter event instead.</p> <p>Click the Trigger’s ‘Add new action’ button. A message box is displayed to inform you that a new Storyboard will be created. Click OK to close the message box.</p> <p>The ‘Objects and Timeline’ panel switches to display the new Storyboard, which is given the default name ‘OnMouseEnter1’.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SrZe5EpVtJI/AAAAAAAAAFg/xBBCjwZw6AI/s1600-h/timeline4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="timeline" border="0" alt="timeline" src="http://lh4.ggpht.com/_BIamsXoZuOw/SrZe5qgDHEI/AAAAAAAAAFk/1hQs3HX7NcE/timeline_thumb2.png?imgmax=800" width="350" height="194" /></a> </p> <p>Drag the yellow playhead to 0.5 seconds.</p> <p>Select the ellipse named ‘lightener’ and set its Opacity to 20%.</p> <p>Select the ellipse named ‘outer_glow’ and set its Opacity to 100%.</p> <h2>Add the MouseLeave animation</h2> <p>On the Triggers panel and click the ‘+Event’ button to add another EventTrigger. Use the drop-down box to select the MouseLeave event.</p> <p></p> <p></p> <p>Click the ‘Add new action’ button for the new event. Blend will automatically add an action to run the previous Storyboard, ‘OnMouseEnter1’.</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/SrZe6OaK0kI/AAAAAAAAAFo/yojygJ7RefU/s1600-h/newstoryboard4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="new storyboard" border="0" alt="new storyboard" src="http://lh6.ggpht.com/_BIamsXoZuOw/SrZe6j11gMI/AAAAAAAAAFs/Jg3RwflK6cw/newstoryboard_thumb2.png?imgmax=800" width="270" height="262" /></a> </p> <p>Click the drop-down list and select ‘New Storyboard’. The ‘Create Storyboard Resource’ dialog is displayed with the Storyboard’s default name set to ‘OnMouseLeave1’. Click the OK button to accept and close the dialog.</p> <p>The ‘Objects and Timeline’ panel switches to display the new Storyboard.</p> <p>Drag the playhead to 0.5 seconds.</p> <p>Select the ellipse named ‘lightener’. On the Properties panel, click the ‘Advanced property options’ button next to the Opacity property. Select ‘Record Current Value’.</p> <p>Do the same for the ellipse named ‘outer_glow’.</p> <h2>Extract the Template</h2> <p>The template is now complete!</p> <p>The final step is to move the template into a separate XAML file.</p> <p>Select the resources tab and click the ‘Create new resource dictionary’ button.</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/SrZe7pAZ_4I/AAAAAAAAAFw/HKhzTPXVykI/s1600-h/resourcestab4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="resources tab" border="0" alt="resources tab" src="http://lh4.ggpht.com/_BIamsXoZuOw/SrZe8PR1l-I/AAAAAAAAAF0/IihZQPc4dxY/resourcestab_thumb2.png?imgmax=800" width="350" height="163" /></a> </p> <p>The ‘New Item’ dialog is displayed. Name the new file ‘ShinyRoundButton.xaml’ and click the OK button.</p> <p>Click the triangle to the left of the Window element and ‘ShinyRoundButtonTemplate’ should be displayed.</p> <p>Click on‘ShinyRoundButtonTemplate’ and drag it onto ‘ShinyRoundButton.xaml’ to move the template into the resource dictionary.</p> <h2>Run the project</h2> <p>That’s it!</p> <p>Hit the F5 button to run your WPF project and observe how the button responds to mouse-over’s and clicks.</p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0tag:blogger.com,1999:blog-7169399530735833437.post-78433433146346844632009-09-13T20:37:00.000+01:002009-10-06T20:37:37.283+01:00Step-by-step Shiny Button Template with Expression Blend 3 – Part 1<h2>Introduction</h2> <p>In this step-by-step walkthrough I’ll be showing you how to use <a href="http://www.microsoft.com/expression/">Expression Blend 3</a> to create a template for shiny round buttons somewhat like the play button in Windows Media Player or the back and forward buttons in Internet Explorer.</p> <p>The tutorial is split over three posts:</p> <p>Part 1 Creating the static template (WPF and Silverlight)</p> <p><a href="http://codeflow49.blogspot.com/2009/09/step-by-step-shiny-button-template-with_20.html">Part 2 Adding transitions using triggers (WPF only)</a></p> <p><a href="http://codeflow49.blogspot.com/2009/10/step-by-step-shiny-button-template-with.html">Part 3 Adding transitions with the Visual State Manager (Silverlight and WPF)</a></p> <p></p> <p>The resulting template can be applied to standard WPF or Silverlight Button controls and styled with different colours to create buttons like these:</p> <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="example buttons" border="0" alt="example buttons" src="http://lh4.ggpht.com/_BIamsXoZuOw/Sqvg4cUX74I/AAAAAAAAAEU/sL2R44SyZ0k/example%20buttons_thumb%5B2%5D.png?imgmax=800" width="245" height="42" /></p> <p> </p> <a name='more'></a> <h3>Part 1 Creating the static template (WPF and Silverlight)</h3> <p>In this part we’ll create a static version of the button template which will be the same for both WPF and Silverlight.</p> <h2>Create the project</h2> <p>Start Blend, and select ‘New Project…’.</p> <p>On the New Project dialog select either ‘Silverlight 3 Application’ or ‘WPF Application’. Give the project a name and click the OK button to create the project.</p> <h2>Add a button</h2> <p>Blend will now present you with a XAML file showing a blank white rectangle. </p> <table border="0" cellspacing="0" cellpadding="2" width="400"><tbody> <tr> <td valign="top" width="192"> <p>Double click the button tool :</p> </td> <td valign="top" width="208"><a href="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9Orq42II/AAAAAAAAAEY/-YWmlY9OYQ8/s1600-h/Button%20Tool.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="Button Tool" border="0" alt="Button Tool" src="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9O6NDWPI/AAAAAAAAAEc/k1vb_lk-8uc/Button%20Tool_thumb.png?imgmax=800" width="35" height="36" /></a></td> </tr> </tbody></table> <p>This will insert a button in the top-left of the layout.</p> <h2></h2> <h2>Set the button properties</h2> <p>With the new button selected, use the properties panel to set the following properties:</p> <p>Set the Height and Width to 40.</p> <p>Set the Content to 4 (Yes, just the number 4).</p> <p>Set the font family to Webdings. This turns the number 4 into a ‘play’ triangle.</p> <p>Set the font size to 22 pt.</p> <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="brush properties" border="0" alt="brush properties" src="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9P9kHgtI/AAAAAAAAACo/vpKRKtZjVLw/brushproperties10.png?imgmax=800" width="400" height="420" /> Under the Brushes category, select the Background brush and select the ‘Solid color brush’ editor.</p> <p>Click in the ‘Hex value’ box and type ‘DarkBlue’. Press enter and this should change into the hex value.</p> <p>Similarly, set the ‘BorderBrush’ property to ‘Cyan’ and the Foreground brush to ‘White’, making sure to select the ‘Solid color brush’ editor each time.</p> <p>Your button should now look something like this for WPF:</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9QZEkR1I/AAAAAAAAACs/jOr1E4kUgf4/s1600-h/buttonwithpropertieswpf3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="button with properties wpf" border="0" alt="button with properties wpf" src="http://lh3.ggpht.com/_BIamsXoZuOw/Sqp9QzfhMcI/AAAAAAAAACw/FpXjpqiyNX0/buttonwithpropertieswpf_thumb1.png?imgmax=800" width="41" height="42" /></a> </p> <p>or this for Silverlight:</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9ROPmguI/AAAAAAAAAC0/08Ebl0RmhAc/s1600-h/buttonwithpropertiessl3.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="button with properties sl" border="0" alt="button with properties sl" src="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9RUxtlJI/AAAAAAAAAC4/nUkilwpVpcc/buttonwithpropertiessl_thumb1.png?imgmax=800" width="42" height="42" /></a> </p> <p>The difference at this stage is down to the default button templates used by Silverlight and WPF.</p> <h2>Create the Template</h2> <p>Right click the button and select ‘Edit Template/Create Empty…’.</p> <p>This brings up the ‘Create ControlTemplate Resource’ dialog.</p> <p>Name the new template ShinyRoundButtonTemplate and click OK to close the dialog.</p> <h2>Add the background</h2> <p>The ‘Objects and Timeline’ panel switches to show the content of the template being edited – so far that consists of nothing but a Grid.</p> <p>Set the Name property of the Grid to ‘main_grid’.</p> <p>We’re going to add an ellipse, so if the ellipse tool isn’t displayed on the toolbar, click and hold the Rectangle or Line tool to display and select Ellipse:</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9RyhnFXI/AAAAAAAAAC8/YxsIeBRLvW4/s1600-h/select%20ellipse%5B4%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="select ellipse" border="0" alt="select ellipse" src="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9SGHVSCI/AAAAAAAAADA/BRnoUgL_YDc/select%20ellipse_thumb%5B2%5D.png?imgmax=800" width="250" height="95" /></a> </p> <p>Now double click the Ellipse tool to insert an ellipse that will occupy the whole of the template’s ‘main_grid’.</p> <p>Set the Name of the ellipse to ‘background’.</p> <p>Click the ‘Advance property options’ button adjacent to the ellipse’s Fill brush.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9SnGbJHI/AAAAAAAAADE/ap8iOL2sFTk/s1600-h/advanced%20property%20options%5B4%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="advanced property options" border="0" alt="advanced property options" src="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9Swn2qmI/AAAAAAAAADI/mGrrfRkOnz8/advanced%20property%20options_thumb%5B2%5D.png?imgmax=800" width="350" height="85" /></a> </p> <p>On the popup menu, select ‘Template Binding/Background’.</p> <p>Click the ‘Advance property options’ button adjacent to the ellipse’s Stroke brush. Select ‘Reset’ to set the Stroke property to ‘No brush’.</p> <h2>Add the Outer Glow</h2> <p>Double-click the ellipse tool again to add another ellipse.</p> <p>Give this ellipse the name ‘outer_glow’.</p> <p>Use the advance options again to set the Fill brush to ‘Template Binding/BorderBrush’ and set the Stroke property to ‘No brush’.</p> <p>This ellipse will be used to provide an outer glow for the button.</p> <p>Under the Appearance section of the Properties panel, locate the Effect property and click the New button. This brings up the Select Object dialog. Select BlurEffect and close the dialog by clicking OK.</p> <p>Set the Radius of the BlurEffect to 10.</p> <p>The ‘outer_glow’ ellipse should be behind the background, so that only the blur around the edge is visible. Right click on the ellipse and select ‘Order/Send to Back’.</p> <p>The outer glow will only be displayed when the mouse is over the button, for the default button state, we want to hide this ellipse.</p> <p>Set the Opacity property of the ‘outer_glow’ ellipse to 0%.</p> <h2>Add Lightener and Darkener</h2> <p>When the state of the button changes, the template will lighten or darken the background colour. We’ll achieve this by overlaying a couple of partially opaque ellipses. In the button’s default state, these will both be hidden.</p> <p>Double-click the ellipse tool again to add another ellipse.</p> <p>Give this ellipse the name ‘lightener’. </p> <p>Set its Fill brush to White, reset its Stroke brush, and set its Opacity to 0%.</p> <p>In the same way, add another ellipse named ‘darkener’.</p> <p>Set its Fill brush to Black, reset its Stroke brush, and set its Opacity to 0%.</p> <h2>Add the Inner Glow</h2> <p>Double-click the ellipse tool again to add another ellipse. Name this one ‘inner_glow’.</p> <p>Set the ellipse’s Margin to 1,1,1,1.</p> <p>Use the advance options to set the Fill brush to ‘Template Binding/BorderBrush’ and reset the Stroke brush.</p> <p>In the Brushes category, select ‘OpacityMask’.</p> <p>Select ‘Gradient Brush’ and then ‘Radial Gradient’.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9T5QCyJI/AAAAAAAAADM/3WUB5QFyk4Y/s1600-h/radial%20gradient%5B24%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="radial gradient" border="0" alt="radial gradient" src="http://lh3.ggpht.com/_BIamsXoZuOw/Sqp9UuqmqYI/AAAAAAAAADQ/yDg82XUQ1po/radial%20gradient_thumb%5B16%5D.png?imgmax=800" width="350" height="382" /></a> </p> <p>Select the right hand gradient stop and set its alpha value to 0%</p> <p>Click the ‘Show advance properties’ expander below the brush editor.</p> <p>Set the following properties for the brush: </p> <p>GradientOrigin = 0.5, 1 </p> <p>Center = 0.5, 1 </p> <p>RadiusX = 0.8 </p> <p>At this point, the button should look like this:</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/Sqp9U8RjIqI/AAAAAAAAADU/44BKDGQd7FU/s1600-h/button%20with%20inner%20glow%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="button with inner glow" border="0" alt="button with inner glow" src="http://lh6.ggpht.com/_BIamsXoZuOw/Sqp9VY2OVxI/AAAAAAAAADY/ET5J_0tlK1g/button%20with%20inner%20glow_thumb%5B1%5D.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Add the highlights</h2> <p>Double-click the ellipse tool again to add another ellipse.</p> <p>Give this ellipse the name ‘lower_highlight’. </p> <p>Reset the ellipse’s Fill brush to ‘No brush’.</p> <p>Use the advance options again to set the Stroke brush to ‘Template Binding/BorderBrush’.</p> <p>Select ‘OpacityMask’ and then select ‘Gradient Brush’.</p> <p>Drag the left hand gradient stop to around the 55% position and set its alpha value to 0%.</p> <p>In the Layout category, set the ellipse’s Margin to 1,1,1,1.</p> <p>Double-click the ellipse tool again to add another ellipse.</p> <p>Give this ellipse the name ‘upper_highlight’. </p> <p>Reset the ellipse’s Fill brush to ‘No brush’.</p> <p>Select the ‘Stroke’ brush and then select ‘Gradient Brush’.</p> <p>Set the left hand gradient stop to ‘White’.</p> <p>Drag the right hand gradient stop to around the 45% position and set it to ‘#00000000’ in the Hex value box.</p> <p>Set the ellipse’s Margin to 1,1,1,1.</p> <p>The button should now look like this:</p> <p><a href="http://lh3.ggpht.com/_BIamsXoZuOw/Sqp9VhqGRII/AAAAAAAAADc/8kw7s8myfiE/s1600-h/with%20highlights%5B7%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="with highlights" border="0" alt="with highlights" src="http://lh3.ggpht.com/_BIamsXoZuOw/Sqp9WPVI9YI/AAAAAAAAADg/tdgC1028TDE/with%20highlights_thumb%5B5%5D.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Add the shine</h2> <p>Double-click the Grid tool to add a new grid. Name this grid ‘shine_grid’.</p> <p>Set the new grid’s left and right Margin to 2, and top and bottom Margin to 1.</p> <p>With ‘shine_grid’ selected, expand the advanced properties of the Layout section.</p> <p>Click the button marked ‘…’ next to the RowDefinitions property. This brings up the ‘RowDefinition Collection Editor’ dialog. Click the ‘Add another item’ button twice to add two rows to the grid. Close the dialog by clicking the OK button.</p> <p>With ‘shine_grid’ still selected, double click the ellipse tool to add an ellipse as a child of ‘shine_grid’.</p> <p>Right click the new ellipse and select ‘Path/Convert to Path’.  Name the new path ‘shine’.</p> <p>This part is a bit fiddly, so it may be helpful to increase the zoom on the artboard. Try about 400%.</p> <table border="0" cellspacing="0" cellpadding="2" width="400"><tbody> <tr> <td valign="top" width="200">Click the ‘Direct Selection’ tool:</td> <td valign="top" width="200"><a href="http://lh6.ggpht.com/_BIamsXoZuOw/Sqp9WToSreI/AAAAAAAAADk/w1dpTuq4GC8/s1600-h/Direct%20Selection%20Tool%5B5%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; margin-left: 0px; border-left-width: 0px; margin-right: 0px" title="Direct Selection Tool" border="0" alt="Direct Selection Tool" src="http://lh3.ggpht.com/_BIamsXoZuOw/Sqp9W2Fl67I/AAAAAAAAADo/k6xpPAVemSg/Direct%20Selection%20Tool_thumb%5B3%5D.png?imgmax=800" width="35" height="35" /></a></td> </tr> </tbody></table> <p>Four points on the path are now displayed. Click the bottom point to select it.</p> <p>Use the up arrow key to nudge this point up until it is in line with the left and right points. </p> <p>The result should look like this:</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/Sqp9XO074wI/AAAAAAAAADs/rjBZOAGnUag/s1600-h/adding%20shine%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="adding shine" border="0" alt="adding shine" src="http://lh4.ggpht.com/_BIamsXoZuOw/Sqp9XyIC73I/AAAAAAAAADw/xed-WvnaLPo/adding%20shine_thumb%5B1%5D.png?imgmax=800" width="156" height="158" /></a> </p> <p>The Nudge operation will adjust the Margin property, so use the ‘Advance property options’ to reset the path’s Margin.</p> <p>Set the Stroke property to ‘No Brush’.</p> <p>Select the Fill brush, select ‘Gradient brush’ and ‘Radial gradient’.</p> <p>Select the left hand gradient stop and set its hex value to #27FFFFFF.</p> <p>Add a new gradient stop at around the 42% position and set its hex value to #2DFFFFFF.</p> <p>Select the right hand gradient stop and set its hex value to #7CFFFFFF.</p> <p>Click the ‘Show advanced property’ expander below the brush editor.</p> <p>On the Translate tab of the brush’s RelativeTransform, set the Y value to 0.5.</p> <p>On the Scale tab, set the Y value to 2.</p> <p><a href="http://lh6.ggpht.com/_BIamsXoZuOw/SqqwIA9XJII/AAAAAAAAAD0/d3ruOJZNEK0/s1600-h/brush%20transform%5B4%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="brush transform" border="0" alt="brush transform" src="http://lh5.ggpht.com/_BIamsXoZuOw/SqqwInZQsTI/AAAAAAAAAD4/AghjXn9g9Uc/brush%20transform_thumb%5B2%5D.png?imgmax=800" width="350" height="119" /></a> </p> <p>The button should now look like this:</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/SqqwJKX-UfI/AAAAAAAAAD8/ktpbzElDJEg/s1600-h/with%20shine%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="with shine" border="0" alt="with shine" src="http://lh3.ggpht.com/_BIamsXoZuOw/SqqwJlYa_wI/AAAAAAAAAEA/y_tDNK6GWzY/with%20shine_thumb%5B1%5D.png?imgmax=800" width="158" height="158" /></a> </p> <h2>Add the ContentPresenter</h2> <p>Finally, we want the button to display its content, so we need a ContentPresenter.</p> <p>Select ‘main_grid’. We want the ContentPresenter to be added as a child of this grid.</p> <p>On the Assets panel, select Controls and double-click on ContentPresenter.</p> <p><a href="http://lh4.ggpht.com/_BIamsXoZuOw/SqqwKB4RNcI/AAAAAAAAAEE/eqopot4v4Sk/s1600-h/assets%20panel%5B4%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="assets panel" border="0" alt="assets panel" src="http://lh5.ggpht.com/_BIamsXoZuOw/SqqwKXHZZlI/AAAAAAAAAEI/yvQJi53-ob8/assets%20panel_thumb%5B2%5D.png?imgmax=800" width="350" height="368" /></a> </p> <p>You should now see the triangle we originally added as our button’s content, but its not centred in the button.</p> <p>Find the Layout category in the Properties panel.</p> <p>For the HorizontalAlignment property, click the ‘Advanced property options’ and select ‘TemplateBinding/HorizontalContentAlignment’.</p> <p>In the same way, bind the VerticalAlignment property to ‘TemplateBinding/VerticalContentAlignment’.</p> <p>Your button should now look like this:</p> <p><a href="http://lh5.ggpht.com/_BIamsXoZuOw/SqqwK8fDEJI/AAAAAAAAAEM/OKQQh6gGO5A/s1600-h/final%20static%20button%5B3%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="final static button" border="0" alt="final static button" src="http://lh5.ggpht.com/_BIamsXoZuOw/SqqwLOPC4bI/AAAAAAAAAEQ/0nTRWmAxa1I/final%20static%20button_thumb%5B1%5D.png?imgmax=800" width="40" height="40" /></a> </p> <h2>Wrapping up</h2> <p>That’s it for the static parts of the template.</p> <p>In future posts, I’ll walkthrough adding states and transitions to bring the button to life.</p> John-Martin Malonehttp://www.blogger.com/profile/17394913464387980467noreply@blogger.com0