Monday, November 24, 2008

Creating a Chord Factory in Silverlight 2

Years ago I created a Windows Forms application that displayed piano chords and musical scales graphically as a sort of pet project/learning exercise. It was written in VB6.0 (I said it was years ago) and contained an image of a piano keyboard and a musical stave. Selecting a root note, either by clicking a key or using a ComboBox, and picking a chord and/or scale, it would show the notes in the chord and/or scale on the keyboard and on the stave. It is still available for download here and will install and run under Vista - although as you can see from the image it fails to install the musical font used to display the clef symbols.

ChordFactory

The Openfeature Chord Factory main screen. That should be a G rather than an O.

As well as showing chords it also harnessed the power of the Windows Multi Media API to play them using the MIDI synthesizer of the PC sound card or to an attached MIDI device. Over time I added further enhancements such as chord-inversions, chord progressions and a help file. I was and still am quite proud of it.

I recently decided to revisit Chord Factory after all these years and have a look at re-implementing it in Silverlight 2 - using XAML to achieve better graphical presentation of the piano keyboard and musical stave and data binding to better store and represent the musical data for the chord shapes and scales. I suspected that the lack of access to the Windows API would make it necessary to find another way of playing the chords, but thought the the Silverlight MediaElement might offer a way around this limitation.

It's not quite finished yet, but I thought it might make the subject of a few posts on how I did it and I'm starting with this one. I have done quite a bit on it so far and the work-in-progress is already up on the web at my Openfeature web site here.

More to come...

20 Tips for Producing Releasable Controls

I thought I would publish the slides from the presentation I put together for last year's Developer Day, on producing releasable controls. It covered attributing and enhancing custom and user controls in order to get them to a level good enough for public or commercial release.

The slide deck is here, but I thought I might also elaborate a bit with a write-up of the hand-written notes I had for presenting.

The idea was to show how to bridge the gap between functional controls for WinForms, Web, WPF etc., that might be good enough for internal project use, and releasable ones that better support deployment and use in the Visual Studio toolbox with all the design-time support that makes a control easier and nicer to use. Simple attributes, extensions and practices that enhance a control to make it look and behave better when used by other developers.

The 20 tips are:

1. The Description Attribute, 2. The Category Attribute, 3. The Browsable Attribute - Use these simple attributes to decorate a control's properties to affect how (and whether) they appear in the property browser of Visual Studio.

4. The ToolboxBitmap Attribute - Add a 16x16 bitmap to your project and reference it using this attribute to avoid the default cog toolbox image.

5. The DefaultValue Attribute, 6. The ResetXxxx Method, 7. The ShouldSerializeXxxx Method - This is how you enable the Reset option in the context menu for a property in the property browser and govern how that property's state is serialized into the designer code for a control. If you want to provide the ability to reset a property, then you need a default to reset it to and if you have a default property, what is the point in serializing the value of that property for a control instance in a form or page, if the property's value is the same as the default. The DefaultValue attribute allows you to set a default (which must be a literal value) and the two methods allow you to get around the need for the default to be a literal value which is often the case where a property's type is an enumeration or a stored value (often resource strings localisation resources). Having implemented these methods, the designer will magically call them when providing the reset functionality for the property browser and when serializing the state of the control.

8. Extend the DefaultValue Attribute - This is a refinement of the above approach to getting around the literal restriction on using DefaultValue. Here you roll your own version of the attribute that can take arguments to allow resource retrieval for the default value rather than a literal.

9. The DefaultProperty Attribute, 10. The DefaultEvent Attribute - Determine which property is scrolled to and highlighted by default in the property browser and which event stub is generated when the control is double-clicked in the designer.

11. The ToolboxItemFilter Attribute - Used to restrict visibility of a control to particular designers in Visual Studio - if you use the Require value of the ToolboxItemFilterType enumeration then the control will only appear in the toolbox when that designer is open.

12. The Bindable Attribute, 13. Implement INotifyPropertyChanged - These help the IDE with hints for the property browser when displaying bindable properties - marking a property as bindable means that you have undertaken to have implemented property change notification for it and ensures that it is included in the list of default binding properties at the top of the property browser.

14. The setter value comparison pattern - This simple pattern helps avoid unnecessarily exercising setter code and erroneously firing property changed events, by checking that the new value is actually different to the old value.

15. The RefreshProperties Attribute - If a change in one of your properties has an effect on the display of others in the property browser or the control's appearance on the design surface then you can use this attribute to signal to the IDE that the property browser should re-query all the property values of the control and/or repaint the control in the designer.

16. Use Sandcastle - Microsoft now makes available the toolset it uses for generating the MSDN reference and help files from XML documentation comments in code. You can use Sandcastle to produce professional docs from your control's XML comments (which of course you should be providing for the sake of intellisense support and the IDE Object Browser).

17. Setup/Toolbox registration - This has perennially been an area of pain and confusion in the past and continues to be to this day. The links here point to sources of help, but the whole subject is inevitably bound up in permissions and issues with target machines and their configuration.

18. TypeConverter - Where your properties are not simple CLR types and the IDE does not know how to present and manage their values in the property browser you can supply one of the standard set of TypeConverters or indeed your own custom TypeConverter to help. In this example the property is a class instance with its own properties and using the ExpandableObjectConverter allows the IDE to know that it can 'drill-down' into the property to expose the property's own properties as an expanded list. TypeConverters specify to the IDE how to convert from a type to a string and back again so that the IDE knows how to serialise and present property values in the property browser window.

19. TypeEditor - Where a property is not easily entered as a string from the property browser a TypeEditor can be used to provide a UI for setting the property. The IDE already has TypeEditors for types such as Color where it will drop down a selector dialog with tabs for system, web and custom colour selection. You can write your own TypeEditors for custom display and editing of your properties and use the TypeEditor attribute to indicate to the IDE that the property has a special editor to display for setting its value.

20. Smart Tags - Common tasks for a control sited on the designer surface can be accessed via a little right-arrow icon if you supply a list of tasks using the smart tags support available in the Visual Studio IDE. The two books I name-check there Pro .NET 2.0 Windows Forms and Custom Controls by Matthew MacDonald and Windows Forms 2.0 Programming by Chris Sells and Michael Weinhardt contain good walkthroughs of how to set these up and provide the UI for them.

Thursday, September 04, 2008

Organising Silverlight XAML Resources

I recently had to work through a large number of XAML files and rationalise the use of styles in a medium-size Silverlight application.

The original files had been produced with Expression Blend, and although some effort had been put into reusing common features such as fonts and colours, the resulting XAML was a mixture of named styles used as static resources and inline setting of properties. There was also repetition of styles across files within the project both in name and in content.

Styles with the same key within a resource hierarchy will override each other with the definition nearest the element winning out and it is easy, unintentionally, to quickly accumulate styles with the same contents but different keys unless you're careful.

An obvious inclination in this sort of situation is to centralise everything and to eliminate all duplication in order to tidy up things up. Styles and other resources used in more than one page or control can be placed in the App.xaml file of an application and accessed as static resources from XAML across the project. In this way if a change is required to the house style, like changing to a new standard font or colour-scheme, a single change in the central resources and a recompile is all that is required for the changes to apply throughout the entire project. And don't forget that one resource can make use of another; so, for example, a font name can be declared as a named resource and all other style resources can reference it as a static resource:

<Sys:String x:Key="HouseFont">
Verdana
</Sys:String>
<
Sys:String x:Key="BigTextSize">
56
</Sys:String>

<
Style x:Key="BigButtonStyle" TargetType="Button">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource BigTextSize}" />
</
Style>


...


<Button Style="{StaticResource BigButtonStyle}" />



On the whole this works fine, and the really nice thing is that the resource management features in Expression Blend make using and maintaining the resources easy. When creating new styles in the designer you can opt to store them centrally and when editing styles or templates it is easy to apply previously saved resources and avoid adding ad hoc styling.



BlendResources



At the same time, however, it is important to bear in mind the intentions of the designer of the application's visuals - my first, over-rigorous attempts at eliminating duplication of styles where the property values were all the same led to some problems because I didn't realise that two styles with exactly the same contents could still be two different styles. Take this example, where two styles contain the same setters and values:



<Style x:Key="ProductDescriptionTextBlockStyle" TargetType="TextBlock">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource MediumTextSize}" />
<
Setter Property="Foreground" Value="{StaticResource BrightTextColour}" />
<
Setter Property="TextWrapping" Value="NoWrap" />
</
Style>

<
Style x:Key="ThumbnailSubTitleTextBlockStyle" TargetType="TextBlock">
<
Setter Property="FontFamily" Value="{StaticResource HouseFont}" />
<
Setter Property="FontSize" Value="{StaticResource MediumTextSize}" />
<
Setter Property="Foreground" Value="{StaticResource BrightTextColour}" />
<
Setter Property="TextWrapping" Value="NoWrap" />
</
Style>



I first assumed these were obvious candidates for merging and renaming to a single style for use on product descriptions and thumbnail subtitles, but logically they are different, and to replace these two styles with a single generally named one locks the style of two conceptual different areas of the look and feel together artificially and arbitrarily - what if the designer of the UI later decides that thumbnail subtitles should be italicised? Would she expect all product descriptions to appear in italics? Rather obviously not. Clearly if a style is needed in more than one place because common aspects of visual design appear through the pages of an application then it makes sense to store it centrally in the application's resources and reference it everywhere it is needed, but elements that happen to have the same set of style properties but are not related to each other might have their styles stored centrally but they shouldn't have their styles merged arbitrarily.



So whilst it is important to rationalise repetition of genuinely duplicate style definitions, it is also important to realise that coincidence of content is not always equality of identity.



Another lesson I learnt was that over-centralisation could become cumbersome; I began by collecting styles in a grand sweep through the application and depositing them all in the App.xaml file on the general principle that styles stored centrally are available everywhere throughout the application if required. But what if they aren't required everywhere? What if styles are only of relevance to a particular page? As I progressed in my task I realised that general styles with names such as 'TitleTextBlock' occurred in several places with different setter content - moving them to a central location meant the need to rename them with prefixes to differentiate them and keep the compiler from objecting.



Under these circumstances it proved important to establish whether they needed to be held centrally at all - if they were only used in a particular page then it seemed better to leave them there and obviate the need for a prefix. On the other hand if they were used in several places and yet still had a conflicting name then a prefix seemed appropriate but adding a prefix based on the page where it was originally found before moving it into App.xaml led to confusing results - why was a style called 'BuyIt_TitleTextBlock' being used in the PrintDetails page? In these circumstances it was important to establish if the style was truly serving the the same purpose in all the locations it was being used and if so to give it a more accurate name that described its purpose rather than where it originated - in this case I settled on 'SummaryTitleTextBlock'.



Finally a word about the suffixes on style keys: as the names used in the style keys grew to include distinguishing qualifiers, their lengths became a bit unwieldy - 'ThumbnailSummaryTitleHyperlinkButtonStyle' for example, at 41 characters, is a getting bit long; and more importantly unnecessarily long - what actual useful information is conveyed by the inclusion of the 'HyperlinkButton' type when that is clear from the TargetType attribute in the declaration of the style? Similarly, the inclusion of the word 'Style' itself adds nothing that we don't already know - the fact is that either where the style is declared or where it is used, it will be clear to anyone reading the code, what it is and to which element type it applies. The only place where resources are seen 'out of context' as it were, is in the Resources view of Expression Blend and here a useful icon indicates the TargetType and the tooltip for each resource gives details of its type. As such it seemed reasonable to shorten resource keys to their descriptive parts with 'ThumbnailSummaryTitleHyperlinkButtonStyle' becoming merely 'ThumbnailSummaryTitle' - until I came up against two 'ThumbnailSummaryTitle' instances - one for a TextBlock and one for a HyperlinkButton in which case the reintroduction of the TargetType suffix was justified to distinguish the two styles.



 



Technorati Tags: ,,,

Tuesday, August 26, 2008

Travel By Thought: McCluskey - The Lost Album

Looking through the Mini-Discs in my attic the other day I found the only surviving copy of a set of recordings I made over 10 years ago, when I was into writing and recording using computers and MIDI equipment.

I wrote 18 pieces based on 'themes' from the music of Orchestral Manoeuvres in the Dark and named them after one of the group's two main members - Andy McCluskey.

Listening to them after all this time, I am quite satisfied with the results - I only had a bedroom to record in, a few pieces of MIDI equipment and an Atari ST, but apart from the odd glitch here and there, the tracks still sound pretty reasonable efforts.

Anyway, to prevent them being lost for another 10 or more years, I have put them up on my web site for my easy access and for the world to stumble across in the unlikely event that anyone else is interested:

http://www.openfeature.co.uk/cnstrct/sound.htm