Welcome to MSDN Blogs Sign in | Join | Help

Silverlight 2 Beta 2 is now available !!

Woo - Hoo!!

Navigate over to http://silverlight.net/GetStarted/ to download the  freshly minted beta 2 bits including the runtime, the SDK, and the Visual Studio 2008 tools for Silverlight 2 development. There is also a brand new version of Blend 2.5 preview and a new version of the Deep Zoom Composer available for download as well.

I have been quite busy working on several large customer projects that involve Silverlight 2 Beta 2. In the coming weeks do visit here to find more tid-bits about SL 2 development and the changes in Beta 2.

Enjoy !!

Posted by jitghosh | 1 Comments

Broken link to attachment fixed for previous post

Sone folks pointed that the code sample attachment in my previous post on the Async Multiple File Upload Control for Silverlight 2 was broken. I have fixed it in the post as well provided a link below to the code on my Windows Live SkyDrive.

http://cid-60bb739cbf5d117b.skydrive.live.com/self.aspx/Public/MultiFileUpload/MultiFileUpload.zip

Sorry for the incovinience.

Posted by jitghosh | 0 Comments

Async Multi File Upload Control with Metadata support for Silverlight 2 (Beta 1)

By now a lot of you must be having a lot of fun of Silverlight 2 Beta 1. If you have not downloaded, installed and played with SL 2 Beta 1, I urge you do it right away - you are missing out!!! You can download SL2 here.

I have been working on a number of projects that are using the Silverlight 2 beta bits, and several of them needed file upload functionality. I looked around, and found a few controls, but while all of them did certain things admirably well, there were a few things missing.

  • A few of the controls I found allowed you to select multiple files, and upload them, but all of them did so sequentially i.e. one file at a time. Parallel uploads were a necessity for my projects, with the extent of parallelization as a controllable parameter.
  • None of them really allowed you to control how a large file gets chunked i.e. at what size boundaries. This can be an important parameterization to improve efficiency.
  • Since most of my projects are media related, it is common for me to work on applications where a user is allowed to attach metadata to the file being uploaded. And metadata could vary from application to application. I needed a control that would allow some sort of metadata architecture, that is not hard wired to the control and pluggable by design. I wanted to reuse the same control in many apps, with the consuming apps defining the metadata UI and serialization process, and wiring it to the control through a standard interface.
  • And lastly I also needed a completely templatable control.

Needless to say I could not find a combination of all of the above in one control - so I set out to do the next best thing - write one for my own. And the point of this entry is to share it with you. The code is zipped and attached.

First a little about the solution structure. You will find several projects in the solution:

  • MFUControl - This the main control project containing most of the functionality behind the control. It also contains all of the control's UI.For those of you who are just starting out with SL 2, or have not played with WPF custom controls before, the default UI for a custom control is defined as a control template that gets applied to the control through a style defined in a file called generic.xaml - this file has to be named exactly this way for the runtime to recognize it(this is similar to WPF). Also, applying a UI to a custom control by way of a control template allows the consumer of the control to later apply other templates to change the L&F.
  • ProgressBar - Since SL 2 Beta 1 does not have a ProgressBar control yet, and I needed one, I created one by extending the RangeBase control. Again a default control template is applied and can be found in the generic.xaml file in the project.
  • MFUTestApp - This the test harness for the app - standard SL 2 app that has one page with the control on it.
  • TestWeb - An ASP.Net web app that can be used to run MFUTestApp from IIS
  • UploadService - This the HTTP backend to which the files are uploaded. I have chosen to use a WCF service, using a RESTful interface (implemented using the WCF Web Programming layer), with a single operation that gets invoked using an HTTP POST accepting a file stream.

I will attempt to sparingly explain some of the key pieces of the code here. I have commented the code pretty well - so hopefully in reading through the downloaded code most of it will be obvious to you.

But first things first - below is a screen shot of the control in action, uploading some videos. By the way, if some of you are designers and other kind of creative professionals, and are snickering at the UI, you will have to forgive the paucity of my artistic skills. I can code, but let it be known - I cannot design nice UI's :-).

MFU1

So the key pieces of the code as I said :

  • The actual upload functionality - The upload piece is pretty simple. I use the HttpWebRequest type to do the upload. Initialize it properly, plug in the file name in the HTTP headers, get the request stream, write the file content to it, and POST - that's about it. On the service side, it is even simpler - open the stream, get the file name from the HTTP headers, create a new file at a known location and write it out. This goes on for every file that is being uploaded.
  • The parallelization/multi threaded upload - Unfortunately while SL 2 allows you to spin up your own threads, it does not allow making network calls from anywhere other than the UI thread(at least not yet). So I had to look for a way around. The good thing is that the network API's in SL 2 are all async, and use the standard Begin...()/End...() async invocation pattern established in .Net. In this pattern as soon as you make the egin..() call, control returns to your code and the actual unit of work initiated with the call gets automatically shifted to a background thread from the thread pool.

In my code I break up the entire list of files of chosen by the user into sublists based on the number of background threads the user desires to use (this is specified by the MaximumUploadThreads dependency property on the control) - one sublist for each thread. As an example if you had selected 14 files and specified 4 threads, the first 3 sublists each get 4 files, and the last one gets 2.

Once these lists are broken up, I loop through them, and call BeginGetRequestStream() once for the first file in each list. Control returns and only as many threads get employed as there are sublists, and upload starts. To ensure that at any point in time, no more threads get employed, I start uploading the next file in any sublist, once the previous upload for that sublist is completed i.e. initiate the next upload in the callback handler specified in the BeginGetResponseStream() method for the previous upload, which gets invoked once a response comes back from the service after the previous upload completes (or fails).

Note that upping the number of threads will allow you to achieve more parallelization, but at the cost of more background threads on the client.

  • The chunking of large files - The control has another dependency property called FileChunkBoundaryInKiloBytes. What you specify is used as the chunking size boundary. For files that are smaller in size than the size specified here are uploaded in one fell swoop, and the progress bar goes straight from 0 to 100%. This is also because the HttpWebRequest has no mechanism for reporting true progress of the network activity :-(. However for files that are larger than the chunking size, are uploaded in chunk sizes as specified. the code follows a different route for those files, and all chunks of a file get uploaded in the same background thread as being used for the sublist to which the file belonged. An internal data structure named FileChunk is used to maintain stream positions, so that successive chunk uploads can be done accurately.

Progress is reported for each chunk, so you will see the progress bar report things somewhat more realistically here. Also additional HTTP headers are passed in to the backend, for each chunk, including the chunk #, total chunks and the chunk size, to facilitate the proper appending of chunks to the file as it gets built on the server with each POST of a chunk.

Note that upping the boundary may be a lucrative option for very large file uploads to achieve faster uploads, but this is client memory, and you can soon get OutOfMemory exceptions if you are not careful.

  • The metadata piece - The assumption here is that the client (the app using the control) and the server has some well known contract for the metadata passed and expected respectively, and I needed a way for the control to facilitate the collection, packaging and uploading of that metadata, without itself being aware of any specifics of the metadata - that is the only way it would be reusable across all possible metadata requirements.

The metadata UI is supplied to the control by you defining a Data Template in your app code with the appropriate UI, and supplying it to the control through the FileMetadataTemplate dependency property.

You also need to implement a custom type to act as the data source for this data template. This type needs to implement an interface named IFileMetadataBase that I defined, and that has a single method named SerializeFileMetadata() returning a string. This method is where you supply your serialization logic (in the provided sample I use Json - but you could as easily use XML) , and as long as the serialized form is a string - we are good. This type also will typically implement the metadata elements as properties that you will bind to the appropriate portions of your metadata Data Template.

So how does all this get wired up ? At runtime if the control senses that a Data Template has been specified for metadata, it raises an event called ProvideMetadataInstance and you will need to handle this. The event arguments to this event has a single property of type IFileMetadataBase (the interface I mentioned above), and you set it to a new instance of the implementing type that you created - and voila!!. The control wires up the instance to the data template. When files are uploaded, it calls the function to serialize the metadata to a string, and passes it on as another additional, well named HTTP header, so that the backend can do whatever it wants with it.

I provide a sample of this in the code, with two metadata fields called "Comments" and "Description". Clicking the little button on each file entry, displays the data template which you can fill out.

MFU2

  • The backend - I implement this as a WCF service. But since the interface is simple (HTTP POST + Headers) - I am certain that you ASP.Net (or even other web platform) experts out there can reimplement it using other patterns.

Also the service now puts all uploaded files in a subfolder called Assets under the service directory. This is hardwired in the service code. Change it as you see fit, but do remember to change service code accordingly as well.

  • There is also remove functionality in the control - you can check the little checkboxes, a Remove button appears, and you can then remove files from the list

There are a lot of things incomplete in the control:

  • Slick UI
  • There should be a ceiling enforced on both the chunking size and max thread count to prevent inadvertent memory outage/resource outage on the client
  • The button (or whatever else) that shows the metadata, needs to be hidden when no data template is attached
  • In future revs of SL 2, as network calls and background threads become more friendly, you can take better advantage of that
  • Any other bugs/incomplete features you can find (of which there may be a ton)
  • Slick UI (Have I said that already ??)

In any case my goal was to give you all something to play with and certainly improve upon. Let me know if this helped.

Remember to uninstall any older versions of SL on your machine, download and install the runtime , the SDK and the tools, and enjoy!!!

 

Download Link : http://cid-60bb739cbf5d117b.skydrive.live.com/self.aspx/Public/MultiFileUpload/MultiFileUpload.zip

Posted by jitghosh | 9 Comments

Slides and Demos from Developer Days, March 13th in New York

I recently gave two presentations at one of our events in New York - one on WPF and one on Silverlight 2. A lot of folks asked me to make the slide decks and the code demos available. So here they are (zipped) - you can download them from my Windows Live SkyDrive below. Feel free to ping me if you have questions. Sorry for being tardy in getting this done.

Click the icon above to download

Enjoy!!

Posted by jitghosh | 3 Comments

WPF based Music CD Ripper

One of the WPF based projects I am working on right now needs some functionality to enable ripping music CD's a la Windows Media Player. I was digging into the various Windows Media SDK's as well as the Media Foundation stuff in Windows Vista to find the best way to achieve this - and it turns out the easiest is to rely on Windows Media Player itself. WMP exposes all of this via COM - so all you need to do is add a reference to the appropriate typelib, and off you go. Probably not the best solution, because of the WMP dependency, but it works nicely. I built a quick WPF prototype, and thought some of you might benefit from the code. I am attaching the Visual Studio project (zipped)- feel free to play with it.

 

Note that you will need Visual Studio 2008 and WMP 11 on your machine. There is also a way to use WMP 10 for this, but the user experience is not as nice. Also note that there are ways to rip music CD's with no dependency on WMP, but the solution will be significantly more complicated. Also be aware that depending on your settings, as soon as you pop a music CD, WMP might come up itself and start ripping. Make sure to close WMP before you try this app out.

 

Below is a screenshot. Zipped source code attached.

Enjoy!!!

CDRipper

Posted by jitghosh | 7 Comments
Attachment(s): CDRipper.zip

WPF Control Templates - An Overview

In several of my discussions with customers around WPF in the recent past, I got asked a bunch of questions around Control Templating. Most of them can be summarized to one - "how do control templates work". Control Templating is fairly fundamental to WPF development, and unlike some niche features like WPF 3D, a good understanding of Control Templating goes a long way to sleek UI development.

There are many excellent writings on this topic - so before I write something on this, I should at least point a few out. Chances are that, you might get a much better idea from these works than my post here.

The best coverage I have read is in Chris Anderson's excellent book Essential Windows Presentation Foundation. If you are working with WPF, and need a deep understanding of not just the workings of the framework, but the design motivations behind why certain things are the way they are - I would urge you to read this book cover-to-cover.  You should also check out Adam Nathan's work WPF Unleashed, and Programming WPF by Chris Sells and Ian Griffiths - both excellent books as well. Now that you have that information, let me see if I can put things in a simple perspective.

To understand control templates, it is helpful to first understand two related concepts:

  • The WPF element tree - the "logical tree" of a control template vs. it's "visual tree"
  • The content model for WPF controls.

Logical Tree

Let's start with the "logical" tree. The simple XAML snippet below produces a ListBox with three items:

 

<ListBox Height="100" Width="100">
 
<ListBoxItem>Item 1</ListBoxItem
>
 
<ListBoxItem>Item 2</ListBoxItem
>
 
<ListBoxItem>Item 3</ListBoxItem
>
</ListBox>
image

 
The element tree of the ListBox as depicted in the XAML hierarchy is shaped like 
 

Picture1

 

This is the logical tree for the ListBox. If we were to take an even simpler snippet of XAML like

 

<Button Height="40" Width="100" Content="Hello" /> image
 

the logical tree would have just one node - the Button element itself. The logical tree is the externally visible element hierarchy that a consumer of the control gets to program against.

Visual Tree

However, the logical tree provides no information as to the UI that the control displays. The fact that the ListBox displays itself with a bounding rectangle with a black border, or that the Button has a gradient background with an exterior chrome are all encapsulated somewhere else. 

In older UI Frameworks like Win32, Windows Forms or MFC, the control author implemented the UI in the control code, thus providing no facility to the control consumer to completely replace the control's UI - the traditional ways of offering customization capabilities have been to expose properties and methods that allow some customization of the constituent elements and consequently the control's look & feel. 

In WPF however, this is done somewhat differently. To understand how, let's first take a look at the element tree of the ListBox again. Type the XAML in XAMLPad (available with the Windows SDK), and XAMLPad renders the ListBox. Click the "Show/Hide Visual Tree" button (pointed to by the blue arrow) as shown below:

 

Picture2

 

Expanding the Visual Tree Explorer completely, if you look at the ListBox node and below,you can see a tree formed of a multitude of other controls and drawing primitives . This is the "visual tree" for the ListBox control - the complete element tree made of the actual drawing primitives and other controls used to implement the UI of the control. If you look down you will find a similarly detailed tree for each of the ListBoxItems situated within the ListBox.

image

 

The "visual tree" for a control is what contributes to the complete look & feel of the control - it is helpful to be able to see it like this. But what is even more helpful is an understanding of how this element tree is supplied to the control in order to generate the UI, and most importantly, how you as a consumer of the control might be able to change it.

Control Templates & the "Visual Tree"

As a control author you have the option of hard coding this "visual tree" in your control implementation i.e. somewhere in the control's creation and rendering lifecycle, you can instantiate the complete element tree in code, and use that to render the UI. Not that it's a bad way, and in fact there are several controls, that come with WPF, that take this approach, but it makes your control's UI pretty hard to customize.

Control Template's provide a more extensible way. You may have heard it said many times, that WPF controls are "lookless" in that they define the functionality behind the control, with a "default" UI which can be completely replaced by their consumer. This is what control templates enable.

Control Templates are XAML declarations of a "visual tree" for a control. As a control author you can declare and use them in your control implementation to provide the "default" UI for your control. Doing so also leaves the control open for templating by consumers - a consumer can then declare new templates that can be supplied to a control, either in code or in XAML itself, to replace the default look & feel.

That said let's take a look at how that might work.

Creating and Applying a Control Template 

A Control Template is declared inside a <ControlTemplate> element and is usually defined in a resource dictionary. As a requirement of being a part of a resource dictionary, the template is given a unique identifier using the x:Key attribute, and it also specifies the control type to which it can be applied using the TargetType property.

Let's start with a simple one that can be applied to the Button Control.

<ControlTemplate x:Key="CTGelButton" TargetType="{x:Type Button}">
    <Grid Width="100" Height="100">
        <Ellipse Stroke="#FF000000" Fill="#FF1C46E7" x:Name="OuterEllipse">
            <Ellipse.BitmapEffect>
                <BevelBitmapEffect BevelWidth="8" EdgeProfile="BulgedUp" Smoothness="0.745"/>
            </Ellipse.BitmapEffect>
        </Ellipse>
        <Ellipse Margin="8,8,8,8" x:Name="InnerEllipse">
            <Ellipse.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" SpreadMethod="Pad">
                    <GradientStop Color="#FF1C46E7" Offset="0"/>
                    <GradientStop Color="#FFFFFFFF" Offset="1"/>
                </LinearGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/>
    </Grid>
</ControlTemplate>

 

Applying the template to a Button control is done so :

<Button Content="Hello World" Template="{DynamicResource CTGelButton}"/>
image

 

As you can see applying the template has completely replaced the default Button UI. However, the essential functionality, as implemented by the Button type, has not changed at all. All the events are still raised the way they would by default, all the methods and properties are still available as prescribed by the Button's API - you would program against the Button instance just the way you would if it was displaying its default UI.

Control Content Model & Control Templates

Sometimes the primary purpose of a control is to display content that is supplied to the control. Take for example a ListBox or a ComboBox or a TreeView - these are all controls that have a default look and feel that can be further customized using control templates, but their primary purpose is to display a set of items somewhere within that look and feel. The part of the WPF control architecture that specifies how controls display content is called the Content Model.

To better understand the content model in WPF, let's consider the ContentControl type. The ContentControl itself has a very limited UI, but has a dependency property called Content, that can either be set or databound to any content, which then gets displayed. More than being useful in and of itself, the ContentControl serves as the base class for many other WPF content controls like Label or Button(in case of Button it is not the immediate ancestor - ButtonBase is), and consequently drives the content model for these controls. For example in the XAML below, we show two examples of setting the Content of the Button we have been working with before - once to a text string, and once again to another XAML element tree consisting of a Grid containing a Radiobutton and a Checkbox(a rather contrived example - but serves the purpose of illustration) that can be visually rendered:

 

Button Content Example 1: Text Content  
   
<Button Content="Hello World" Template="{DynamicResource CTGelButton}"/>
image
   
Button Content Example 2: Visual Tree Content   
   
<Button RenderTransformOrigin="0.625,2.55" Grid.Row="1" Margin="50,21,128,92"
        Style="{DynamicResource StyleGelButton}">
    <Button.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition/>
            </Grid.RowDefinitions>
            <RadioButton Content="RB 1" Grid.Row="0" IsChecked="True"/>
            <CheckBox Content="CB 2" Grid.Row="1" IsChecked="True"/>                    
        </Grid>
    </Button.Content>
</Button>
image

The ContentControl defines a content model where it or its derivatives can display a single piece of content (it can be a whole tree of elements - but still rooted at a single element).

But why is the understanding of the Content Model important to you when considering control templating ?

When you design a template for a control you need to be aware of the intended content model for that control, and to be fair to the control's intended behavior, should try to retain the same content model in your custom template. Let's take a look at the first template we designed for our Button.

<ControlTemplate x:Key="CTGelButton" TargetType="{x:Type Button}">
    <Grid Width="100" Height="100">
        <Ellipse Stroke="#FF000000" Fill="#FF1C46E7" x:Name="OuterEllipse">
            <Ellipse.BitmapEffect>
                <BevelBitmapEffect BevelWidth="8" EdgeProfile="BulgedUp" Smoothness="0.745"/>
            </Ellipse.BitmapEffect>
        </Ellipse>
        <Ellipse Margin="8,8,8,8" x:Name="InnerEllipse">
            <Ellipse.Fill>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" SpreadMethod="Pad">
                    <GradientStop Color="#FF1C46E7" Offset="0"/>
                    <GradientStop Color="#FFFFFFFF" Offset="1"/>
                </LinearGradientBrush>
            </Ellipse.Fill>
        </Ellipse>
        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/>
    </Grid>
 </ControlTemplate>

Take a look at the line of XAML in bold above. The ContentPresenter control is essentially a placeholder that binds to the content specified at the declaration of the Button control via its Content property. The ContentPresenter contains all the rules that determine how the content is displayed. When you are defining a new template for the Button control, if you do not specify a ContentPresenter somewhere in your control template, the Button will not behave as intended i.e. no matter what is specified for the Content property , it will not be displayed within your newly templated Button.

There are several other content models supported by WPF - like having a header portion to the content or displaying a list of items. There are other similar base level control classes, like HeaderedContentControl, ItemsControl and HeaderedItemsControl that can help implement these alternate content models. Let's take a look at a ListBox for example, which has ItemsControl as a parent in its inheritance chain. If we were to specify a template for a ListBox like so:

 

<ControlTemplate x:Key="CTListBox" TargetType="{x:Type ListBox}">
    <Border BorderBrush="#FFE62121" BorderThickness="4,4,4,4" CornerRadius="3,3,3,3" >
        <Border.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFBCDEDC" Offset="0"/>
                <GradientStop Color="#FFFFFFFF" Offset="1"/>
            </LinearGradientBrush>
        </Border.Background>
        <ItemsPresenter/>
    </Border>
</ControlTemplate>

 

Again notice the ItemsPresenter in the template. This is what preserves the intended "multiple items" content model as prescribed by the ItemsControl, and automatically binds to and displays the content in the Items collection for the ListBox. The template when applied to a ListBox with a set of items, like below , produces the UI on the right.

<ListBox IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="158,142,0,194" 
         Width="96" Template="{DynamicResource CTListBox}">
    <ListBoxItem Content="Item 1"/>
    <ListBoxItem Content="Item 2"/>
    <ListBoxItem Content="Item 3"/>
    <ListBoxItem Content="Item 4"/>
</ListBox>
image

 

So as you see, you should consider the intended content model for the control you are trying to template, and preserve that in your template. A complete discussion of all the various control content models is beyond the scope of this writing, but you can look in the .Net Framework SDK documentation and samples to find more details about the content model , its mechanics, and the set of rules that define  how the WPF runtime resolves how to render arbitrary content (for example a straight piece of text vs. a XAML element tree vs. an instance of some CLR type etc.). 

 

Binding to Parent Properties 

More often than not there may be a desire, or even a need, to not hard code property values in a control template, but let the control consumer specify those values. The control consumer's primary access is however to the control itself - so there needs to be a way of allowing the consumer's desired property settings flow to the template applied to the control. For example in the ListBox control template in the previous section, we see a Border control being used in the template, with its BorderBrush and BorderThickness properties set to specific hard coded values. The ListBox control itself however exposes the same properties. However the way the template is specified above, applying values to those properties on the ListBox control will have no effect on the template, and the ListBox will always show up with a red border of thickness 4 - no matter what.

This is where the TemplateBinding markup extension comes to the rescue. TemplateBinding is a kind of specialized data binding, that binds to the property values in the TemplatedParent i.e. the control instance to which the template is being applied. Take a look at the slightly modifed ListBox template below:

 

<ControlTemplate x:Key="CTListBox" TargetType="{x:Type ListBox}">
    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                              CornerRadius="3,3,3,3" >
        <Border.Background>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FFBCDEDC" Offset="0"/>
                <GradientStop Color="#FFFFFFFF" Offset="1"/>
            </LinearGradientBrush>
        </Border.Background>
        <ItemsPresenter/>
    </Border>
</ControlTemplate>

We are now setting the BorderBrush and BorderThickness as TemplateBindings to matching properties in the TemplatedParent.

 

As a result, the following two ListBox declarations will produce differing outputs :

 

<ListBox IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="158,142,0,194"
BorderBrush="LightBlue" BorderThickness="7" Background="Black"
         Width="96" Template="{DynamicResource CTListBox}">
    <ListBoxItem Content="Item 1"/>
    <ListBoxItem Content="Item 2"/>
    <ListBoxItem Content="Item 3"/>
    <ListBoxItem Content="Item 4"/>
</ListBox>
 
image
<ListBox IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" Margin="158,142,0,194"
BorderBrush="Gold" BorderThickness="2" Background="Blue"
         Width="96" Template="{DynamicResource CTListBox}">
    <ListBoxItem Content="Item 1"/>
    <ListBoxItem Content="Item 2"/>
    <ListBoxItem Content="Item 3"/>
    <ListBoxItem Content="Item 4"/>
</ListBox>
   
image

 

You may have noticed that in addition to setting the BorderBrush and BorderThickness properties on the ListBoxes, I also set the Background property value. But it does not have any impact on the ListBox, since in the template, the Background property for the Border element is hardcoded to a gradient.

 

If you look at the Button control template that we have been using in the sections above, you will find another example of TemplateBinding - the ContentPresenter uses TemplateBinding to bind to the Content property of the TemplatedParent (the Button instance in this case).

While in the examples above we have bound similar properties within the templates to the TemplatedParent i.e. BorderBrush to BorderBrush etc. there is no such rule mandating so. As long as the types match or there is a suitable TypeConverter, you can pretty much achieve any kind of binding, only limited by your sense of what is functionally sensible to do. 

 

Control Templates & Triggers

The Button control template that we have been working with before is pretty inert - when you apply it you do not see any of the usual animations that are associated with a button's default UI when a mouse moves over it, or it receives focus, or it is depressed. So let's add a trigger to the template above :

<ControlTemplate x:Key="CTGelButton" TargetType="{x:Type Button}">
    <Grid Width="100" Height="100">        
<!-- OMITTED FOR BREVITY -->
    </Grid>
    <ControlTemplate.Triggers> 
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="BitmapEffect" TargetName="OuterEllipse">
                <Setter.Value>
                    <BitmapEffectGroup>
                        <OuterGlowBitmapEffect GlowColor="#FFFF2300" GlowSize="17" Noise="0"/>
                        <BevelBitmapEffect BevelWidth="8" EdgeProfile="BulgedUp" Smoothness="0.7"/>
                    </BitmapEffectGroup>
                </Setter.Value>
            </Setter>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

 

A Trigger is a WPF construct that allows you to declaratively specify a single or a set of changes to be applied to a specific element within scope, when a certain action happens. These driving actions could either be changes in the values of one or a set of properties or be the firing of an event. In other words using Triggers you can achieve the same effect that you would achieve in non WPF applications like Windows Forms by possibly coding sizeable event handlers.

In this case we are using a Property Trigger that fires when the value of the IsMouseOver property changes to True. When that happens, the <Setter> element in the trigger instructs that the BitmapEffect property of the target element OuterEllipse be set as defined in the <Setter.Value>. Unlike what you would possibly do in an event handler, you do not have to do anything to explicitly set the UI back to its original state when the IsMouseOver property changes back to False - the Trigger takes care of that. The resulting UI would look like below when the mouse moves over the Button instance:

image

 

Control Templates & Styles

Styles are convenient ways of grouping property settings together and applying them to more than one element. Since we apply control templates to controls using the Template property, we can use a Style to actually apply the control template, instead of directly setting the Template property on the control instance element. So we could do something like below:

<Style x:Key="StyleGelButton" TargetType="{x:Type Button}">    
    <!-- Other Property Setters ommitted for brevity -->
    <Setter Property="Template" Value="{DynamicResource CTGelButton}"/>
</Style>
<Button Content="Hello World" RenderTransformOrigin="0.625,2.55" Grid.Row="1" Margin="50,21,128,92" Style="{DynamicResource StyleGelButton}"/>

A style can be universally applied to all instances of a type. If you skip setting the x:Key property on the style above, and consequently skip setting the Style property on the Button, the style will be applied to all Buttons within scope. For control templating purposes, this is handy when you want to apply a certain template to all controls of a specific type.

Styles also come in handy when you need to apply templates to a control conditionally - say depending on the outcome of a property trigger. The snippet below defines a style that applies two different templates to the Button control depending on whether the Button is depressed or not.

<ControlTemplate x:Key="CTGelButton" TargetType="{x:Type Button}">
    <Grid Width="100" Height="100">
        <!-- OMITTED FOR BREVITY -->
</ControlTemplate>

<ControlTemplate x:Key="CTGelButtonPressed" TargetType="{x:Type Button}">
    <Grid Width="100" Height="100">
        <Ellipse Stroke="#FF000000" Fill="#FF1C46E7" x:Name="ellipse" StrokeThickness="5"/>
        <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" Content="{TemplateBinding Content}"/>
    </Grid>
</ControlTemplate>

<Style x:Key="StyleGelButton" TargetType="{x:Type Button}">    
    <Setter Property="Template" Value="{DynamicResource CTGelButton}"/>
    <Style.Triggers>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Template" Value="{DynamicResource CTGelButtonPressed}"/>
        </Trigger>
    </Style.Triggers>
</Style>

Applying the style produces a different look & feel for when the button is depressed

<Button Content="Hello World" RenderTransformOrigin="0.625,2.55" Grid.Row="1" 
Margin="50,21,128,92" Style="{DynamicResource StyleGelButton}"/>
image

 

In Conclusion

While the examples above are fairly simplistic, I hope for those of you who have been trying to gain an initial understanding of control templates, the information above will provide a good starting point. In future posts I will  talk about some interesting ways to template the controls that come with WPF, as well as authoring your own controls to be templatable.

Posted by jitghosh | 11 Comments
Filed under: ,

New Drops for ASP.Net 3.5 Extensions CTP and Entity Framework Beta

Scott Guthrie announced a CTP release for ASP.Net Extensions available for public download. Lots of exciting features that you can play with, including the new ASP.Net MVC Framework, as well as the Entity Framework.

ASP.Net 3.5 Extensions CTP

MVC Toolkit Extras

Quick Starts

 

Also download the beta 3 build of Entity Framework Tools for Visual Studio 2008 RTM from here.

ADO.Net Entity Framework Tools Dec 07 Community Technology Preview

 

Enjoy!!

Posted by jitghosh | 1 Comments

Great article on Communications As A Service

It is becoming increasingly obvious that designing telecommunication architectures in a service oriented way actually makes a lot of sense.  Joe Hofstader, another Architect on our team, has tons of experience building service based solutions for the telecom industry. Check out his article on Caas here. Joe does an excellent job in positioning a Caas Reference architecture based on SIP and IMS.

Enjoy!!

Posted by jitghosh | 1 Comments

.NET Product Roadmap Announcements

If you have seen Scott Guthrie's recent post on the .Net Web Product roadmap, also check out my team mate Harry Mower's