Page view counter

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

Posted by jesseliberty | 31 comment(s)
Filed under:

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.

Posted by jesseliberty | 28 comment(s)
Filed under: ,

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

    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
          {
             get { return name; }
             set
             {
                name = value;
                NotifyChange( "Name" );
             }
          }
    
          public int Id
          {
             get
             {
                return id;
             }
             set
             {
                if ( value == 9 )
                {
                   throw new Exception( "can't have 9" );
                }
                id = value;
                NotifyChange( "Id" );
             }
          }
       }
    }

    Page Xaml

    <UserControl x:Class="DataGridBindingValidationTester.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="400" Height="300" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
        <Grid x:Name="LayoutRoot" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="0.15*"/>
                <RowDefinition Height="0.85*"/>
            </Grid.RowDefinitions>
            <TextBlock Margin="18,8,56,8" x:Name="Output" FontSize="14" Text="Error Messages Show Here" TextWrapping="Wrap"/>
            <data:DataGrid x:Name="TestDataGrid" Margin="10,10,10,10" Grid.Row="1"  AutoGenerateColumns="False" >
                <data:DataGrid.Columns>
                    <data:DataGridTextColumn Header="Name" Binding="{Binding Name}"  />
                    <data:DataGridTemplateColumn Header="ID">
                        <data:DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock  Text="{Binding Id}"  />
                            </DataTemplate>
                         </data:DataGridTemplateColumn.CellTemplate>
                        <data:DataGridTemplateColumn.CellEditingTemplate>
                            <DataTemplate>
                                <TextBox Text="{Binding Id,Mode=TwoWay,NotifyOnValidationError=true,ValidatesOnExceptions=true}" />
                            </DataTemplate>
                        </data:DataGridTemplateColumn.CellEditingTemplate>
                    </data:DataGridTemplateColumn>
                </data:DataGrid.Columns>
            </data:DataGrid>
        </Grid>
    </UserControl>

    Page.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    
    namespace DataGridBindingValidationTester
    {
       public partial class Page : UserControl
       {
          public Page()
          {
             InitializeComponent();
             Loaded += new RoutedEventHandler( Page_Loaded );
             TestDataGrid.BindingValidationError += 
                new EventHandler<ValidationErrorEventArgs>( TestDataGrid_BindingValidationError );
          }
    
          void TestDataGrid_BindingValidationError( object sender, ValidationErrorEventArgs e )
          {
             if ( e.Action == ValidationErrorEventAction.Added )
             {
                ( (Control) e.OriginalSource ).Background = new SolidColorBrush( Colors.Red );
                Output.Text = "Error: " + e.Error.Exception.Message;
             }
             else if ( e.Action == ValidationErrorEventAction.Removed )
             {
                ( (Control) e.OriginalSource ).Background = new SolidColorBrush( Colors.White );
             }
    
          }
    
          void Page_Loaded( object sender, RoutedEventArgs e )
          {
             List<TestData> tests = new List<TestData>();
    
             tests.Add( new TestData { Id = 1, Name = "A" } );
             tests.Add( new TestData { Id = 4, Name = "B" } );
             tests.Add( new TestData { Id = 2, Name = "C" } );
             tests.Add( new TestData { Id = 5, Name = "D" } );
             tests.Add( new TestData { Id = 3, Name = "E" } );
             tests.Add( new TestData { Id = 8, Name = "F" } );
             tests.Add( new TestData { Id = 7, Name = "G" } );
             TestDataGrid.ItemsSource = tests;
             
          }
       }
    }

    The key to why this should work is that the DataGrid's Cell Editing Template for Binding the ID (when the user is entering data) has a DataTemplate that uses a TextBox that is bound with both of the necessary properties,

    <DataTemplate>
        <TextBox Text="{Binding Id,
                        Mode=TwoWay,
                        NotifyOnValidationError=true,
                        ValidatesOnExceptions=true}" />
    </DataTemplate>

    In addition, the event handler is created in the class constructor and implemented in the code behind.

    TestDataGrid.BindingValidationError += 
       new EventHandler<ValidationErrorEventArgs>( TestDataGrid_BindingValidationError );
    
    void TestDataGrid_BindingValidationError( object sender, ValidationErrorEventArgs e )
    {
       if ( e.Action == ValidationErrorEventAction.Added )
       {
          ( (Control) e.OriginalSource ).Background = new SolidColorBrush( Colors.Red );
          Output.Text = "Error: " + e.Error.Exception.Message;
       }
       else if ( e.Action == ValidationErrorEventAction.Removed )
       {
          ( (Control) e.OriginalSource ).Background = new SolidColorBrush( Colors.White );
       }
    
    }

    The bug is that this does not work.  The reason this is not a bug but a SUBTIPUBNAAWTPE is this: what is actually causing this to fail is not that the event wouldn't be raised, but rather that by the time the error might be raised, the DataGrid has already shifted back from TextBox to TextBlock – and the properties are no longer set.

    (Okay, my snide answer was this: …it may not be a BindingValidation bug, but it is a Silverlight bug by any reasonable definition; or it is like saying that it isn’t a bug when your brakes fail because they were never really designed to stop the car if the car is on an actual road, though they work just great up  on the lift.  )

    More about this soon…. including a much more systematic review of DataGrid.

    [1] Alice in Wonderland – Public Domain – Project Gutenberg

    Posted by jesseliberty | 11 comment(s)
    Filed under:

    Sizing in Silverlight – Pixels and Stars

    SLLogoWords

    Virtually all measurements (width, height, etc.) are measured in Pixels in Silverlight… except when they're not.  

    Pixels

    When you are creating a shape or setting a margin, or filing in the width or height of a control the implicit unit is pixel.  Thus,

    <Button  Content="Button" Width="100" />
    <CheckBox  Content="CheckBox" Height="20" Width="75"/>
    <StackPanel Orientation="Horizontal" >
        <RadioButton Height="29" Width="106" Content="RadioButton1" />
        <RadioButton Height="29" Width="136" Content="RadioButton2" />
    </StackPanel>
    <ListBox Width="100" Height="100">
    </ListBox>
    <Slider Width="250" Height="25"/>
    <swc:Calendar Height="150" Width="200" />

    All the measurements here are pixels, from the width of the button to the height of the Calendar.

    Proportional (Star) Sizing

    There are two ways to set the height of a grid's row or the width of a grid's column. One is to use absolute sizing, and thus pixels; the other is to use proportional sizing. When you create a pair of rows by clicking on the margin in Blend, the default is not to create two rows with absolute sizes, but rather two rows whose size is defined relative to one another.  This is indicated in the art board with open locks and in the Xaml with asterisks after the height values.

    GridProportionalSpacing

    When row and height values are expressed using star sizing, the unit of measure is not pixels; they are proportional values. Thus, Blend has indicated that the top row is to be allocated 25% of the total height and the bottom row 75%

    If you click on both locks, you’ll change over to absolute heights, the locks will close, and the Heights will become 120 and 360 (no asterisks) respectively; now measured in pixels, but in the same proportions.

    Pop Quiz

    One of these things is not like the others:

    <Grid.RowDefinitions>
        <RowDefinition Height="0.25*" />
        <RowDefinition Height="0.75*" />
    </Grid.RowDefinitions>
    
    <Grid.RowDefinitions>
        <RowDefinition Height="100*" />
        <RowDefinition Height="300*" />
    </Grid.RowDefinitions>
    
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="300" />
    </Grid.RowDefinitions>

     

    -jesse

    Posted by jesseliberty | 13 comment(s)
    Filed under: ,

    Silverlight and Data

     

     

    Tim and I and many others have been discussing, off and on, the frequent requests for videos/tutorials/demos, etc. that show how to move data into and out of databases and display them in Silverlight.

    On the one hand, my response is that the very question reveals that we've not done a good enough job explaining the boundaries of Silverlight as a UI tier-framework; that once you're talking about creating (rather than consuming) a web service and once you're writing LINQ you are outside of Silverlight.

    On the other hand, I see two compelling counter arguments.

    #1 is that by showing the complete set of tiers and how they interact (SQL and whatever technology we choose to get the data in and out (e.g., Linq or  Astoria) and WCF to create a web service, and Silverlight consuming the web service, probably creating business objects, and a DataGrid in Silverlight to display the data, along with two way binding, we better establish where the actual boundaries of Silverlight lay and how Silverlight interacts with these other technologies.

    iStock_EngineXSmall

    #2 is that for most of our readers Tim and I may be "Silverlight Developer Community Program Mangers" but really we're just Microsoft techies. And as I wrote in a private correspondence "when I go into my Subaru dealer, I understand that one guy may be a transmission specialist but that doesn’t mean he can’t answer a simple question about how frequently I should change my oil.  If I feel it is clear that the explanation I’m asking for will take sitting down and getting into details and really call upon his specialty that is one thing, but if it is just a general Subaru question, then his answering “oh, I don’t do oil”  would probably infuriate me and it certainly wouldn’t help me understand where the transmission system ends and the engine system begins and how they both form part of the powertrain."

    So, after thinking about this quite a bit, I think we have to show the entire power train: from inside the SQL db through displaying it in a DataGrid, but with a clear emphasis on the Silverlight front-end and how and where you can learn more about the other enabling technologies for the other tiers.

    More to come, but I invite your feedback.

    -j

    Posted by jesseliberty | 21 comment(s)
    Filed under: ,

    Something New Coming – Pocket MFA

    My theory, based entirely on my own experience is that many developers would like to know just a bit more about design (not all developers, and not a lot more, just some developers, and just a bit more). Our reasons include:

    1. The bar has been set higher by Silverlight and other application development platforms that set high user expectations

    2. Some of us don't have access to professional designers, or don't have access early in our project

    3. Some of us are developing prototypes and no designer is involved but we want the prototype to look good enough that the design doesn't "get in the way."

    In short, we're putting our code in front of others, and while many folks can say they don't care what it looks like, the truth is that good looking (or at least good-enough looking) code makes a very different impact than poor looking applications.

    Thus, I am taking action. My goals are to provide this information to developers in what I'm calling the Pocket MFA  series. This is an entirely optional set of add-ons to the tutorials, videos, blog entries and other work I do. It will be optional and easy to skip, but my hope is that you'll find value in it. It is an experiment that will last through Q1 and then be reassessed.

    As a start, I'll be making recommendations on some background reading, but I'm happy to announce that one of our best designers will be adding a brief commentary to my forthcoming videos (at the end so you can skip it if you really don't want to know about this) detailing small changes that I could have made to improve the appearance of my application.

    These commentaries will run under 5 minutes, but collectively I hope to learn and I hope they will teach, the fundamentals that we can use to bring the appearance of our applications up that notch or two that can make a world of difference.

    There are three books that I typically state are indispensible to anyone creating software (The Design of Everyday Things, Why Software Sucks and Don't Make Me Think).  That said, if we're focusing on design, then I think we may want to start with this gem:

     

    And while it is not targeted at Silverlight 2, you may well want to get a leg up by watching Arturo's brilliant video from the Fire Starter series. Click on the image below to go to the Firestarter site, and then click on Arturo's tile (see arrows) to watch his video.

    FireStarter

    Posted by jesseliberty | 16 comment(s)
    Filed under: ,

    Liberty – Shill?

     

    Recommends2 Okay, I never thought this was an issue I was likely to face, but the folks in Marketing wanted to run this ad, and so I was faced with that interesting question of what we used to call “Selling Out.” (yeah, yeah, i work for Microsoft, so my radical friends would say that happened long ago!)

    And, actually, that was how I decided it was fine (and very ego enhancing I admit). That is, I work for Microsoft, and specifically in this job, because I don’t have to say anything I don’t believe; and this ad doesn’t ask me to say anything I don’t believe, and wouldn’t say – in fact I say it all the time. (In fact, come to think of it, I’m not getting paid for the ad so how can this be a sell out?  Hey! I wanna sell out, please?)

    I do recommend Expression Blend, heartily and with no hesitation to anyone writing Silverlight applications. In fact I did a video, Green Eggs and Blend on “why I gave up a 15 year commitment to working in a single Integrated Development Environment and came to discover I do so Like Expression Blend.”

    But…. since it is weird, I thought I’d post about it. Of course the biggest reaction may not be “how could you?” but rather, “who cares?”  That said, to the extent that anyone does; I thought I’d say out loud that here, as with Silverlight, C# and etc.; the enthusiasm comes before the recommendation, job, book or whatever.

    The picture of me, by the way, is by Rachel Liberty; age 12.  Nice shot.

    Posted by jesseliberty | 4 comment(s)
    Filed under:

    Did You Try to Attend A WebCast Today??

     

     

    Apparently a Web Cast cancellation sent out months ago did not reach some 34 loyal, innocent and now very frustrated users; to whom I sincerely apologize.

    iStock_SadGirlverySmall

    It was not my intention to leave you in limbo; in fact I didn't even know about the meeting until I received an email from one or two folks asking if something went wrong (nice of them to give the benefit of the doubt). There are no excuses, except to say that we tried carefully to inform everyone many weeks ago when we changed the schedule.

    There are two webcasts left on the schedule

    • Skinnable Custom Controls on November 12
    • Deep Zoom on December 17

    After that, I'm going to pull back from Webcasts and think long and hard about how to use that medium more effectively.

    In any case, if you were there, waiting, and wasting your time, I do apologize, and if you drop me a line and let me know, I'll see if I can't get you a pass to the on line version of Programming Silverlight once we're up on Safari as my way of apologizing.

    Silverlight Controls – Look Nicer, Taste Great

     

     

    In my earlier column i referred to the nice new look of the Silverlight 2 controls. I couldn't resist throwing together a very fast application (using Blend to lay  it out, and Visual Studio to bind the data) showing off a few of the controls.

    SL2Controls

    Not an ideal layout, but just enough to show the bit of extra polish that has been added to the controls at release.

    Happy Battle of Hastings Anniversary.

    -j

    Posted by jesseliberty | 12 comment(s)
    Filed under:

    Silverlight 2 Release Guide

    SLLogo

    As promised, Silverlight 2 is now not merely released, it is really and most sincerely released…

    If You Are A New Silverlight Programmer

    If you are taking this occasion to become a Silverlight programmer, welcome! Everything you need is here on the Get Started Page. I suggest you follow this order: download and install the areas marked (1), (2)  in the upper left corner, then skip down to Start Learning and read (1) Next mix (4) and (5) together and leaven with (2) and (3) as appropriate.  By the time you finish, we'll have a lot more for you and if you have questions, you'll get quick answers on the forum

    If you are already a Silverlight Programmer

    1. All your Beta code just broke. With luck, you were using the RC0 release and you have non-Beta code standing by ready to drop in. Now's the time to do it. If not, now's the time to get the new tools and update.

    2. What you need to start coding in Silverlight 2 – While there is quite a bit you can download, all you need is

    • Visual Studio SP1 or Visual Web Designer Express SP1
    • Silverlight Tools For Visual Studio
    • Microsoft Blend 2 Service Pack 1
    • Mac Runtime [optional]

    The combination of Blend 2 + Blend 2 SP1 is the updated Blend 2.5, and the Silverlight Tools + either VS SP1 or VWD SP1 is the complete Silverlight Development environment + the SDK + the documentation + the developer runtime + the debugger + the ASP.NET Server controls + the Project templates! 

    3. This is the last time Silverlight will not be backwards incompatible – from now on when we update, your code should continue to work. (at least, that's the plan)

    4. What's new, what changed?

    You'll find a lot of information on this in Scott Gu's Announcement which is very much worth reading. I'll be expanding on this in detail in coming posts, with an emphasis on reviewing the rich controls, and exploring some aspects of the base library such as Linq support, local data caching, network support and enhanced media support.

    You'll note that even the familiar controls look more polished; a lot of work went into their final default look – though as many of you know, every Silverlight control is ultimately lookless, subject to templating (skinning).

    Silverlight 2 brings the Silverlight Control Pack – with dozens of additional controls, and a promise of new controls being added continually over the next few months leading to a total of over 100. The first control pack will include the TreeView, DockPanel, WrapPanel, ViewBox, Expander, NumericUpDown, AutoComplete and more.  Each of these controls will be released with full source code and an OSI license that will give you permission to modify and extend and use the source for any purpose! …. (Sorry, I became disoriented for a moment).

    I will be covering each control in the Control Pack as it becomes available.   That is one of the areas I'll be focusing on this year and I'll be working closely with the Controls team to make sure you have the complete information as soon as it is available.

    Other changes include confirmation of our partnership with Soyatec to sponsor tool development for creating Silverlight apps using the cross platform Eclipse development environment. There is already a brief tutorial on building a Silverlight app with Eclipse available here.

    Silverlight 2 adds support for ADO.NET Data Services (Astoria), extended networking support, and new video codecs for high def video.  I'll review each of these and more in coming posts and videos.

    5. What about the Tutorials and Videos Already Posted

    We stayed up late and fixed them all, in most cases leaving the video intact but fixing up the code to ensure it will work fine with Silverlight 2. If you download any code and it won't work, please do let us know; but we've checked so you shouldn't have any problems. The tutorials have had all the code updated, and all the tutorial text has been updated (and look for two versions of the tutorials (one in VB and one in C#) to appear soon. All the code in my recent blog postings has been with RC0 so it should be fine, older blog postings may need a recompile, or even a tiny fix.

    6. Breaking Changes

    Yes, you want the latest Breaking Changes document, but most developers will find few breaking changes that affect their code (the one that kept hitting me was the changes to Content Presenter – easy to find and to fix) .

    7. Subscribe

    If you haven't already, I recommend subscribing to three or four Silverlight blogs (or 20!).  My personal priority order, to ensure you are up to date is:

    Silverlight 2 Releases Tomorrow

    SLLogo

    I'm very pleased to confirm that we'll be releasing Silverlight 2 tomorrow.

    eWeek has an article that mentions the release and our funding for an open-source project to create an Eclipse plug-in for Silverlight.  My personal opinion is I can't imagine using Eclipse for Silverlight development on the PC given the availability of Visual Studio…. but on the Mac, if/when such a thing is available… that would be very different. (Of course, this is a personal preference)

    ZDNet covers the story and mentions that Silverlight penetration is approaching 50% in some countries, and that during the Olympics, NBCOlympics.com, powered by Silverlight had 50 million unique visitors, 1.3 billion page views.  Here's what ZDNet has to say about the Eclipse announcement

    Microsoft is going to be working with Soyatec to bring Silverlight development capabilities to Eclipse, which in theory means that we could finally have Mac and possibly even Linux development tools for Silverlight. According to the press release this will also be free. A technology preview of the tool is available now

    Computer World's coverage includes these morsels

    Microsoft is also releasing for free a set of programming templates called the Silverlight Control Pack under its Microsoft Permissive License, as well as the technical specification for Silverlight's Extensible Application Markup Language (XAML) vocabulary via Microsoft's Open Specification Promise…[and] letting users of the free Visual Web Developer 2008 Express Edition write Silverlight applications

    Data Binding – Data Validation

    SLLogoWords

    The third and final Data Binding topic I'd like to cover for now is Data Validation. I'll modify the code discussed yesterday we're going to validate the Quantity on Hand field, already marked as two-way (that is, the user can enter a new value and it is stored in the underlying business object – the current book).

     DataBindingArchitectureTwoWay

    Our goal is to capture and handle two types of errors

    • Exceptions thrown from the Binding Engine
    • Exceptions thrown from the Binding Source

    An example of an exception the Binding Engine would throw would be were the user to enter letters where an integer value is expected

    Binding Source exceptions would be created by the author of the Binding Source class (the Book Class) to ensure data integrity. In our case, we might throw an exception if we are handed a negative value for Quantity on hand. Thus, we might modify the set accessor for Quantity on hand as follows,

     

       1: public class Book : INotifyPropertyChanged
       2: {
       3:    private int quantityOnHand;
       4:      // Snip 
       5:  
       6:    public int QuantityOnHand
       7:    {
       8:       get { return quantityOnHand; }
       9:       set
      10:       {
      11:          if ( value < 0 )
      12:          {
      13:             throw new Exception( "Quantity on hand cannot be negative!" );
      14:          }
      15:          quantityOnHand = value;
      16:          NotifyPropertyChanged( "QuantityOnHand" );
      17:       }       // end set
      18:    }
      19:  

    To manage both of these types of errors need to take 3 steps

    1. Identify the error handler either in the control or higher in the visiblity hierarchy (e.g., a container; in this case the grid that contains the text box)
    2. Set NotifyOnValidationError and ValidateOnException to true. The latter tells teh Binding Engine to create a validation error event when an exception occurs. The former tells the Binding Engine to raise teh BindingValidationError event when a validation error occurs.
    3. Create the event handler named in step 1

    Identify the Handler

    We'll put the identifier of the handler in the grid so that it may be shared by all the controls within the grid.

    <Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError" >

    Set NotifyOnValidationError and ValidateOnException

    These are set as part of the binding syntax in the control itself,

       1: <TextBox x:Name="QuantityOnHand"   
       2:     Text="{Binding Mode=TwoWay, Path=QuantityOnHand, 
       3:         NotifyOnValidationError=true,  ValidatesOnExceptions=true }"
       4:     VerticalAlignment="Bottom"
       5:     HorizontalAlignment="Left"
       6:     Height="30" Width="90"
       7:     Grid.Row="4" Grid.Column="1" />

    Create the Event Handler

    The event handler named in the grid is implemented in the associated code-behind file,

       1: public partial class Page : UserControl
       2: {
       3:    private bool clean = true;  // new flag
       4:  
       5:    void Change_Click( object sender, RoutedEventArgs e )
       6:    {  // if not clean, don't change books
       7:       if ( !clean )
       8:          return;
       9:       // snip
      10:    }
      11:  
      12:    private void LayoutRoot_BindingValidationError( 
      13:       object sender, ValidationErrorEventArgs e )
      14:    {
      15:       if ( e.Action == ValidationErrorEventAction.Added )
      16:       {
      17:          QuantityOnHand.Background = new SolidColorBrush( Colors.Red );
      18:          clean = false;
      19:       }
      20:       else if ( e.Action == ValidationErrorEventAction.Removed )
      21:       {
      22:          QuantityOnHand.Background = new SolidColorBrush( Colors.White );
      23:          clean = true;
      24:       }
      25:    }

    Delegation of Responsibility

    Notice the careful delegation of responsibility. 

    The Binding class knows that it is handling validation and some first approximation of validity (integers aren't text) but it turns to the Book class for further validation (e.g, Quantity on Hand can't be negative). If it finds that the value is invalid it raises an event, but it is up to the UI to handle that event and decide how to display that there is invalid data to the user.

    Page.xaml in this case manages that by refusing to move to the next book and turning the input box red. There are a thousand other things it could do, but the key here is separation of responsibility. The UI doesn't know why the data is invalid, only that it is.

    Here is what it looks like when you enter invalid data and hit the Change Book button

    InvalidData

    As you can see, the entry box turns red, and the book does not change until the user fixes the data entered.

    For those of you who want to copy and paste, here are all the changes

    // page.xaml.cs
    
    private bool clean = true;
    
    
    private void LayoutRoot_BindingValidationError( 
       object sender, ValidationErrorEventArgs e )
    {
       if ( e.Action == ValidationErrorEventAction.Added )
       {
          QuantityOnHand.Background = new SolidColorBrush( Colors.Red );
          clean = false;
       }
       else if ( e.Action == ValidationErrorEventAction.Removed )
       {
          QuantityOnHand.Background = new SolidColorBrush( Colors.White );
          clean = true;
       }
    }
    
    
    
    // page.xaml
    
    <Grid x:Name="LayoutRoot" Background="White" BindingValidationError="LayoutRoot_BindingValidationError" >
    
    <TextBox x:Name="QuantityOnHand"   
        Text="{Binding Mode=TwoWay, Path=QuantityOnHand, 
            NotifyOnValidationError=true,  ValidatesOnExceptions=true }"
        VerticalAlignment="Bottom"
        HorizontalAlignment="Left"
        Height="30" Width="90"red
        Grid.Row="4" Grid.Column="1" />
    
    
    // book.cs
    
    public int QuantityOnHand
    {
       get { return quantityOnHand; }
       set
       {
          if ( value < 0 )
          {
             throw new Exception( "Quantity on hand cannot be negative!" );
          }
          quantityOnHand = value;
          NotifyPropertyChanged( "QuantityOnHand" );
       }       // end set
    }
    Posted by jesseliberty | 17 comment(s)
    Filed under: ,
    Next