Feed Icon  

Contact

  • Bryant Likes
  • Send mail to the author(s) E-mail
  • twitter
  • View Bryant Likes's profile on LinkedIn
  • del.icio.us
Get Microsoft Silverlight
by clicking "Install Microsoft Silverlight" you accept the
Silverlight license agreement

Hosting By

Hot Topics

Tags

Open Source Projects

Archives

Ads

A “Default Command” for Silverlight

Posted in Avanade | Silverlight at Monday, 28 September 2009 07:23 Pacific Daylight Time

The current Silverlight application that I’m building has a Login view. One of the things that bugged me when I started using the application is that you would have to click the Login button after typing your password. I wanted to duplicate the default button behavior of HTML forms where when you hit the enter key it would trigger the default button on the form. I did some googling on the subject and came across this post by Patrick Cauldwell which is one way to solve the problem. However, in my case I had a username Textbox, a password Passwordbox, and a company Combobox and didn’t want to specify the button for each control.

So I create a simple solution of creating a content control that attaches to all the KeyUp events of all the child FrameworkElements in the content. To do this I used the FindChildren<T> extension method from the Avanade Silverlight Accelerator which is a toolkit we use internally at Avanade to speed up Silverlight development. The ContentControl exposes a DefaultCommand property which you then bind to the ICommand property on your ViewModel.

Below is a trimmed down example of the Login view. I’m using a variant of the RelayCommand/DelegateCommand as the LoginCommand here (see Laurent’s post on the RelayCommand for a good overview of Commands in Silverlight).

<ctrls:FormControl DefaultCommand="{Binding LoginCommand}">   
  <TextBox Text="{Binding Username, Mode=TwoWay}" />
  <PasswordBox Password="{Binding Password, Mode=TwoWay}" />
  <Button IsEnabled="{Binding LoginEnabled}" 
          cmds:ButtonClickCommand.Command="{Binding LoginCommand}" 
          Content="Login" />
</ctrls:FormControl>

There are many other things you could add to this but this is all the functionality that I needed and I decided to keep it simple. Download the class file (plus the extension method) below. Let me know if you find it useful!

Faking the Initialized Event in Silverlight

Posted in Silverlight at Tuesday, 24 March 2009 09:24 Pacific Standard Time

This is another nugget of gold gleaned from the Climbing Mt Avalon workshop, although I believe this one came from Jonathan Russ. He was talking about a bunch of threading tricks in WPF and showed how if you wanted to run some code after everything was initialized you could use the BeginInvoke method of the Dispatcher object. Since there are many places in my code where I want to execute something when the control loads, but only once (since the loaded event gets fired whenever the object gets re-added to the visual tree) I end up writing a lot of code like:

public partial class Page : UserControl
{
    private bool initialized = false;

    public Page()
    {
        InitializeComponent();
        Loaded += new RoutedEventHandler(Page_Loaded);
    }

    void Page_Loaded(object sender, RoutedEventArgs e)
    {
        if (!initialized)
        {
            // do some initialization work
            initialized = true;
        }
    }

}

This works, but it isn’t perfect and there seems to be a lot of issues with the timing of the loaded event. So based on what Jonathan was saying, you could instead just put a call into BeginInvoke in the contructor like so:

public partial class Page : UserControl
{
    public Page()
    {
        InitializeComponent();
        Dispatcher.BeginInvoke(Initialized);
    }

    private void Initialized()
    {
        // do some initialization work
    }
}

So what is this actually doing? BeginInvoke puts a message in the message pump that is running under the covers of everything (note: I’m not a C++ programming so I don’t really fully understand message pumps so this is an over simplification). Because it is last in line in the queue of messages to process, it gets executed after all the other initialization code which has already lined up. If you debug this you will see it actually gets called after the Loaded event gets called. However, this code is the first thing to execute once everything has been loaded and setup which is usually when I want my code to execute.

So this is a much better way to handle initialization code since you aren’t adding event handlers that really only need to fire once and it executes once everything is fully initialized.

Animation Hack Using Attached Properties in Silverlight

Posted in Silverlight | UX at Monday, 23 March 2009 07:27 Pacific Standard Time

In my last post I blogged about using Attached Properties to get around the limitation that only Dependency Properties can be animated. One astute commented noted that he was guessing this could be applied to animations as well and the answer is yet it can. However, it requires one extra step that makes it a little less appealing.

Also I mentioned in my last post, I got this idea from the Climbing Mt Avalon workshop at MIX which has now been posted online and I would recommend watching if you’re doing Silverlight or WPF work. And now on to the code…

Typically if you want to animating something like the width of a grid in a column that isn’t animatable either because it isn’t a double, color, or another easily animatable type, then you would declare a dependency property on your own host class, usually a UserControl, and then animate that instead. A good example is this blog post on the subject which is what I’ve referred to many times.

However, if we take the attached property route instead of putting the code in our user control, we could declare our own attached property to do the work for us. Here is a simple example:

public static class Attachments
{

    public static readonly DependencyProperty ColumnWidthProperty =
            DependencyProperty.RegisterAttached("ColumnWidth", 
            typeof(double), typeof(Attachments), 
            new PropertyMetadata(
                new PropertyChangedCallback(OnColumnWidthChanged)));

    public static void SetColumnWidth(DependencyObject o, double value)
    {
        o.SetValue(ColumnWidthProperty, value);
    }

    public static double GetColumnWidth(DependencyObject o)
    {
        return (double)o.GetValue(ColumnWidthProperty);
    }

    private static void OnColumnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ColumnDefinition)d).Width = new GridLength((double)e.NewValue);
    }

}

Once we have this code we can now simply animate the attached property like so:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SilverlightApplication1"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.Resources>
            <Storyboard x:Name="expandBlue">
                <DoubleAnimation Storyboard.TargetName="blue"
                                 To="300" Duration="0:0:1" />
                <DoubleAnimation Storyboard.TargetName="red"
                                 To="100" Duration="0:0:1" />
            </Storyboard>
            <Storyboard x:Name="expandRed">
                <DoubleAnimation Storyboard.TargetName="red"
                                 To="300" Duration="0:0:1" />
                <DoubleAnimation Storyboard.TargetName="blue"
                                 To="100" Duration="0:0:1" />
            </Storyboard>
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="blue" local:Attachments.ColumnWidth="200" />
            <ColumnDefinition x:Name="red" local:Attachments.ColumnWidth="200"/>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.Column="0" Fill="Blue" MouseLeftButtonDown="Blue_MouseLeftButtonDown" />
        <Rectangle Grid.Column="1" Fill="Red" MouseLeftButtonDown="Red_MouseLeftButtonDown"/>
    </Grid>
</UserControl>

Unfortunately if you try the above code (after adding in the mouse event handlers) it won’t work. Why not? Well there seems to be an issue with animating custom attached properties when setting the target property directly in code (actually you’ll notice I left that out above. However, there is a way around it which I found over on Ed’s blog which is to set the target property in code. So here is the code behind with the work around:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        Storyboard.SetTargetProperty(expandBlue.Children[0], new PropertyPath(Attachments.ColumnWidthProperty));
        Storyboard.SetTargetProperty(expandBlue.Children[1], new PropertyPath(Attachments.ColumnWidthProperty));
        Storyboard.SetTargetProperty(expandRed.Children[0], new PropertyPath(Attachments.ColumnWidthProperty));
        Storyboard.SetTargetProperty(expandRed.Children[1], new PropertyPath(Attachments.ColumnWidthProperty));
    }

    private void Blue_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        expandBlue.Begin();
    }

    private void Red_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        expandRed.Begin();
    }
}

Once we set the target property via code, then everything works great. However, that is a pain and makes things a lot less clean. But still I think this is a useful approach to animating the properties that are not easily animatable.

Styling Hack Using Attached Properties in Silverlight

Posted in Silverlight at Wednesday, 18 March 2009 09:08 Pacific Standard Time

I need to find the forum post where this question was asked, but I’ll have to do that later since I’m at MIX09 and searching the forums is low on my list. But I wanted to share a cool hack that I came across in the Climbing Mt Avalon (it was definitely a climb, not a hike).  One of the many cool things that was shared was a tidbit by Jaime Rodriguez about using Attached Properties.

The question in the forums was how you can style the VerticalScrollBarVisibility property on a TextBox. The problem is that since this property isn’t a DependencyProperty  so it can’t be styled. You can test this out by trying the following Xaml:

   1: <UserControl x:Class="Attachment.Page"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     Width="400" Height="300">
   5:     <UserControl.Resources>
   6:         <Style TargetType="TextBox" x:Key="test">
   7:             <Setter Property="FontSize" Value="24" />
   8:             <Setter Property="VerticalScrollBarVisibility" Value="Visible" />
   9:         </Style>
  10:     </UserControl.Resources>
  11:     <Grid x:Name="LayoutRoot" Background="White">
  12:      <TextBox Text="This is a test" Style="{StaticResource test}" />
  13:     </Grid>
  14: </UserControl>

If you try to run this it will fail. So how can we set this property in style? Well, a trick you can use is to set your own attached property and then have the property set the VerticalScrollBarVisibility property on the TextBox for you. Here is a very quick example that I cooked up (using Robby’s code snippet):

   1: namespace Attachment
   2: {
   3:     public static class Attachments
   4:     {
   5:         public static readonly DependencyProperty MyVsbvProperty =
   6:             DependencyProperty.RegisterAttached("MyVsbv", 
   7:                 typeof(ScrollBarVisibility), 
   8:                 typeof(Attachments), 
   9:                 new PropertyMetadata(OnMyVsbvChanged));
  10:  
  11:         public static void SetMyVsbv(DependencyObject o, ScrollBarVisibility value)
  12:         {
  13:             o.SetValue(MyVsbvProperty, value);
  14:         }
  15:  
  16:         public static ScrollBarVisibility GetMyVsbv(DependencyObject o)
  17:         {
  18:             return (ScrollBarVisibility)o.GetValue(MyVsbvProperty);
  19:         }
  20:  
  21:         private static void OnMyVsbvChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  22:         {
  23:             ((TextBox)d).VerticalScrollBarVisibility = (ScrollBarVisibility)e.NewValue;
  24:         }
  25:     }
  26: }

Very unintuitive name and my casts could be bad since there are no type checks, just an example. So here when the attached property is changed we change the property on the TextBox that the property is declared on. So if we change our style to use the attached property instead of the actual property it will work:

   1: <UserControl x:Class="Attachment.Page"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:local="clr-namespace:Attachment"
   5:     Width="400" Height="300">
   6:     <UserControl.Resources>
   7:         <Style TargetType="TextBox" x:Key="test">
   8:             <Setter Property="FontSize" Value="24" />
   9:             <Setter Property="local:Attachments.MyVsbv" Value="Visible" />
  10:         </Style>
  11:     </UserControl.Resources>
  12:     <Grid x:Name="LayoutRoot" Background="White">
  13:                 <TextBox Text="This is a test" Style="{StaticResource test}" />
  14:             </Grid>
  15: </UserControl>

 

So there you have it. If you need to style a property on a control that isn’t a dependency property you can use this method to get around that limitation. There are a bunch of other uses for this that I’ll be blogging when I have another minute.

Enjoy!

Silverlight Streaming Utility Classes

Posted in Silverlight at Wednesday, 11 March 2009 08:36 Pacific Standard Time

Yesterday I was working through another question in the Silverlight Forums about how to upload video to Silverlight Streaming via code. At first I tried to reference the Video.Show application, but there is a lot of code there and it doesn’t help if you just want to upload a bunch of videos to the same application. So I ended up taking some of the code from Video.Show and some of the code from the SDK/API and created a very simple Utility class to help with the process.

You can download the code on the Code Gallery site. It is very simple in that there is no error handling and I didn’t create a Silverlight version yet. I did implement GET, POST, PUT, MKCOL, and DELETE as well as creating the functionality to package a bunch of videos into a single zip which can be posted all at once.

A few examples from the code, first creating a directory and PUTting a file in it:

WebDavClient client = new WebDavClient("Your AppID", "Your Key"); 
// get those from http://silverlight.live.com
 
client.CreateFolder("MyVideos");
client.PutFile("MyVideos","C:\\videos\reallyCoolVideo.wmv");

Next, packaging up a bunch of videos and POSTing the zip as an application:

WebDavClient client = new WebDavClient("Your AppID", "Your Key"); 
// get those from http://silverlight.live.com
 
client.PackageAndPostFiles("MyVideos","C:\\videos\firstCoolVideo.wmv","C:\\videos\anothercoolVideo.wmv");

Let me know if you’d like to see a Silverlight version (be easy to implement) or if there are any other features you’d like added.

Enjoy!