Page view counter

Jesse Liberty - Silverlight Geek

More Signal Less Noise

October 2008 - Posts

Themes Revisited: The Implicit Style Manager [Updated!]

In a recent post on theming using the new Themes from the Controls Toolkit I showed that you can add a theme to your Xaml and then add a container as the content of that theme.

A powerful alternative is to use the ImplicitStyleManager to apply the theme to a single control or, more commonly, to a container (for example, a grid) and all its controls.

To do so, you'll want to provide the Silverlight URI to the .xaml file that defines the theme, which you can copy straight from the source code provided with the Toolkit into your project.

ThemeXamlInProject

Based on a question I received, I realized I should have provided more clarification:

The exact steps for adding this Xaml file are to go to the source files for the toolkit, navigate to the Themes pseudo-folder and grab Themes.xaml from under Controls.Theming.ShinyBlue and copy it to your project,  renaming it to Microsoft.Windows.Controls.Theming.ShinyBlue.xaml  (as shown).

This name is based on the fact that the file you are grabbing is from the Controls.Theming.ShinyBlue project and Controls is identified in the file as follows:

xmlns:controls="clr-namespace:Microsoft.Windows.Controls; assembly=Microsoft.Windows.Controls"

With that you are ready to create your page, which you can certainly lay out in either Blend or Visual Studio,

CreatingThemeTestInBlend

On clicking the Apply Theme in the upper left hand corner we'll apply the theme that is supplied as part of the control toolkit. We've already added the .xaml file that defines the ShinyBlue theme, so we need only add a reference to the Theme support dlls,

ThemeSupportDLLs

and the using statement at the top of Page.xaml.cs so that we can refer to the ImplicitStyleManager,

using Microsoft.Windows.Controls.Theming;

That done, we create the event handler to respond to the press of the Apply Theme button,

void applyTheme_Click( object sender, RoutedEventArgs e )
{

Within this method we'll create a Silverlight URI that points to the Xaml file. The URI constructor takes the Silverlight path to the ShinyBlue.xaml and the enumerated constant UriKind.Relative. With that, we are ready to call three static methods on ImplicitStateManager:

1. SetResourceDictionaryURI takes the control that we want to set the theme for (in our case the Layout Root, which will also apply the theme to all its contained controls) and the URI.

2. SetApplyMode again takes the control we're setting the theme for, but this time the second parameter is one of the ImplicitStyleApplyMode constants ( the possible values are Auto, OneTime or None).

3. Apply which applies the style and takes the single parameter of the control we're applying the style to.  Here is the complete Page.xaml.cs, with the code we've just discussed at the end.

using System;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Windows.Controls.Theming;

namespace ThemesWithISM
{
   public partial class Page : UserControl
   {
      public Page()
      {
         InitializeComponent();
         Loaded += new RoutedEventHandler( Page_Loaded );
      }

      void Page_Loaded( object sender, RoutedEventArgs e )
      {
         applyTheme.Click += new RoutedEventHandler( applyTheme_Click );
      }

      void applyTheme_Click( object sender, RoutedEventArgs e )
      {
         Uri uri = new Uri( @"ThemesWithISM;component/Microsoft.Windows.Controls.Theming.ShinyBlue.xaml", UriKind.Relative );
         ImplicitStyleManager.SetResourceDictionaryUri( LayoutRoot, uri );
         ImplicitStyleManager.SetApplyMode( LayoutRoot, ImplicitStylesApplyMode.Auto );
         ImplicitStyleManager.Apply( LayoutRoot );
      }
   }
}

Applying The Style

When the page is first displayed no style is attached,

BeforeApplyingTheme

Clicking on the Apply Theme button invokes the event handler which calls the ImplicitStyleManager methods and applies the theme,

AfterApplyingTheme

Toolkit release & Themes

Today at Microsoft PDC, Scott Guthrie demonstrated some of the new controls that have been provided as a part of the Silverlight Toolkit

The Silverlight Toolkit was previously named the Silverlight Control Pack

This toolkit provides a set of controls and themes for Silverlight 2. 

  • AutoCompleteBox
  • Chart
  • DockPanel
  • Label
  • Expander
  • TreeView
  • UpDown
  • ViewBox
  • WrapPanel
  • ImplicitStyleManager

 

These controls and their source code are available with Ms-Pl licensing on Codeplex

Historically, charting has been an extra-cost item, provided by third party vendors, but the Silverlight team is providing an extensive and extensible set of chart controls, with source code for free. We will be creating numerous HDI videos and tutorials to assist with getting the most from these controls and Tim has already posted a mini-tutorial to get you started.

I’ll kick of an examination of themes with a very simple application. To get started add the theme dll references to your application

ThemesDLLs

Note that for convenience, I’ve chosen to put my Controls dlls into a subdirectory of C:\Program Files (x86)\Microsoft SDKs\Silverlight\v2.0 though this is not required.

You can now add a theme either in Blend or in Visual Studio. Let’s start in Blend, but also look in Visual Studio to see how the Xaml is placed and, at least at the most superficial level, what the Theme does for you.

Themes in Blend

Once the themes are in your references, you can treat them as controls by extending the chevron, clicking on “show all” and choosing “custom controls” (remember, these controls are not in the core).

AssetLibraryThemes

You can add a theme to your page just as you add any control. typically, you will want to add a theme to a high level FrameworkElement, as all of the children (contained controls) will be themed.

Once you add the theme, you’ll want to double click on it, making it the container, so that additional controls will be “within” the theme, and thus the theme will be applied to those controls.

Within that theme can be one control, but of course that control can be (and should typically be) a container control, and so we end up with something like this,

   1: <UserControl
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     x:Class="ThemesTest.Page"
   5:     Width="800" Height="600" 
   6:     xmlns:shinyRed="clr-namespace:Microsoft.Windows.Controls.Theming;assembly=Microsoft.Windows.Controls.Theming.ShinyRed" 
   7:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
   8:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
   9:     mc:Ignorable="d">
  10:  
  11:     <Grid x:Name="LayoutRoot" Background="White">
  12:         <shinyRed:ShinyRedTheme HorizontalAlignment="Stretch" Margin="0" Width="Auto" 
  13:          FontFamily="Verdana" FontSize="24" FontWeight="Bold">
  14:             <Grid Height="Auto" x:Name="InnerGrid" Width="Auto">
  15:               <Grid.ColumnDefinitions>
  16:                     <ColumnDefinition Width="0.1*"/>
  17:                     <ColumnDefinition Width="0.1*"/>
  18:                 </Grid.ColumnDefinitions>
  19:  
  20:                 <Button x:Name="btn"
  21:                     Height="72" 
  22:                     HorizontalAlignment="Left" 
  23:                     VerticalAlignment="Bottom" 
  24:                     Width="244" Margin="0" 
  25:                     Content="This button is themed" 
  26:                     FontSize="18"  FontFamily="Verdana"/>
  27:                 <CheckBox 
  28:                     HorizontalAlignment="Left" 
  29:                     VerticalAlignment="Bottom" 
  30:                     Margin="10,0,0,0" 
  31:                     Width="150" Height="50"
  32:                     Content="CheckBox"
  33:                     Grid.Column="1" />
  34:             </Grid>
  35:         </shinyRed:ShinyRedTheme>
  36:     </Grid>    
  37: </UserControl>

Notice that we start with on outer grid, within that grid is a theme and inside that theme is another grid. We’re now back to programming exactly the way we always have; doing nothing special to the controls; but they are created within a theme, and thus the the theme is applied to the button and checkbox,

TwoThemedControls

To get a sense of how this affects a variety of controls, I created a slightly larger application that has two grids, one with a number of controls that are themed, the second with the same controls unthemed.

Here’s the page.xaml,

<UserControl xmlns:basics="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="themes1.Page"
Width="700" Height="650" 
xmlns:rainerPurple="clr-namespace:Microsoft.Windows.Controls.Theming;assembly=Microsoft.Windows.Controls.Theming.RainierPurple" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
<Grid x:Name="outer">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="1*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="1*" />
        <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <rainerPurple:RainierPurpleTheme Margin="0,0,0,0"     >
        <Grid x:Name="LayoutRoot" Background="White" Height="600" Width="320" Grid.Column="0" Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.1*"/>
                <ColumnDefinition Width="0.1*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="0.1*"/>
                <RowDefinition Height="0.1*"/>
                <RowDefinition Height="0.8*"/>
            </Grid.RowDefinitions>
            <Button Width="100" Content="Click Me" x:Name="myButton" HorizontalAlignment="Left" FontFamily="Verdana" FontSize="14"  Margin="5,0,0,0" VerticalAlignment="Bottom"/>
            <CheckBox Grid.Column="1" Content="Theme engaged" HorizontalAlignment="Left" IsChecked="True" FontSize="14" FontFamily="Verdana" Margin="5,0,0,0" d:LayoutOverrides="Height" VerticalAlignment="Bottom"/>
            <basics:Calendar DisplayMode="Month" IsTodayHighlighted="True" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Margin="5,0,0,0" Width="150" VerticalAlignment="Top" />
            <PasswordBox Width="111" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Height="30" Margin="5,0,0,0" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5" />
            <StackPanel HorizontalAlignment="Stretch" Margin="0,0,0,0"
            Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
                <RadioButton x:Name="rb1" GroupName="Grp1" Content="yes" IsChecked="true" Width="50" Height="20" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,0,0,0" />
                <RadioButton x:Name="rb2" GroupName="Grp1" Content="no" Width="50" Height="20" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,0,0,0" />
            </StackPanel>
            <Button Height="42" Margin="36,82,46,0" VerticalAlignment="Top" Grid.Column="1" Grid.Row="2" Content="Button"/>
        </Grid>
    </rainerPurple:RainierPurpleTheme>
    <Grid x:Name="LayoutRoot2" Background="White" Height="600" Width="320" Grid.Row="0" Grid.Column="1" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.1*"/>
            <ColumnDefinition Width="0.1*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="0.1*"/>
            <RowDefinition Height="0.1*"/>
            <RowDefinition Height="0.8*"/>
        </Grid.RowDefinitions>
        <Button Width="100" Content="Click Me" x:Name="myButton2" HorizontalAlignment="Left" FontFamily="Verdana" FontSize="14" Margin="5,0,0,0" VerticalAlignment="Bottom"/>
        <CheckBox Grid.Column="1" Content="Theme engaged" HorizontalAlignment="Left" IsChecked="True" FontSize="14" FontFamily="Verdana" Margin="5,0,0,0" d:LayoutOverrides="Height" VerticalAlignment="Bottom"/>
        <basics:Calendar DisplayMode="Month" IsTodayHighlighted="True" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Margin="5,0,0,0" Width="150" VerticalAlignment="Top" />
        <PasswordBox Width="111" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" Height="30" Margin="5,0,0,0" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5" />
        <StackPanel HorizontalAlignment="Stretch" Margin="0,0,0,0"
            Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
            <RadioButton x:Name="rb1a" GroupName="Grp1" Content="yes" IsChecked="true" Width="50" Height="20" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,0,0,0" />
            <RadioButton x:Name="rb2a" GroupName="Grp1" Content="no" Width="50" Height="20" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="5,0,0,0" />
        </StackPanel>
    </Grid>
</Grid>
erControl>

The output looks like this (adjusted to save space)

twoGridsWithThemes

Note that the theme is in the .dll and not in App.xaml; you are certainly free to add styles and templates on top of these themes. 

As noted this micro-tutorial is only intended to get you started, and not to be comprehensive. Hope it helps.

Greetings From PDC – Get Ready….

PDC is a wonderful conference but get ready for the onslaught of announcements, new material, information overload…

pdcbrain

I can assure that there is a lot of great stuff, and of course Tim and I and many others will be focusing on those announcements big and small that affect Silverlight.  This is a good moment, just a days before ScottGu’s keynote to say that it is our goal that Silverlight.net will prove itself as the go-to-first location to learn about everything new affecting Silverlight development.

We’ll be working closely with all the teams to make sure that we have the complete information and that we can offer mini-tutorials right away in our blogs, and well developed videos and tutorials in record time.

Since I’m in “pitch” mode, this may be a good time to consider subscribing as well so as not to miss anything. 

 Subscribe in a reader

Stay tuned, I’ll have lots of detail very soon.

So Much Technology – So Little Time

 

 

We have, I think, officially passed the point where anyone can keep up with the new technology available for developers, just from Microsoft (let alone all the new options from all the other companies), and PDC is les than a week away.

A  totally indefensible distortion of recent history as I remember it

When I started fussing with computers (1971) you could certainly learn the entire field (and then some) in a couple hours.  I was incredibly lucky, and I didn't like it much (my friends who did like it are all stuck in jobs in banks working in Cobol or worse) and so I didn't return to it with any seriousness until 1984). 

In the early 80's you could teach yourself all there was to know about microcomputers, and you could come up the learning curve as you remained productive.

There were choices to be made (I distinctly remember choosing DOS over CP/M and then PC over Apple IIe and then DOS over OS/2 and then Unix/C over DOS (for practical reasons – I had a gig).  So by 1989 or so I was already "specializing." 

In 1992 I was offered the opportunity to switch to Windows, which by then had grown up enough to be interesting. The project was cross-platform (Win 3.1/Mac; using a beta of the the ill-fated Bedrock cross-platform compiler) and, most important, it was C++, a switch I was eager to make and one which launched my 2nd career as a hack author (first book, 850 pages, 6 weeks; while working full time. Yowza!)

As an aside to this tangent, I'll tell you that you have not lived until you try to create software with a new programming model (Object-oriented) on a beta development platform (Bedrock) with a beta compiler (Zortech) and an alpha debugger using a 3rd party editor;  none of which was designed to work with any of the others. We spent a couple years on that project (written about Beginning Object Oriented Analysis and Design) only to be eaten alive by the World Wide Web as well we should have been.  But I digress.

In any case, in the 1990s something else began to happen, not only did I find myself choosing one platform over another (Windows over OS/2 for example ["OS/2 version n+2, the Real OS/2"] – I found myself whittling down what parts of Windows I would spend my time learning, as Windows Development itself was getting to big to learn it all.

Just keeping up with my little niche was a full time job. Since about 1995: ASP –> Web Classes –> ASP.NET –> ASP.NET w/Ajax –> ASP.NET/AJAX/MVC…  .NET –> .NET 2, 3, 3.5., MFC ->  WinForms –> WPF –> Silverlight…. you get the idea.  (I confess, I just more or less ignored DCom, waiting patiently for it to go away). 

MacBookProAlong the way I've flirted with the Mac (I do like the Mac a lot and wish I'd spent more time there..  though on balance, so far it appeals to my tin man, not my scarecrow)    -- but Silverlight meets that need, and I've convinced my boss that one of my "commitments" for this year is to increase my expertise in the Mac so as to provide cross-platform expertise (read this as: I get to play with my mac more).

Another aside: after 9/11 my rant was this: if I were in charge of the FAA the first thing I would do would be to call the Israeli Government and say "send me the person who set up your El Al security system, I want him in charge of the TSA for 1 year."  Similarly, if I were in charge of Windows, the first thing I would do is hire packgagingsomeone whose full time job it is to be able to answer the question "why is this easier on the Mac?"  -- it may be there are very good reasons, but we'd better know them.  Have you set up a Mac?  It is a blast.  Plug it in, wait a minute, answer two or three very obvious questions, wait a minute, you're done.  

While I'm ranting, I'd also have someone on my team in charge of "why does their packaging look nicer than ours?"

</Rant></Digression>

Where Was I? Oh Yes…

I'm often asked how to evaluate Silverlight against Flash, and as I've said before, I don't do that, (though there are lots of folks here who do that well). But the question that does interest me is this: of the ever increasing bounty of developer technology coming out of Microsoft: what do you need to know?

What Does A Silverlight Programmer Need To Know?

Let me start off by saying that this list will probably need to be updated frequently – not much I can do about that. Second, much depends on what else besides being a Silverlight programmer you have in mind, and what kinds of Silverlight applications you'll be building and what size team you're on and …. you get the idea.  Further, this is just my opinion – not a Microsoft official guideline.

That said, if I were pressed to answer what skills a Silverlight programmer really needs to keep up with, my list would start with:

Tools

Start here, return to here, this is critical.

  • Expression Blend and here
  • Silverlight

    Related Technology

    • Astoria
    • C# or VB (make your life easier)
    • Basic UI Design
    • WPF (Older sibling, many resemblances)
    • WCF (web services)
    • The Rest of .NET 3.5 Services (the mischpacha)
    • ASP.NET  ("Might be fun, could be dangerous, maybe tomorrow")

    Some Books That May Help

    Knowing the author and his writing, my guess is that this will be terrific (not yet released)

    Data and Services with Silverlight 2: John Papa: Books

    ISBN: 0596523092
    ISBN-13: 9780596523091

    There are a number of good books on C# and VB. If you are new to both, I can't help but recommend this, though this new edition won't be out for a few weeks.

    Learning C# 3.0: Jesse Liberty, Brian MacDonald: Books

    ISBN: 0596521065
    ISBN-13: 9780596521066

    Books I like on learning the related .NET 3.5 technologies (yes, there i go again with one of my books, but it is the only one I know of that covers WPF, WCF, WF and all of .NET 3.5 in a single volume).

    Programming .NET 3.5: Jesse Liberty, Alex Horovitz: Books

    ISBN: 059652756X
    ISBN-13: 9780596527563

    Programming WPF: Chris Sells, Ian Griffiths: Books

    ISBN: 0596510373
    ISBN-13: 9780596510374

    There are a number of excellent books on ASP.NET, many from my own team

    November 22, 2008

    November 22, 1963.  45 years.  Sic Transit Gloria Mundi

    Posted: Oct 22 2008, 09:56 AM by jesseliberty | with 10 comment(s)
    Filed under:
    It Ain't You, Babe… A Not-a-bug bug in DataGrid

    SLLogoWords

     

    I'll be writing a set of mini-tutorials on the DataGrid that will, as the King advises, begins at the beginning, goes on till it comes to the end and then stops[1], but before I do, a "Set Of Behaviors That Is Perfectly Understandable But Not At All What The Programmer Expects (SOBTIPUBNAAWTPE)" has surfaced in DataGrid.  (I was told this is not a bug – my response was a bit snide).

    Since this is causing a great deal of frustration and confusion, I wanted to alert you to it before you pull all your hair out – I'll also let you know as soon as I have the details of the work around.

    iStock_ ice create spilled Large

    To understand the bug (oops) you need to understand two properties associated with DataBinding Validation for two-way binding.

    In English that means that when you enter data that will be written back to the data source, Silverlight will validate the data and handle two types of exceptions for you if you set the right properties.  The two types of exceptions are:

    1. Exceptions that are thrown when the binding engine tries to convert the type of the data
    2. Exceptions that are thrown from within the binding object's set accessor

    The two properties that you need to set are NotifyOnValidationError and ValidatesOnException.  They both default to false. You want to set them to true; if you do the exceptions are turned into BindingValidationError events – and even better they are bubbling events which means that you can put your event handler on the containing control. 

    The way this is supposed to work is that you can associate an event handler for the BindingValidationError with the DataGrid itself, and if there is a problem binding the data in any of the columns it will bubble up to that one handler, rather than firing an exception that might bring your application to a stand still. 

    As a practical test of this, and stealing borrowing from examples from Reid Maker (who pointed out the SOBTIPUBNAAWTPE in private correspondence) and from Manish Dalal's Blog (who illustrated how this should work during Beta 2) I tried to prove to myself that it wasn't a bug by trying various variations (e.g., moving the event handler in and out of Xaml, moving the exception generation in and out of an event, generating the exception in each of the two ways, and so forth).

    Here is the code, somewhat simplified

    The Data Source Class

    using System;
    using System.ComponentModel;
    
    namespace DataGridBindingValidationTester
    {
       public class TestData : INotifyPropertyChanged
       {
          public event PropertyChangedEventHandler PropertyChanged;
          private int id = 0;
          private string name = string.Empty;
    
          private void NotifyChange( String name )
          {
             if ( PropertyChanged != null )
             {
                PropertyChanged( this, new PropertyChangedEventArgs( name ) );
             }
          }
    
          public string Name
          {