Skip to content
Archive of posts filed under the Silverlight category.

Silverlight’s KeyUp Event and Backspace

Surprisingly enough, I never ran into this issue, event though I worked with Silverlight for three years now.  The specific issue is that some keyboard events are not echoed in KeyUp events.  For example, if you subscribe to KeyUp in a textbox and you hit Backspace key, KeyUp event does not fire.  This is quite inconsistent in my opinion.  The reason this happens is because the event is trapped by Silverlight, processed independently and marked as Handled, so it does not bubble up to the textbox.  You can see some workarounds on the internet, most involving inheriting from a textbox.  I do not particularly like this answer because it involves a lot of work on my part.

So, I wanted to blog about functionality in Silverlight that is not widely known, but I used on a few occasions.  Specifically, it allows developers to receive events that have been marked as handled elsewhere.

I am referring to AddHandler function.  Here is typical syntax:

Element.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(Element_KeyDown), true);

Element.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(Element_KeyUp), true);

The key is the last parameter to AddHandler.  It signals to Silverlight to inform you of the events even though they have been marked as handled.  You would use this call instead of

Element.KeyUp += Element_KeyUp;

You can read more about this function here.

Enjoy.

Thanks.

Post to Twitter

Update for WP7 Database

I have had a small number of requests to enhance the functionality of my Windows Phone 7 database project on CodePlex.  In light of Mango release for WP 7 that will contain SQL CE database, I think that my project will likely be used less in just a few months.  The reason being is that once the users update, the reason to use Isolated storage to persist data becomes less appealing.  I am not knocking on my own project, I am just recognizing the reality.  Having said that, the database will likely still be in use for a while, since we have to wait for the actual phone users to update the version, which cannot be done via 3G, you have to use Zune to update.  Because of that, I think, I decided to implement the most request feature, specifically named tables.  In other words, right now you can create a table in my database and give it a type of data to store, such as :

db.CreateTable<Person>();

 

What named tables allow you to do, is horizontally partition your data by allowing multi0ple tables to store the same type, such as:

string name2 = "p2";
Database db = Database.CreateDatabase("test"
);
db.CreateTable<
Person
>(name1);

 

So, the syntax pretty much remains the same, so anywhere you used to refer to db.Table<T>, you can now also use db.Table<T>(tableName).  This includes all functions, such as adding of rows and querying.

db.Table<Person>(name1).Add(NewRandomPerson());

 

Nothing else changes.  One thing to notice, that this is pretty deep change that required me to touch a lot of code and test legacy data to ensure it opens properly.  As always, I did my due diligence, as you can gather from the tiny number of reported issues in over a year of usage.  Nevertheless, I encourage everyone to thoroughly test your applications.  You can open up my test project and see how I tested legacy data by looking at the method NamedTablesLegacyTest in my test page in test project.  As a result, I am going to publish this release under alpha version until I get some feedback that is sufficient enough to warrant beta status.

I made another small change, making DoesTableExist method public.

Enjoy.

Thank you.

Post to Twitter

Silverlight and Self-Hosted WCF

I have been working on a project that is based on Silverlight.  It is a large application that performs a variety of tasks, but also needs local access.  Basically, it needs access to scanner in order to scan and upload documents up to the data store.  I had an idea to create a WPF tray application that hosts a WCF Service that Silverlight application can talk to.  Because of WCF restrictions in Silverlight, you have to enable cross domain access in self-hosted WCF service.  There is a variety of posts on the subject, so I am not going to rehash the steps.  You can for example ready about that here.

I thought I came up with a pretty clean solution, and it got tested and worked great.  However, when we deployed it to a customer computers, we had intermittent problems with it.  It worked on soma machines, but did not on others.  We were trapping the errors, and it was reported as cross domain error even though we had all the correct code there to make it work.  Quite a puzzle.  One specific client was running IE 6, and our application was using https.  I pondered on the topic for a while, and on a hunch I added our site to the list of trusted sites in IE.  Voila, the error went away.

I wanted to blog about it, because I could not find anything on the internet that reports the same issue and the same fix.

Thanks.

Post to Twitter

More Changes to Calendar Control for WP 7

In the spirit of further improving my calendar control for Windows Phone 7, I added ability to show week number in the first column of the calendar control.

image

As you can see, the very first column can show week number,.  If course, I cannot break existing functionality, so the feature is disabled by default.  You can enable it by setting appropriate property on calendar control, called WeekNumberDisplay.  It has three options:


namespace WPControls
{
 
   
/// <summary>

   
/// Option of how to display week numbers in the calendar
   
/// </summary>
   
public enum WeekNumberDisplayOption
    {
       
/// <summary>
       
/// Do not show week number
       
/// </summary>
        None = 0,
       
/// <summary>
       
/// Show week number starting with start of the year
       
/// </summary>
        WeekOfYear = 1,
       
/// <summary>
       
/// Show week number starting with start of month
       
/// </summary>

        WeekOfMonth = 2
    }
}

 

So, you have options to show week of the year, week of the month or none.  Week of the month is simply number that starts with 1.  As far as week of the year goes, I am using built in functionality to properly determine this using localization rules as follows.

var systemCalendar = System.Threading.Thread.CurrentThread.CurrentCulture.Calendar;
weekNumber = systemCalendar.GetWeekOfYear(
  item.ItemDate,
  System.Threading.
Thread
.CurrentThread.CurrentCulture.DateTimeFormat.CalendarWeekRule,
  System.Threading.
Thread
.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek);

 

You can use this code any time you need to determine week number.

You can visit the home page for calendar control to download the latest source code.

http://wpcontrols.codeplex.com/

Thank you and keep the suggestions coming.

Post to Twitter

Update to Calendar Control for Windows Phone 7

Today due to numerous requests (technically one request from one person Smile), I updated my CodePlex project for calendar control for Windows Phone 7 – http://wpcontrols.codeplex.com/.

I added gesture support to the project.  You can now swipe (flick) from side to side to increment or decrement month, and swipe top to bottom and back to increment or decrement year.

I thought it was a very good enhancement idea that feels very natural to me to support on Windows phone.  I used XNA libraries to enable this support, and it only required a few lines of code.  To enable support you will need to set property on the calendar control – EnableGestures – to true.

Please let me know if you have any feedback.

Thanks.

Post to Twitter

More on Markup Extensions in Silverlight 5

In my previous post I showed how to write a simple mark up extension.  I also noticed that not too many folks are aware of the fact that you can obtain a lot of information about how markup extension is used in XAML from the provider object.  I am going to demonstrate how to do this.  I will write an extension that would invoke a method on view model when a button is clicked by “binding” directly to Click event of the button.

Frist, we have to know more about the object we are using mark up extension on.  I am going to call mine EventToMethod.  Here is what the class looks like

using System;

using System.Reflection;

using System.Windows;

using System.Windows.Markup;

using System.Xaml;

 

namespace SL5Features.Extensions

{

  /// <summary>

  /// Extension that invokes a specified method when an event occurs.

  /// </summary>

  public class EventToMethod : FrameworkElement, IMarkupExtension<Delegate>

  {

    /// <summary>

    /// method handle that will be invoked

    /// </summary>

    private MethodInfo executeMethod = null;

 

    /// <summary>

    /// Main method required to be implemented by mark up extension

    /// </summary>

    /// <param name="serviceProvider">Service provider</param>

    /// <returns>Event delegate</returns>

    public Delegate ProvideValue(IServiceProvider serviceProvider)

    {

      // obtain value target provider and get mark up extension’s target from it

      var target =

        (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

 

      // since we are bound to an event, we are getting EventInfo object

      EventInfo prop = target.TargetProperty as EventInfo;

      // test to see what type of event we are getting

      if (prop.EventHandlerType.Equals(typeof(RoutedEventHandler)))

      {

        // create delegate for routed event and return it

        return new RoutedEventHandler(RoutedHandler);

      }

      else

      {

        //create delegate for regular event and return it

        return new EventHandler(RegularHandler);

      }

    }

 

    /// <summary>

    /// Routed event handler delegate to invoke in response to routed event

    /// </summary>

    /// <param name="sender"></param>

    /// <param name="args"></param>

    public void RoutedHandler(object sender, RoutedEventArgs args)

    {

      RegularHandler(sender, args);

    }

 

    /// <summary>

    /// Event handler to invoke in response to plain vanilla event

    /// </summary>

    /// <param name="sender"></param>

    /// <param name="args"></param>

    public void RegularHandler(object sender, EventArgs args)

    {

      if (executeMethod == null)

      {

        Type type = ViewModel.GetType();

        executeMethod = type.GetMethod(MethodName);

      }

      executeMethod.Invoke(ViewModel, new object[] { });

    }

 

    /// <summary>

    /// Name of the method to invoke when an event is invoked, such as button click

    /// </summary>

    public string MethodName

    {

      get { return (string)GetValue(MethodNameProperty); }

      set { SetValue(MethodNameProperty, value); }

    }

    public static readonly DependencyProperty MethodNameProperty =

        DependencyProperty.Register(

        "MethodName",

        typeof(string),

        typeof(EventToMethod),

        new PropertyMetadata(null));

 

    /// <summary>

    /// View model to invoke

    /// </summary>

    public Object ViewModel

    {

      get { return (Object)GetValue(ViewModelProperty); }

      set { SetValue(ViewModelProperty, value); }

    }

 

    public static readonly DependencyProperty ViewModelProperty =

        DependencyProperty.Register(

        "ViewModel", typeof(Object),

        typeof(EventToMethod),

        new PropertyMetadata(null));

 

  }

}

 

I documented properties, etc…  The basic idea is to get button (or any other) object from the provider, get event information, then create a delegate for that event and return it, just like any other mark up extension must return a value.  I added ViewModel and MethodName properties so that I can get event handle from ViewModel based on event name.  If you bind your mark up extension to a property on a control, TargetProperty will contain PropertyInfo object.

XAML could not look simpler:

 

<ResourceDictionary

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:models="clr-namespace:SL5Features.Models"

   xmlns:ext="clr-namespace:SL5Features.Extensions">

 

  <DataTemplate DataType="models:Person">

    <Grid>

      <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="7"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="7"/>

        <RowDefinition Height="Auto"/>

      </Grid.RowDefinitions>

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="Auto"/>

        <ColumnDefinition Width="7"/>

        <ColumnDefinition Width="*"/>

      </Grid.ColumnDefinitions>

     

      <TextBlock Text="First Name:" 

                Grid.Column="0" Grid.Row="0" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"

                Foreground="Red"/>

     

      <TextBlock Text="Last Name:" 

                Grid.Column="0" Grid.Row="2" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"

                Foreground="Red"/>

     

      <TextBox Text="{Binding Path=FirstName, Mode=TwoWay}"

              Grid.Column="2" Grid.Row="0"

              Background="Yellow"/>

     

      <TextBox Text="{Binding Path=LastName, Mode=TwoWay}" 

              Grid.Column="2" Grid.Row="2"

              Background="Yellow"/>

 

      <Button Content="Save" HorizontalAlignment="Left" 

             Grid.Row="4" Grid.Column="0"

             Click="{ext:EventToMethod 

                 ViewModel={Binding ElementName=LayoutRoot, Path=DataContext}, 

                 MethodName=RunIt}"/>

    </Grid>

  </DataTemplate>

</ResourceDictionary>

 

As you can see, I am binding button’s click method via my mark up extension.  Now, in my view model I just need to declare RunIt method, and that is it:

using SL5Features.Models;

using System.Windows;

 

namespace SL5Features.ViewModels

{

  public class PersonViewModel : ViewModelBase<Person>

  {

    public PersonViewModel()

    {

      Model = new Person() { FirstName = "Sergey", LastName = "Barskiy" };

    }

 

    public void Run(object parameter)

    {

      MessageBox.Show("Run");

    }

 

    public void RunIt()

    {

      MessageBox.Show("RunIt");

    }

 

    public bool CanRun(object parameter)

    {

      return true;

    }

  }

}

 

I added all the functionality to the solution from the previous post, but I am using alternate template for this implementation.  Too see the end result, just add ?Template=Alt to the query string when you run the app. 

To summarize, the idea is the same as my previous post – eliminate the need to create commands in my view model.

 

You can download updated solution here.

Thanks.

Post to Twitter

Markup Extensions in Silverlight 5

Another cool feature available in Silverlight 5 is markup extensions.  The idea behind the feature is ability to allow developers to supply values to XAML parser at the time it parses visual tree.  In other words, once parser finds a markup extension in XAML, it will create an instance of it, set any properties that the extension might have, then call ProvideValue method that will return a value of the type that the property that markup extension supports expects.  For example, I am writing a markup extension to supply an ICommand to the button, my XAML would looks like the following:

      <Button Content="Save" HorizontalAlignment="Left" 

             Grid.Row="4" Grid.Column="0"

             Command="{ext:CommandMarkupExtension 

                 ViewModel={Binding ElementName=LayoutRoot, Path=DataContext}, 

                 ExecuteMethodName=Run, 

                 CanExecuteMethodName=CanRun}"/>

 

So, in this example for markup extension I am writing a command extension.  As you can see in the XAML above, my extension takes three parameters: ViewModel to invoke, execute and can execute method names.  This way I can de-clutter my view model by removing all the command instantiation code, and just write the two methods I need.  The code in this extension is very easy – just a handful of dependency properties and interface implementation for IMarkupExtension:

using System;

using System.Windows;

using System.Windows.Input;

using System.Xaml;

 

namespace SL5Features.Extensions

{

  public class CommandMarkupExtension : FrameworkElement, IMarkupExtension<ICommand>

  {

 

    public Object ViewModel

    {

      get { return (Object)GetValue(ViewModelProperty); }

      set { SetValue(ViewModelProperty, value); }

    }

 

    public static readonly DependencyProperty ViewModelProperty =

        DependencyProperty.Register(

        "ViewModel", typeof(Object),

        typeof(CommandMarkupExtension),

        new PropertyMetadata(null));

 

    public string ExecuteMethodName

    {

      get { return (string)GetValue(ExecuteMethodNameProperty); }

      set { SetValue(ExecuteMethodNameProperty, value); }

    }

    public static readonly DependencyProperty ExecuteMethodNameProperty =

        DependencyProperty.Register(

        "ExecuteMethodName",

        typeof(string),

        typeof(CommandMarkupExtension),

        new PropertyMetadata(null));

 

 

 

    public string CanExecuteMethodName

    {

      get { return (string)GetValue(CanExecuteMethodNameProperty); }

      set { SetValue(CanExecuteMethodNameProperty, value); }

    }

 

    public static readonly DependencyProperty CanExecuteMethodNameProperty =

        DependencyProperty.Register(

        "CanExecuteMethodName",

        typeof(string),

        typeof(CommandMarkupExtension),

        new PropertyMetadata(null));

 

    public ICommand ProvideValue(IServiceProvider serviceProvider)

    {

      ReflectionCommand command =

        new ReflectionCommand(ViewModel, ExecuteMethodName, CanExecuteMethodName);

      return command;

    }

  }

}

 

To support the extension I need to write a command object that would actually implement ICommand.  This class is pretty trivial, so I am not commenting it much:

using System;

using System.Reflection;

using System.Windows;

using System.Windows.Input;

 

namespace SL5Features.Extensions

{

  public class ReflectionCommand : ICommand

  {

 

    private MethodInfo canExecuteMethod = null;

    private MethodInfo executeMethod = null;

    private object viewModel = null;

 

    private ReflectionCommand() { }

 

    public ReflectionCommand(

      object viewModel,

      string executeMethodName,

      string canExecuteMethodName)

    {

      this.viewModel = viewModel;

      Type type = viewModel.GetType();

      if (!string.IsNullOrEmpty(canExecuteMethodName))

      {

        this.canExecuteMethod = type.GetMethod(canExecuteMethodName);

      }

      this.executeMethod = type.GetMethod(executeMethodName);

 

    }

 

    public void Execute(object parameter)

    {

      executeMethod.Invoke(viewModel, new[] { parameter });

    }

 

    public bool CanExecute(object parameter)

    {

      if (viewModel != null && canExecuteMethod != null)

      {

        return (bool)canExecuteMethod.Invoke(viewModel, new[] { parameter });

      }

      else

      {

        return true;

      }

    }

 

 

    public event EventHandler CanExecuteChanged;

 

    public void RaiseCanExecuteChanged()

    {

      if (CanExecuteChanged != null)

      {

        CanExecuteChanged(this, EventArgs.Empty);

      }

    }

 

 

  }

}

 

So, far it is pretty easy.  Now, all I have to do is add Run and CanRun method on my view model that my command will invoke:

using SL5Features.Models;

using System.Windows;

 

namespace SL5Features.ViewModels

{

  public class PersonViewModel : ViewModelBase<Person>

  {

    public PersonViewModel()

    {

      Model = new Person() { FirstName = "Sergey", LastName = "Barskiy" };

    }

 

    public void Run(object parameter)

    {

      MessageBox.Show("Run");

    }

    public bool CanRun(object parameter)

    {

      return true;

    }

  }

}

 

Hopefully, I demonstrated the power of markup extension for you.  The goal of using them to me is reduction of the amount of code elsewhere in the system, since you will obviously have to write more XAML.  Of course, I am sure Blend 5 will support mark up extensions, so potentially you can just drag my extension on top of the button and setup a few properties in properties window.  You will also see a number of demos where an extension is used to support localization, which seems pretty intuitive use of the feature. Bottom line is: I love getting new features that make my job easier by allowing me to write less code and re-use more of the code written.

 

You can download the example here.

Thanks.

Post to Twitter

Unleash the Power of Implicit Data Templates in Silverlight 5

One of the cool new features in Silverlight 5 are implicit data templates.  They allow developers to associate a set of visuals encapsulated inside a data template with a specific class.  You can find a cool demo of this feature on Tim Heuer;s blog.  One of the links in this article shows how to use the feature inside a list box.

I would like to demonstrate ultimate power of this feature when it comes to creating views dynamically based on a specific type.  Let me elaborate.  I want to create an entry screen for a person class using MVVM pattern.  First, I am creating a simple Person class:

 

 

namespace SL5Features.Models

{

  public class Person : ModelBase

  {

 

    private string firstName;

 

    public string FirstName

    {

      get { return firstName; }

      set { firstName = value; OnPropertyChanged("FirstName"); }

    }

 

    private string lastName;

 

    public string LastName

    {

      get { return lastName; }

      set { lastName = value; OnPropertyChanged("LastName"); }

    }

 

  }

}

 

My base class does nothing more than implements INotifyPropertyChanged interface:

using System.ComponentModel;

 

namespace SL5Features.Models

{

  public class ModelBase : INotifyPropertyChanged

  {

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)

    {

      if (PropertyChanged != null)

      {

        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

      }

    }

  }

}

 

Now, I want to create a default template for this class.  Unlike other demos you saw so far, I am going to add this template to a resource dictionary.  I am going to create a new folder in my project called Templates.  Then, I am going to right-click, select Add New Item, then select resource dictionary type.  Once dictionary is created, I am going to add a data template to it, and associate it with the person type.  I have to add namespace to my models of course.  Here is what my dictionary looks like:

<ResourceDictionary

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:models="clr-namespace:SL5Features.Models">

 

  <DataTemplate DataType="models:Person">

    <Grid>

      <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="7"/>

        <RowDefinition Height="Auto"/>

      </Grid.RowDefinitions>

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="Auto"/>

        <ColumnDefinition Width="7"/>

        <ColumnDefinition Width="*"/>

      </Grid.ColumnDefinitions>

     

      <TextBlock Text="First Name:" 

                Grid.Column="0" Grid.Row="0" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"/>

     

      <TextBlock Text="Last Name:" 

                Grid.Column="0" Grid.Row="2" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"/>

     

      <TextBox Text="{Binding Path=FirstName, Mode=TwoWay}"

              Grid.Column="2" Grid.Row="0"/>

     

      <TextBox Text="{Binding Path=LastName, Mode=TwoWay}" 

              Grid.Column="2" Grid.Row="2"/>

    </Grid>

  </DataTemplate>

</ResourceDictionary>

 

Pretty simple screen.  Now for giggles I am going to create new dictionary with slightly different implementation for the same UI:

<ResourceDictionary

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:models="clr-namespace:SL5Features.Models">

 

  <DataTemplate DataType="models:Person">

    <Grid>

      <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="7"/>

        <RowDefinition Height="Auto"/>

      </Grid.RowDefinitions>

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="Auto"/>

        <ColumnDefinition Width="7"/>

        <ColumnDefinition Width="*"/>

      </Grid.ColumnDefinitions>

     

      <TextBlock Text="First Name:" 

                Grid.Column="0" Grid.Row="0" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"

                Foreground="Red"/>

     

      <TextBlock Text="Last Name:" 

                Grid.Column="0" Grid.Row="2" 

                HorizontalAlignment="Right"

                VerticalAlignment="Center"

                Foreground="Red"/>

     

      <TextBox Text="{Binding Path=FirstName, Mode=TwoWay}"

              Grid.Column="2" Grid.Row="0"

              Background="Yellow"/>

     

      <TextBox Text="{Binding Path=LastName, Mode=TwoWay}" 

              Grid.Column="2" Grid.Row="2"

              Background="Yellow"/>

    </Grid>

  </DataTemplate>

</ResourceDictionary>

 

Now, the fun part of injecting the visuals into my view.  I am going to inject them into MainPage, but ordinarily you would create a new user control.  All I do is add ContentControl and set Content to my view model’s property called Model that will contain my Person instance:

<UserControl 

   x:Class="SL5Features.MainPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:models="clr-namespace:SL5Features.Models"

   mc:Ignorable="d"

   d:DesignHeight="300" d:DesignWidth="400">

 

  <Grid x:Name="LayoutRoot">

    <ContentControl 

     x:Name="Host" 

     HorizontalAlignment="Stretch" 

     VerticalAlignment="Stretch" 

     HorizontalContentAlignment="Stretch" 

     VerticalContentAlignment="Stretch"

     Content="{Binding Path=Model}"

     />

  </Grid>

</UserControl>

 

Oh, I did not show you my view models structure.  I have a base class with Model property and INotifyPropertyChanged implementation.  Simple and basic:

using System.ComponentModel;

 

namespace SL5Features.ViewModels

{

  public class ViewModelBase<T> : INotifyPropertyChanged

  {

 

    private T model;

    public T Model

    {

      get { return model; }

      set { model = value; OnPropertyChanged("Model"); }

    }

 

 

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)

    {

      if (PropertyChanged != null)

      {

        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

      }

    }

  }

}

 

In my person view model I am going to cheat and just create an instance of a person:

using SL5Features.Models;

 

namespace SL5Features.ViewModels

{

  public class PersonViewModel : ViewModelBase<Person>

  {

    public PersonViewModel()

    {

      Model = new Person() { FirstName = "Sergey", LastName = "Barskiy" };

    }

  }

}

 

Now, in App.Xaml.cs I am going to inject the view model into my main page:

    private void Application_Startup(object sender, StartupEventArgs e)

    {

      AddDictionaries();

      this.RootVisual = new MainPage() { DataContext = new PersonViewModel() };

    }

 

Now, if you run the application you will not get the desired result.  Last step is to show you what magic my AddDictionaries contains:

 

    private void AddDictionaries()

    {

      // do we have a template query parameter

      var hasTempalteKey = HtmlPage.Document.QueryString.ContainsKey("Template");

      // create Url for default visuals dictionary

      var uri = new Uri("/SL5Features;component/Templates/Templates.xaml", UriKind.Relative);

 

      // now if I have query parameter called Template set to "ALT", I am going to use differnt Url

      if (hasTempalteKey && HtmlPage.Document.QueryString["Template"].ToUpper().Contains("ALT"))

      {

        // alternate tempalte Url

        uri = new Uri("/SL5Features;component/Templates/AltTemplates.xaml", UriKind.Relative);

      }

      // now creat new dictionary and inject it into Application resources

      ResourceDictionary dictionary = new ResourceDictionary();

      dictionary.MergedDictionaries.Add(

        new ResourceDictionary() { Source = uri });

      this.Resources.MergedDictionaries.Add(dictionary);

    }

 

I commented the code to demonstrate what I am doing.  What my goal is to swap visuals based on query string containing Template=Alt.  Now, run the application .  Here is what it looks like:

 

image

Now, the cool part.  Just alter the Url and whatch the magic:

image

As you can see, I have swapped the visuals by dynamically swapping templates.  You can imagine that you can design template and use then as a replacement for your views, injecting them into pre-defined shells.  You can see how you can decrease the amount of code needed for view / view model construction in a typical MVVM application, but also dynamically inject different visuals without changing any code.

You can download my sample application here.

Enjoy Silverlight 5!  You can find the download links here.

Post to Twitter

Pitfalls of Deploying Silverlight Applications in Web Farms

I wanted to make a few notes regarding my recent experience of deploying a Silverlight application in web farm environment.  Here is what the topology looked like.  It included load balancer appliance configured to redirect the traffic to one of three servers.  There was also SQL Server cluster in active-passive configuration.  The application was using 3 different databases.  There was also SSRS component deployed on the same instance(s) of SQL Server, since Silverlight application included report viewer built using SSRS Report Viewer for Web Forms.  The viewer was hosted in an ASPX page that contains SSRS Report Viewer.  The page itself was hosted inside a Silverlight window that contained Telerik’s HtmlPlaceholder control.

The first problem that we encountered was MSDTC.  We use TransactionScope to ensure transactional integrity of data updates.  Unfortunately, since we have multiple databases in some updates, TransactionScope will automatically promote all transactions to MSDTC.  We got errors from MSDTC right away.  We had to configure MSDTC on each of the server in the SQL cluster.  In cluster environment in Component Services you have to actually expand cluster node and configure MSDTC from there.  You have to enable network access.  We set it up with no authentication since all machines that participate in each transaction are not on the same domain, so configuring authentication for MSDTC would be pretty hard.  We also had to configure MSDTC on all application servers that house our WCF services that Silverlight application is using.  Event after all that MSDTC did not work.  We also had to put exceptions into two different firewalls that production environment deployed.  Once that was done, MSDTC finally worked.

The next set of errors came from report viewer.  We kept getting invalid view errors.  Of course, since I do not deploy production applications every month, I forgot about view state.  Silverlight does not care about that, but SSRS Viewer does!  So, first step was to synchronize machine keys for all web servers in our environment.    You can read more about machine keys here.  You can use this little program to generate keys on the fly.  Once that was done, I was expecting SSRS to work.  However, I was still getting errors.  Again, it had everything to do with web farms.  I forgot that I also need to synchronize session state.  I had to configure web applications to use SQL Server based session state.  First, you have to enable session state on an SQL Server you are going to use.  You can use aspnet_regsql.exe tool that ships with .NET to do so.  You can run it from any machine, and simply point to SQL Server.  You can read about this tool in this article on MSDN.  The last step is to update web.config files on all our web servers to looks similar to the following.  Your syntax will vary depending on version of IIS you use and how your application pool is configured (classic or integrated pipeline mode) in IIS 7+.  You can read more about the session node here.  Here is an example of the configuration.

 

<sessionState
    mode="SQLServer"
    sqlConnectionString="data source=<SQL Server Name or IP address>;
        user id=<User ID>;password=<Password>"
    cookieless="false"
    timeout="20"
    />

Timeout is in minute.  20 minutes is the default, and you can change it if you would like.

OK, these are the steps we had to take to deploy the app.  As always, I try to make notes my blog to document my experiences to hopefully make my next deployment task easier.  I always encourage developers to maintain a blog for this exact reason.  Your own blog becomes your personal knowledge base.

Post to Twitter

Maximum Number of Concurrent Connections in Internet Explorer

Today as I was debugging and optimizing a Silverlight application, I discovered a hidden feature in IE 8 that allows you to increase the number of concurrent connections to any server.  Here is the link that describes the procedure.

http://msdn.microsoft.com/en-us/library/cc304129(VS.85).aspx

You can try to speed up your browser by changing this setting.

Post to Twitter

Building Windows Phone 7 Silverlight Application

It this post I want to describe the process I went though building and publishing my first Silverlight application for Windows Phone 7.  It is currently being tested, and I hope I will pass the test this time.  I went through a couple of iterations of testing already, learning in the process from my mistakes.  I want to describe the process so that I myself can remember the steps, but hopefully help other folks with some tips and tricks.

In order to be able to publish an application for Windows Phone 7, you must sign up as a developer on App Hub – http://create.msdn.com.  This process was pretty painless actually, and only took a few minutes.  A couple of important things to remember.  Once you sign up, you will get an email from GeoTrust.  You have to follow the link in the email and answer a few questions confirming your identity.  The questions for me came from my credit report.  This tells me that Microsoft really wants to ensure there is a real person behind the signee.  Once you complete this step, you have to go back to App Hub and fill out your bank account information.  Once you are done with paperwork, you are ready to start writing your application.

To create an app, you have to have some tools installed on your machine.  You have to have at lest Visual Studio Express for Windows Phone, but I would also recommend Expression Blend for Windows Phone 7.  You can find the links to the software on main page of App Hub.

Once you have basic tools, you will likely need some secondary software to help you write your applications.  Here is what I would recommend.

  • Windows Phone 7 Toolkit from CodePlex.  Controls in the toolkit are written by Microsoft folks just like Silverlight toolkit.  You can download the toolkit here  To help you get started, check out Tim Heuer’s post on the toolkit here.
  • Another good tool is version of Prism for Windows Phone 7.  This article on MSDN describes the content of Prism for the phone.  You can download binaries here.  Once you build Prism 4, you will find Phone folder under Bin with all the binaries.  There is a lot of cool functionality there.
  • I had some troubles getting commanding to work using blend using event to command behavior.  As a result, I also downloaded and used MVVM Light by Laurent Bugnion.  You can download binaries and find some quick start links on CodePlex here.
  • If you want to save some data on the phone, I would recommend using a database abstraction by your truly.  You can download Database for Windows Phone 7 here.

Now, some sample code.

Application bar is the portion of the screen that shows the menu.  I am using Prism to implement commands to react to user interactions.  Here is XAML portion of the application bar.

<phone:PhoneApplicationPage
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
   xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
   xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 
  
xmlns:wi="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    
  
xmlns:i="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity"
 
  
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
   xmlns:mvvmLight="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP7"
   xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;

assembly=System.Windows.Controls.DataVisualization.Toolkit"
   x:Class="SportTimer.MainPage"
 
  
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
 
  
FontFamily="{StaticResource PhoneFontFamilyNormal}"
   FontSize="{StaticResource PhoneFontSizeNormal}"
   Foreground="{StaticResource PhoneForegroundBrush}"
   SupportedOrientations="Portrait"  Orientation="Portrait"
   shell:SystemTray.IsVisible="True">
 
    <!–Sample code showing usage of ApplicationBar–>
    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/icons/clock.png" Text="time" />
            <shell:ApplicationBarIconButton IconUri="/icons/person.png" Text="people"/>
            <shell:ApplicationBarIconButton IconUri="/icons/event.png" Text="events"/>
            <shell:ApplicationBarIconButton IconUri="/icons/graph.png" Text="history"/>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>
 
    <wi:Interaction.Behaviors>
        <i:ApplicationBarButtonCommand ButtonText="time" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding TimeIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="people" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding PeopleIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="events" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding EventIndex}"/>
        <i:ApplicationBarButtonCommand ButtonText="history" 

CommandBinding="{Binding ChangeIndexCommand, Mode=OneWay}" 

CommandParameterBinding="{Binding HisotryIndex}"/>
    </wi:Interaction.Behaviors>
    <!–LayoutRoot is the root grid where all page content is placed–>
    <Grid x:Name="LayoutRoot" Background
="Transparent">

 

Let me comment a bot on the code.  Application bar can have at most 4 buttons, and I am using all of them.  I am declaring application bar button command separately which is how Prism wants the implementation done, then bind commands to buttons via Text property of the button. Commands are declared in my view model as follows

 

        public DelegateCommand<object> ChangeIndexCommand { get; set; }        public void OnChangeIndex(object parameter)        {            SelectedPivotIndex = int.Parse(parameter.ToString());        }

 

ChangeIndexCommand = new DelegateCommand<object>(OnChangeIndex);

I am creating an instance of the command in view model constructor.  The command simply changes selected index of the pivot control,

I also have some button controls in my application.  I use MVVM light for those, again because I could not get Prism behavior to work.

<Button Content="Stop" Grid.Row="3" Grid.Column="2">    <wi:Interaction.Triggers>        <wi:EventTrigger EventName="Click">            <mvvmLight:EventToCommand Command="{Binding Path=StopTimerCommand}" />        </wi:EventTrigger>    </wi:Interaction.Triggers></Button>

 

Another interesting control I use is ContextMenu from toolkit.  I am using it to delete items from ListBox:

<ListBox x:Name="FilteredHistoryListBox" Grid.Row="3" Grid.ColumnSpan="3"

           ItemsSource="{Binding Path=FilteredHistory}">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <Border Margin="0" BorderThickness="0" Background="Transparent" Padding="0">

                <toolkit:ContextMenuService.ContextMenu>

                    <toolkit:ContextMenu>

                        <toolkit:MenuItem Header="Delete">

                            <wi:Interaction.Triggers>

                                <wi:EventTrigger EventName="Click">

                                    <mvvmLight:EventToCommand 

Command="{Binding ElementName=EventsItem, Path=DataContext.DeleteHistoryCommand, Mode=OneWay}" 

CommandParameter="{Binding}" />

                                </wi:EventTrigger>

                            </wi:Interaction.Triggers>

                        </toolkit:MenuItem>

                    </toolkit:ContextMenu>

                </toolkit:ContextMenuService.ContextMenu>

                <StackPanel Margin="0,0,0,7">

                    <TextBlock Text="{Binding Path=TimeString}"  

TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextExtraLargeStyle}"/>

                    <TextBlock Text="{Binding Path=HistoryDateString}" TextWrapping="NoWrap" Margin="12,-6,0,0" Style="{StaticResource PhoneTextSubtleStyle}"/>

                </StackPanel>

            </Border>

        </DataTemplate>

    </ListBox.ItemTemplate>

 

 

Now, about application bar icons.  I was trying to use the icons from Visual Studio, and I failed the test.  Then, I actually read the documentation Smile

The application bar icons must be 48×48 pixels with transparent background, with the icon itself (image or text) white 24×24 pixels.  I found this very good post by Brad Tutterow, and I used it to create custom icons for my application.  Nothing fancy, but my skill were good enough to create four icons for my Sport Timer application.   Make sure to test your application in light theme either on the phone or emulator.  Here is my person icon and graph icon.

Persongraph

I wanted to incorporate graphs info my application, and I found this great port of chart library from Silverlight toolkit.  At least I think that is what it is.  Here is the link to the post about it that includes download link.

Another tip that I have is that for some reason virtual keyboard did not work on one of my screens.  Come to find out through trial and error that you must inherit for PhoneApplicationPage for that to work.  I used UserControl, following typical Silverlight development pattern.  Once I changed the inheritance in XAML and .cs files, everything worked like magic.

Also, you have to test your icons on the phone.  Make sure to pin your application to start up to ensure it looks good.  You can setup icons and test for start up page on the phone and regular list on the phone in properties of your application page.  Make sure to check these settings.

image

You can use the same image or different ones.  I followed the default application and used different sizes.  You can see the image size from the icon name.  All of them are images in png format.

When you submit your application, you are also required to submit a number of image in specific format.  I used Paint.NET to resize my images and set DPI.  You can do both through Resize command window.  Also, make sure the screenshots of your application do not include the emulator itself, only the application.  You will fail testing because of the this as well.  Again, follow the descriptions in submission page to verify the DPI and sizes of all your images.

I hope this post may save a few folks a few extra minutes.

Post to Twitter

Silverlight 5

Today I am going to make an attempt to analyze new features in Silverlight 5.0 and see how they fit into full picture of Microsoft efforts and their announcements regarding Silverlight and HMTL 5.

You can see full list on Scott Guthrie’s blog here.  You can also read some more comments by John Papa here.  You can watch keynote here.

First of all, multimedia experience in Silverlight 5 further enhances great abilities of Silverlight.  Setting up live streaming is very easy in IIS 7.  Also, performance of playback will be improved.  All-in-all, we all already knew that Silverlight is great for media.  I am a lot more interested in business applications though.

One of my biggest pet peeves is productivity.  I am glad to see that Microsoft is paying attention to develop experience.  Debugging on data binding errors in XAML via breakpoints is pretty neat.  Having said that, binding errors are already echoed to the output window today.  Default data templates can be setup for a specific type.  This feature is super cool to me.  I can just put my business object into XAML and it will be automatically resolved via data template and UI will be created for it.  I can see that MVVM frameworks will add support for something like that to enable more transparent resolution of data into visuals.  You will also be able to use data binding in styles’ property setters.  This makes styles ever more powerful.  There will be DataContextChanged event added.  I have been missing this event ever since I started with Silverlight.  One has to always play tricks to create controls that need to update themselves when their data context changes.  Those tricks will no longer be needed.  Markup extensions will be supported for properties and event handlers.  As a result, you can create markup extensions methods that will for example just invoke a method on a view model without having to always create a command.  This will make you more productive, saving you from having to write boiler plate code over and over.  Ancestor type relative source will allow data binding of data template properties to the control properties that this data template support.

There are improvements in WCF stack and FCW RIA services.  WS-Trust  will be supported.  There will be better support for complex types in RIA services, providing more comprehensive abilities for complex business scenarios.  Silverlight 5 network stack will also have support for low-latency scenarios, such as frequent (almost-live) updates. 

There is a number of improvement regarding text presentation.  Multi-line text that flows around other visuals, clearer typography, just to name a few.  Printing is finally better.  You will have PostScript vector printing API will provide support for complex documents and reports.  Layout transitions make building appealing interfaces much simpler.  Text layout performance is greatly improved.  Double-click event will be there.

Silverlight 5 will enable 3D GPU accelerated rendering.  This may not be applicable for main stream line of business applications.

Out of browser support becomes literally awesome.  You can now have child windows that are undocked from main window.  They show up in Windows task bar as separate windows as well.  You can now have infinite real estate for you applications.  Also, you can now invoke WIn32 API directly from out-of-browser and in-browser.  If a policy is configures, you can literally export to Word using dynamics and launch Word with new document while in browser.  Users will have more control over sandboxing without compromising security.  You will also be able to access hardware devices by utilizing COM interop.  You can have better kiosk support via on screen keyboard in full screen mode.

64 bit Silverlight is coming.  This to me is a critical feature, and should have been there years ago.  I do not want to teach my users which browser to use for my app.  Now, it is not necessary.  Hardware acceleration will be available in windowless mode now.  This is a critical piece of general speed improvements.

Developer experience is further improved via Microsoft Visual Studio profiling support including CPU, memory, thread contention.

Now the summary.  Rumors of Silverlight death have been greatly exaggerated, and now this is pretty obvious.  Actions always speak louder then words, and SL 5 announcement by Scott Guthrie is something that community needed badly ever since Bob Muglia’s comment at PDC.

As you can see, Silverlight is getting performance improvements, productivity improvements, user experience improvements and media handling improvements.  The sandbox can be relaxed by users, enabling richer integration with Windows operating system.  Silverlight is even getting 3D.  What are the lessons learned from this announcement?  Here is my prioritized list:

  • Silverlight is alive and well and will be with us for many years to come.  Nobody should be afraid to use Silverlight platform for business applications.
  • Silverlight will be faster for users in version 5.
  • Silverlight will be even more productive environment in version 5.
  • Integration with Office and Windows will be better.  Now, this is bad news for WPF.  .

It appears to me that Microsoft is positioning Silverlight to be default de facto platform for line of business application.  I cannot say I disagree.  Rich applications developed faster and cheaper is what businesses need and Silverlight has.

 

Here is keynote.  Watch and enjoy.

Post to Twitter

Silverlight vs. HTML 5

It is time for me to jump on bandwagon of discussing the latest comments out of Microsoft regarding Silverlight.  If you have not read the latest commend by Bob Muglia, Microsoft VP, you can read his interview with Mary-Jo Foley here.  One particular paragraph bothers me a ton:

Silverlight is our development platform for Windows Phone,” he said. Silverlight also has some “sweet spots” in media and line-of-business applications, he said.

 

I am seriously bugged by this maybe unintentional dismissal of Silverlight as development platform for web applications.  I have been holding the following opinion on the subject for quite some time.  I think for public facing web sites Silverlight maybe not be an ideal fit since it increases the barrier of entry for consumers.  However, for internal business applications and B2B applications it is a great fit.  This is primary because you have pretty good control in business environment and you can very easily ensure that all computers have Silverlight installed.  Thus, Silverlight plugin simply becomes a prerequisite for such applications.  I have been developing B2B applications in Silverlight for over 2 years, and have not seen any problems with this approach until Bob Muglia’s comment.  Based on my personal experience, you can delivery better applications faster in Silverlight vs. traditional web technologies such as APS.NET.  Granted, you have a learning curve to overcome, but isn’t this the case with any technology?  If one is in software business, studying becomes an essential part of one’s carrier. 

Let’s take the following hypothetical situation. You are a software company that developed a Silverlight B2B application over the course of a couple of years.  You are successfully selling it.  All of a sudden your competitor with an inferior product, which is developed using ASP.NET reads the comment above.   They immediately incorporate this fact into their marketing approach, costing your sales.  You can see how a relatively small comment can cause a company that spent millions in development costs a multimillion dollar sale.

I do not think Silverlight is going away by any stretch of imagination.  It is and will remain a great platform for web based business applications.  However, it would be more than necessary for Microsoft to clear the air and do so with a sense of urgency.  I do not believe that dismissive attitude toward Silverlight is correct, and probably was an unintended consequence of stressing the importance of HTML 5 for Microsoft.

Post to Twitter

Presentation at Atlanta MS Pros

Yesterday I did a presentation at local Atlanta MS Pros users group on LightSwitch.  I just want to post the slides for the presentation.  These slides also contain a bunch of links to LightSwitch resources.

You can download the presentation here.

Post to Twitter

Using WinDbg to Find Memory Leaks in Silverlight Applications

In light of recent issues with memory leaks in Silverlight and the fact that service pack that was supposed to address these issues was released last week, I found myself working on an application, trying to confirm that it does not leak any longer.  To simplify my approach, I created a destructor for my view with the following code:

        ~BaseView()
        {
#if DEBUG
            System.Diagnostics.Debug.WriteLine("Destructed view " + this.GetType().Name);
#endif
        }

 

This code will echo to Debug window when garbage collector hits my view.  To my dismay, the view was never collected after being removed from a region.  (I am using Prism for my sample application).  I did some research, and decided to use WinDbg to help me pinpoint memory leaks.

First step is to download tools for my Windows 7 64 bit machine.  I found the link here:http://www.microsoft.com/whdc/devtools/debugging/install64bit.mspx

So I installed checking all options.  I started WinDbg and tried to load Silverlight debug symbols from (C:\\Program Files (x86)\\Microsoft Silverlight\\4.0.50826.0\\sos.dll).  Unfortunately I got an error – not a valid 32 bit application, even though I am running 64 bit.  Come to find out, I actually need 32 bit version of WinDbg since Silverlight only runs in 32 bit environment.  Would be nice to have a better message, but here we go.  Next step is to install 32 bit version of WinDbg.  make sure you checked ALL options during main tools install.  If so, you will find that version here: C:\Program Files\Microsoft SDKs\Windows\v7.1\Redist\Debugging Tools for Windows.

Now, start WinDbg from Program Files (x86) folder.  I just use search feature in Windows 7, and type WinDbg into search box after clicking on Start button.

Now I run my application in IE, and load my UserView (user control) a few times, and close it (remove from region) a few times, 3 times to be specific..

With WinDbg running, I now have to attach to a process, Internet explorer in my case. Make sure you do not have Visual Studio running in debug mode, or you will get  an error trying to attach second debugger to IE.  I use File->Attach To Process menu in WinDbg and look for iexplore process.  Then I will see Command window.  In the bottom portion of the window I see a textbox – this is WinDbg command line.  I type the following: .load C:\\Program Files (x86)\\Microsoft Silverlight\\4.0.50826.0\\sos.dll and hit enter.  Make sure to start with a period(.).

Now, let’s take a memory snapshot.  Type the following and hit enter: !dumpheap –stat 

Once that is done, hit Ctrl+Home to go to the top of command window, then hit Ctrl+F to pull up search window, type your control name (UserView) in my case and hit Enter.  You now will see how many instance of your view there are in memory:

05dcaa14        3          300 KSS.Silverlight.SystemWide.Views.UserView

In my case there are three.The first column is MT, which will contain my type.  using this value I can find addresses of each of three instances.  Type the following and hit Enter:

!dumpheap -MT 05dcaa14

Now I see addresses for each of three instances.  I pick up one at random to see the references that keep the object from being picked up by garbage collector.  Type the following and hit Enter:

!gcroot 12753bfc

Here is the output for this command:

0:035> !gcroot 12753bfc
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 4 OSTHread 1c28
Scan Thread 30 OSTHread cc4
Scan Thread 31 OSTHread 15b0
Scan Thread 33 OSTHread cb8
DOMAIN(05FE3BD8):HANDLE(Pinned):2f812f8:Root:  13594260(System.Object[])->
  125a8888(System.Collections.Generic.Dictionary`2[[System.IntPtr, mscorlib],[System.Object, mscorlib]])->
  127a9408(System.Collections.Generic.Dictionary`2+Entry[[System.IntPtr, mscorlib],[System.Object, mscorlib]][])->
  127dd420(System.Windows.Controls.Grid)->
  127dd484(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127dd4d0(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127dd54c(System.Windows.Controls.Border)->
  127e9874(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127e98c0(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127ddd88(System.Windows.Controls.Grid)->
  127dddec(System.Collections.Generic.Dictionary`2[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]])->
  127dde38(System.Collections.Generic.Dictionary`2+Entry[[MS.Internal.IManagedPeerBase, System.Windows],[System.Object, mscorlib]][])->
  127dde84(System.Windows.Controls.ScrollViewer)->
  127e97f0(System.Windows.Controls.ItemsPresenter)->
  127e9858(MS.Internal.CoreTypeEventHelper)->
  127ea1b4(System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib],[MS.Internal.CoreTypeEventHelper+EventAndDelegate, System.Windows]])->
  127ea200(System.Collections.Generic.Dictionary`2+Entry[[System.Int32, mscorlib],[MS.Internal.CoreTypeEventHelper+EventAndDelegate, System.Windows]][])->
  127ea1a4(MS.Internal.CoreTypeEventHelper+EventAndDelegate)->
  127ea16c(System.Windows.Input.KeyEventHandler)->
  12760854(Telerik.Windows.Controls.RadComboBox)->
  12757a7c(System.Windows.Controls.Grid)->
  127cf2ac(System.Windows.Controls.ContentPresenter)->
  127cf188(System.Windows.Controls.Grid)->
  12757160(Groupbox.GroupBox)->
  12756df4(System.Windows.Controls.Grid)->
  12753bfc(KSS.Silverlight.SystemWide.Views.UserView)

You should start looking from the bottom and work your way up to the gcroot – garbage collector root object.  In my case I find RadComboBox object – first reference that looks like it is causing issues.  I remove the combo box from my UserView user control and repeat the test.  This time view disposes.  I found my leak!

More typically, leaks are caused by hanging references to your objects, most commonly by event handlers.  In my case this was not the case, but this is typically where you would look first.

Thanks.

Post to Twitter

Modular Silverlight Development, App.xaml, Blend and Resources

As I was working on one of my personal learning projects, I encountered a small problem. The project was Prism based with multiple modules.  I wanted to isolate my resource files, so I created a separate project that included my XAML resources, such as styles.  This approach works just fine by using merged dictionaries in App.xaml:

<Application 
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   x:Class="MyApp.Silverlight.App"
            >
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/MyResources.Silverlight.Common;component/Resources/MyResourcesDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

Now I can reference those resource in my other modules’ screens and use them.  Now back to the original issue.  I can use styles from MyResourceDictionary.xaml, but Blend generates an error for me – it cannot find my resources.  Here is an easy way to overcome this issue.  You have to add the same dictionary into the resources of each screen:  In the example below I am showing resources area for a user control called MySampleView from MyApp module.,

    <MyApp:MySampleView.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/MyResources.Silverlight.Common;component/Resources/MyResourcesDictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <resource:Resource x:Key="LocalizedResource"/>
        </ResourceDictionary>
    </MyApp:MySampleView.Resources>

As you can see, I combine the styles dictionary with a local resource, in example localized user strings.  You can just as easily add converters, etc… in the same fashion.

There is some cost of course associated with merging dictionaries into each screen, but using Blend is a big benefit.  You can get around this issue by keeping this code commented out, and uncomment when using Blend

There is also another solution, involving having #DEBUG that moves this exact code into code behind of each view.  Of course, this is annoying as well, and this is when the base class for the view comes in.  Here is the code I could add to it to accomplish the same as XAML approach:

#if DEBUG
            var dictionary = new ResourceDictionary() 
                { Source = new Uri("/MyResources.Silverlight.Common;component/Resources/MyResourceDictionary.xaml", UriKind.RelativeOrAbsolute) };
            Resources.MergedDictionaries.Add(dictionary);
#endif

 

This of course underscores the usefulness of having base classes for all your major components, such as views in your applications.  It could be an inconvenience since you cannot just add new user control.  You would have to edit both XAML and code behind to change the inheritance structure of your user controls (views).

<MyApp:MySampleViewBase
   x:Class="MyApp.Views.MySampleView"

public partial class MySampleView : MySampleViewBase, IMySampleView

 

You can further optimize this process by creating custom control templates that would write all this code for you.  This way you would not have to modify the files after creating a new user control.

Thanks.

Post to Twitter

Encryption in Silverlight and .NET Applications

Today I would like to cover a specific use case that came up a few times in Silverlight applications I wrote.  For example, I wand a user to enter some sensitive information, encrypt it in Silverlight client, transfer it over to the server, then decrypt it and perforation some operations on that data.

First step of course is to find sufficiently strong encryption protocol that can be implemented in both Silverlight and .NET and be completely compatible between both run times.  I am going to go for AES encryption.  AES stands for “Advanced Encryption Standard”.  This standard is widely used and approved by US government and standard bodies.  See this article for details.

Luckily, AES encryption is implemented in both Silverlight and .NET run times, using exact same set of classes, primary one being AesManaged class.  My goal is to create a class that I can cross-compile in both runt times, so this comes in super handy.  Second, I wand to implement two methods Decrypt and Encrypt, while paying attention to IDisposable interfaces that the vast majority of classes inside Cryptography namespace implement.  Both static methods take two parameters, input string and a password to be used.  Of course, you have to make sure you use the same password in both methods while encrypting and decrypting information.  You should probably dynamically generate a password during handshake process between a Silverlight client and a .NET server.  I will also use maximum key size and block size of encryption.  I will also dynamically generate key (Key) and initialization vector(IV) properties.    I am going to now spare everyone a number of boring details, and will simply post final version of my utility class:  You can include this class in both .NET and Silverlight project, and even link the physical .cs file from one to the other to ensure that you only have a single version in source control.

Thanks

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
 
namespace Encryption
{
    public static class EncryptionUtility
    {
 
        /// <summary>
        /// Encrypt the data
        /// </summary>
        /// <param name="input">String to encrypt</param>
        /// <returns>Encrypted string</returns>
        public static string Encrypt(string input, string password)
        {
 
            byte[] utfData = UTF8Encoding.UTF8.GetBytes(input);
            byte[] saltBytes = Encoding.UTF8.GetBytes(password);
            string encryptedString = string.Empty;
            using (AesManaged aes = new AesManaged())
            {
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
 
                aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
                aes.KeySize = aes.LegalKeySizes[0].MaxSize;
                aes.Key = rfc.GetBytes(aes.KeySize / 8);
                aes.IV = rfc.GetBytes(aes.BlockSize / 8);
 
                using (ICryptoTransform encryptTransform = aes.CreateEncryptor())
                {
                    using (MemoryStream encryptedStream = new MemoryStream())
                    {
                        using (CryptoStream encryptor = 
                            new CryptoStream(encryptedStream, encryptTransform, CryptoStreamMode.Write))
                        {
                            encryptor.Write(utfData, 0, utfData.Length);
                            encryptor.Flush();
                            encryptor.Close();
 
                            byte[] encryptBytes = encryptedStream.ToArray();
                            encryptedString = Convert.ToBase64String(encryptBytes);
                        }
                    }
                }
            }
            return encryptedString;
        }
 
        /// <summary>
        /// Decrypt a string
        /// </summary>
        /// <param name="input">Input string in base 64 format</param>
        /// <returns>Decrypted string</returns>
        public static string Decrypt(string input, string password)
        {
 
            byte[] encryptedBytes = Convert.FromBase64String(input);
            byte[] saltBytes = Encoding.UTF8.GetBytes(password);
            string decryptedString = string.Empty;
            using (var aes = new AesManaged())
            {
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, saltBytes);
                aes.BlockSize = aes.LegalBlockSizes[0].MaxSize;
                aes.KeySize = aes.LegalKeySizes[0].MaxSize;
                aes.Key = rfc.GetBytes(aes.KeySize / 8);
                aes.IV = rfc.GetBytes(aes.BlockSize / 8);
 
                using (ICryptoTransform decryptTransform = aes.CreateDecryptor())
                {
                    using (MemoryStream decryptedStream = new MemoryStream())
                    {
                        CryptoStream decryptor = 
                            new CryptoStream(decryptedStream, decryptTransform, CryptoStreamMode.Write);
                        decryptor.Write(encryptedBytes, 0, encryptedBytes.Length);
                        decryptor.Flush();
                        decryptor.Close();
 
                        byte[] decryptBytes = decryptedStream.ToArray();
                        decryptedString = 
                            UTF8Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
                    }
                }
            }
 
            return decryptedString;
        }
    }
}

Post to Twitter

XAML Intellisense Stops Working in Visual Studio 2010

Today as I was working on a Silverlight application in Visual Studio 2010, XAML Intellisense just stopped working for me.  Quick internet search yielded no useful results, so I was to figure this out on my own.  Just to test I created a brand new application, and Intellisense was fine there.  Logical answer was that there was something wrong with my project.  I re-created the project, and slowly retraced my steps, testing XAML Intellisense  after each step.  The feature broke again as soon as I added a reference to  third party library I downloaded off the internet.  Something wrong with a file, obviously.  What I saw is that the DLL in question was blocked by Windows security.  I unblocked by right-clicking on the file in Windows explorer, going to properties and clicking Unblock button.

The package that I downloaded included many files, and I really hated to go through each one. Next internet search yielded a great solution from SysInternals.  You can download it here.  Once I got streams utility, I ran it on entire folder, and voila – Intellisense was back.  The command line is “streams –s –d ‘Folder with DLLs to Unblock’”, in my case “streams –s –d “c:\ThirdParty””

So, my research solved two problems for me – missing XAML Intellisense  and ability to unblock multiple files which is something I wanted to find an answer to a while ago,

Post to Twitter

Unit Testing Silverlight Applications – UI testing and Test Automation

In my last post I am going to cover the last two topics I set out to address.  The first topic is UI testing.  What unit test frameworks lack sometime is the actually UI testing.  What I mean by that is for example, click on a button, then see what happens.  In case of Silverlight, Silverlight framework itself has a number of helper classes to help us achieve this goal.  For example, ButtonAutomationPeer class allows us to drive button actions from within unit tests.  Also, Microsoft Silverlight unit testing framework allows developers to insert UI components onto unit testing surface.  Let me illustrate both concepts via an example.  Here is my code for such unit test”

[TestMethod]
[Asynchronous]
[Description("Asynch Get Companies in UI")]
[Tag("Asynch")]
public void TestUIGetCompanies()
{
 
    var companyVM = new CompanyModule.ViewModels.CompanyListViewModel(
        new Microsoft.Practices.Composite.Events.EventAggregator());
    CompanyListView companyV = new CompanyListView();
    companyV.DataContext = companyVM;
    TestPanel.Children.Add(companyV);
    ButtonAutomationPeer buttonPeer = 
        new ButtonAutomationPeer(companyV.FindName("GetCompaniesButton") as Button);
    DataGrid grid = companyV.FindName("CompanyGrid") as DataGrid;
    IInvokeProvider buttonInvoker = (IInvokeProvider)buttonPeer;
 
    IGridProvider gridPeer = new DataGridAutomationPeer(grid);
 
    EnqueueCallback(() => buttonInvoker.Invoke());
    EnqueueConditional(() => { return companyVM.CompanyList != null; });
    EnqueueCallback(
        () => Assert.IsTrue(companyVM.CompanyList.Count() > 0, "Should have data"),
        () => Assert.IsTrue(grid.Columns.Count == 3, "Should have 3 columns"),
        () => Assert.IsTrue(gridPeer.RowCount > 0, "Should have rows"));
    EnqueueTestComplete();
}

 

Let’s trace down what is going on in this test.  First of all, I am creating view model class.  Since I do not have a bootstrapper, I manually create EventAggregator myself.  Next, I am create a view to put my view model into.  I create view, then put my view model into the data context of my view.  Nest important step is to add my view to unit te3swt harness.  This is accomplished by adding my view to test panel.  My screenshot below illustrates where test panel is in terms of test runnier UI.  I added hand cursor to illustrate the test panel referred to in UI below as “Test Stage.”  As I run the unit tests, I will actually see my view there in the test stage.  Just like I added the view, I can remove it from test stage.

image

Next I am setting up code to invoke a button.  I am creating new instance of ButtonAutomationPeer class.  Of course, I need to find a button to attach the automation peer to, and I am using FindName method to find an i9nstance of my button.  To use this functionality I had to name my button.  Then, I am setting up an automation peer for my grid as well.  In general, most user input controls in Silverlight framework have matching automation objects.  In my case, I am testing the results of my button invocation directly against the grid, making sure that the grid has correct number of rows and columns.  I can also combine this type of testing with mocking,  Here is the unit test for this case:

[TestMethod]
[Asynchronous]
[Description("Asynch Get Companies in UI With Mocking")]
[Tag("Asynch")]
public void TestUIGetCompaniesWithMock()
{
    var companyVM = new Mock<ICompanyListViewModel>();
    companyVM.SetupGet(testVM => testVM.CompanyList).
        Returns(new ObservableCollection<Company>(new[] {
        new Company(){
            CompanyID = Guid.NewGuid(), DateAdded = DateTime.Now, CompanyName = "some random company"},
        new Company(){ 
            CompanyID = Guid.NewGuid(), DateAdded = DateTime.Now.AddDays(-1), CompanyName = "another company"}}));
    companyVM.SetupGet(testVM => testVM.GetCompaniesCommand).
        Returns(new DelegateCommand<object>((o) =>
        companyVM.Raise(vm => 
            vm.PropertyChanged += null, new System.ComponentModel.PropertyChangedEventArgs("CompanyList"))));
 
 
    CompanyListView companyV = new CompanyListView();
    companyV.DataContext = companyVM.Object;
    TestPanel.Children.Add(companyV);
    ButtonAutomationPeer buttonPeer = new ButtonAutomationPeer(companyV.FindName("GetCompaniesButton") as Button);
    DataGrid grid = companyV.FindName("CompanyGrid") as DataGrid;
    IInvokeProvider buttonInvoker = (IInvokeProvider)buttonPeer;
 
    IGridProvider gridPeer = new DataGridAutomationPeer(grid);
 
    EnqueueCallback(() => buttonInvoker.Invoke());
            
    EnqueueCallback(
        () => Assert.IsTrue(companyVM.Object.CompanyList.Count() > 0, "Should have data"),
        () => Assert.AreEqual(3, grid.Columns.Count, "Should have 3 columns"),
        () => Assert.AreEqual(2, gridPeer.RowCount, "Should have rows"));
    EnqueueTestComplete();
}

 

In the case above I am mocking property changed event by invoking it when a button is clicked, causing UI to re-bind.  The rest of testing code is very similar to actual invocation of server side code.

The last topic I would like to cover is StatLight framework.  You can take a closer look at the framework here.  This framework allows developers to invoke unit tests written with Microsoft unit testing framework for Silverlight from a command line and also read in results of such runs.  Once you download and unzip the DLLs into a folder, you will need to do one more thing – Unblock those DLLs in the properties of each file in Windows explorer.  Also, if you want to test server side code using StatLight, you will need to convert your web site to use local IIS inste4ad of Cassini (Visual Studio built-in IIS Server).  You will also need to put clientaccesspolicy.xml into the root of your IIS in order to avoid cross domain exceptions.  Using the StatLight framework is very simple.  Simply call StatLight.exe and pass XAP file on command line that contains your unit tests.  Here is a screenshot of what it looks like:

image 

As you can see, your –x parameter is the only one you have to specify to test.  You will also see that unit test is launched at the same time.  Now, to test results you have to add one more parameter – r.  Here is what that command would look like:

image

Once you run this, you will end up with out.txt in the specified folder.  Here is the content of this file:

image

The last parameter I want to mention is ability to limit test run by tag attribute I covered in an earlier post.  To user this feature, you have to add –t command line attribute like so:  Here is what this command line look like:

image

You can download complete solution here.

Thanks.

Post to Twitter

Windows Phone 7 Beta is here

Windows Phone 7 Developer tool beat has been released by Microsoft.  You can download it here.
Make sure to download and read release note available on the page above.

 

Thanks.

Post to Twitter

Unit Testing Silverlight Applications – Mocking

In this post I will explore ability to mock various Silverlight classes in order to enable mocking in your unit tests.  There is a variety of mocking frameworks available, but I will pick one for my testing – Moq.  You can download the framework here,  Once this is done, I need to add some references to my Silverlight unit test project.

Moq requires three assemblies available in the folder where Moq is installed:

image

If we are mocking view model or another object relying on Prism, we also need to add Prism references

image

Now we are ready to mock!

Let’s start by doing something simple.  I will mock my view model.  The only property I really want to test is my model property, which in my case exposes list of companies.  TO do so, I just need to setup property getter that contains my model.  The getter will be called when first accessed.  Here is what we have:

[TestMethod]
[Tag("Mocking")]
[Description("VM Mocking")]
public void TestMocking()
{
    var vm = new Mock<ICompanyListViewModel>();
    vm.SetupGet(testVM => testVM.CompanyList).
        Returns(new ObservableCollection<Company>(new[] {
            new Company()
                { CompanyID = Guid.NewGuid(), DateAdded = DateTime.Now, CompanyName = "some random company"},
            new Company()
                { CompanyID = Guid.NewGuid(), DateAdded = DateTime.Now.AddDays(-1), CompanyName = "another company"}}));
    Assert.AreEqual(2, vm.Object.CompanyList.Count, "Mocking failed");
 
}

 

I am only mocking view model in this case.  With Moq framework, as it is the case with most mocking frameworks, you are required to have interfaces in order to mock.  In case of RIA Services, this is an issue because client side classes are sealed and do not implement interfaces.  If you are using your own WCF service with custom classes, you can avoid this small issue.  You can also mock events as well.  This is how I would mock property changed event in my view model:

companyVM.SetupGet(testVM => testVM.GetCompaniesCommand).Returns(new DelegateCommand<object>((o) =>
    companyVM.Raise(vm => vm.PropertyChanged += null, new System.ComponentModel.PropertyChangedEventArgs("CompanyList"))));

 

As you can see, mocking is pretty easy concept, and the web page for Moq has quick start guide to help you get started.  Feel free to use a different mocking framework as well.  In the next post I will show how to unit test user interface using Silverlight unit testing framework.

Thanks

Post to Twitter

Unit Testing Silverlight Applications – Asynchronous Testing

In this post I will describe how to create asynchronous unit tests for Silverlight applications.  First of all, I’d like to point out that any communication with a server component in Silverlight must be asynchronous.  Reason being is that if communication was synchronous and the remote service was not responding, browser which host Silverlight application would lock up.  As you can see, asynchronous communication with a RIA Services WCF service is very important in our case. 

Let’s take a look on how to write a test that would assert that we can successfully get a list of companies from the server.  To do so, we must first take a look on how to write such a test.  This can be accomplished using asynchronous constructs available in Silverlight unit testing framework.  First of all, we have to change inheritance for our test class.  When you create a new test class, it does not inherit from any class, and we have to change this first of all.  Here is what old test class declaration look like:

[TestClass]
public class Tests

Here is what we are going to change it to:

[TestClass]
public class Tests : Microsoft.Silverlight.Testing.SilverlightTest

Now we must decorate our test method with appropriate attribute to signal to test running harness that it is about to execute asynchronous test:

[TestMethod]
[Asynchronous]
[Description("Asynch Get Companies")]
[Tag("Asynch")]
public void TestGetCompanies()

Now, let take a deeper look into framework itself to see the key methods that we can use in base class – SilverlightTest.

First one is EnqueueConditional.  This method is designed to let unit test wait until condition specified as an argument to EnqueueConditional is met.  It is very useful when you want to wait until a method call to the service is completed.  Here is how I would use this method:

        [TestMethod]
        [Asynchronous]
        [Description("Asynch Get Companies")]
        [Tag("Asynch")]
        public void TestGetCompanies()
        {
            bool isLoaded = false;
            Exception error = null;
            IEnumerable<Company> results = null;
            CompanyDomainContext context = new CompanyDomainContext(new Uri(@"http://localhost:4988/SilverlightTestingDemo-Web-CompanyDomainService.svc", UriKind.Absolute));
            var query = context.GetCompaniesQuery();
 
            context.Load<Company>(query, (result) =>
            {
                isLoaded = true;
                results = result.Entities;
                error = result.Error;
            }, null);
            EnqueueConditional(() => isLoaded);

 

What I am doing above is declaring a Boolean variable isLoaded that would signal to the framework to continue the test once data has been loaded.  I am setting this variable to true in the lambda expression callback that is called one server method’s execution is completed – (result)=> expression.

Next interesting method is EnqueueCallback.  This method simply declares multiple or in Action delegates that will be executed one they are popped off execution stack when harness processes test method calls.  What I mean is that the harness will execute all Action delegates that EnqueueCallback declares when it proceeds with running a test method once condition that  EnqueueConditional declares is met. If there are no such calls in the method body and there are no calls to EnqueueDelay that would also pause execution, then EnqueueCallback has no meaning, and asynchronous test essentially becomes synchronous.  Here is what we have so far:

        [TestMethod]
        [Asynchronous]
        [Description("Asynch Get Companies")]
        [Tag("Asynch")]
        public void TestGetCompanies()
        {
            
            bool isLoaded = false;
            Exception error = null;
            IEnumerable<Company> results = null;
            CompanyDomainContext context = new CompanyDomainContext(new Uri(@"http://localhost:4988/SilverlightTestingDemo-Web-CompanyDomainService.svc", UriKind.Absolute));
            var query = context.GetCompaniesQuery();
 
            context.Load<Company>(query, (result) =>
            {
                isLoaded = true;
                results = result.Entities;
                error = result.Error;
            }, null);
            EnqueueConditional(() => isLoaded);
            EnqueueCallback(
                () => Assert.IsTrue(results.Count() > 0, "Should have data"),
                () => Assert.IsNull(error, "Should have no errors"));

 

The last important method is EnqueueTestComplete.  This method puts Test Completed signal onto the execution stack. This method is typically the very last statement of the test method body.  Here is our final version of the method:

        [TestMethod]
        [Asynchronous]
        [Description("Asynch Get Companies")]
        [Tag("Asynch")]
        public void TestGetCompanies()
        {
            
            bool isLoaded = false;
            Exception error = null;
            IEnumerable<Company> results = null;
            CompanyDomainContext context = new CompanyDomainContext(new Uri(@"http://localhost:4988/SilverlightTestingDemo-Web-CompanyDomainService.svc", UriKind.Absolute));
            var query = context.GetCompaniesQuery();
 
            context.Load<Company>(query, (result) =>
            {
                isLoaded = true;
                results = result.Entities;
                error = result.Error;
            }, null);
            EnqueueConditional(() => isLoaded);
            EnqueueCallback(
                () => Assert.IsTrue(results.Count() > 0, "Should have data"),
                () => Assert.IsNull(error, "Should have no errors"));
            EnqueueTestComplete();
        }

 

You can download the complete code here.  In the next post I will cover mocking for synchronous and asynchronous unit tests.

Thanks..

Post to Twitter

Unit Testing Silverlight Applications

I am starting a short series of posts on unit testing of Silverlight applications.  I will be using the following set of technologies. 

  • Microsoft Silverlight Unit testing framework that ships with Silverlight tool kit
  • Moq – mocking framework that supports Silverlight 4
  • StatLight – unit testing automation framework that will allow for unattended / automated running unit tests

I am going to start with a simple Silverlight application that is using RIA services and Prism.  First things first, let’s create unit test project.  Project template will be installed when you install the Silverlight toolkit.  Here is what add project dialog looks like.  The template is located under Silverlight tab

image

Here are the setting for the next dialog:

image

Once project is created, a simple test class is also created.  If you ever worked with Microsoft unit testing in Visual Studio, you will find the API quite familiar, including all key classed, attributes and namespaces.  I am going to create a simple synchronous test first, testing my RIA services class to ensure that validation rules are setup properly.  To do so, I first add a reference to my simple Company module to my Silverlight unit test project.  Since I am also testing RIA services classes, I will add two more references: System.ComponentModel.DataAnnotations and System.ServiceModel.DomainServices.Client.dll.  Now with this our of the way, here is what my test class and method look like:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Silverlight.Testing;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SilverlightTestingDemo.Web;
 
namespace SilverlightUnitTest
{
    [TestClass]
    public class Tests
    {
        [TestMethod]
        [Tag("Synch")]
        [Description("Rules")]
        public void TestCompanyRules()
        {
            Company company = new Company();
            company.CompanyName = "test";
            Assert.AreEqual(0, company.ValidationErrors.Count, "Should be valid");
            company.CompanyName = string.Empty;
            Assert.AreEqual(1, company.ValidationErrors.Count, "Should be in valid");
        }
    }
}

 

Let me go over the attributes I used.  TestClass attribute is what signals to Unit testing framework as to what classes contain unit tests.  TestMethod attribute identifies methods that represent a single unit test.  Tag attribute is used by unit test runner UI to filter out what tests based on attributes will be run.  Description attribute data will be shown in runner UI when unit tests are run. Assert class is used to assert test results.  For example, in my first Assert statement I make sure that Company instance is valid once name is set.

When I run unit tests after setting up unit test application’s web site as start up project, here is what I see.

image

Test are setup to auto-run by default.  You will see the countdown label, and if you click on count down label, you will have a chance to select specific tests to run.

image

After tests are run, you will see test run summary in the top left cornet of the screen.  In my case I see that I had total of 1 test, and 2 test has passed.  if a test fails, you will see that in the test run summary.  You can download solution so far here.  In my next post I will cover asynchronous testing in Silverlight application.

Thanks.

Post to Twitter

Implementing Double-Click In Silverlight DataGrid

As I was working on one of my presentations, I wanted to go to a detail from from query form by letting user double-click.  No standard Silverlight controls implement double-clicks, and this includes DataGrid.  So, naturally one would need to listen to click events and interpret clicks within a certain time to be a double-click.  In my case I will use 300 milliseconds.  Another fact to consider is that if you try to do hook up double-click to the DataGrid itself, you will be disappointed because LeftMouseButtonUp event only fires when there are no rows to get in the way.  So, to make this work we will have to use each row’s mouse events.  I am going to wrap this up in a behavior first.  I am going to call this behavior  DataGridMouseLeftButtonDownCommandBehavior.  Here is what my class looks like, and it is very simple.  As you see, I am inheriting from CommandBase from Prism (Composite Application Guidance for Silverlight/WPF).

using System;
using Microsoft.Practices.Composite.Presentation.Commands;
using System.Windows.Controls;
using System.Windows.Input;
 
namespace CompanyModule.Converters
{
    /// <summary>
    /// Inherit from command base from Prism
    /// </summary>
    public class DataGridMouseLeftButtonDownCommandBehavior : CommandBehaviorBase<DataGrid>
    {
        /// <summary>
        /// Last time mouse was clicked
        /// </summary>
        private DateTime _lastTime;
 
        /// <summary>
        /// Number of milliseconds to interpret as doible-click
        /// </summary>
        private const long MillisesondsForDoubleClick = 300;
 
        /// <summary>
        /// Create new instance
        /// </summary>
        /// <param name="dataGrid">DataGrid to attach behavior to</param>
        public DataGridMouseLeftButtonDownCommandBehavior(DataGrid dataGrid)
            : base(dataGrid)
        {
            dataGrid.LoadingRow += OnLoadingRow;
            dataGrid.UnloadingRow += OnUnloadingRow;
        }
 
        /// <summary>
        /// Hook up mouse events
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnUnloadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.MouseLeftButtonUp -= OnMouseLeftButtonDown;
        }
 
        /// <summary>
        /// Unhook events to avoid memory leaks
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnLoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.MouseLeftButtonUp += OnMouseLeftButtonDown;
        }
 
 
        private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // if timing is right, fire command
            if ((DateTime.Now.Subtract(_lastTime).TotalMilliseconds) < MillisesondsForDoubleClick)
            {
                ExecuteCommand();
            }
            // reset the time
            _lastTime = DateTime.Now;
        }
    }
}

 

Now that we have behavior of the way, we need to come up with a clean way to hook it up as well as setting a command and command parameter onto a DataGrid.

I am going to use a static class and attached properties.  Attached properties are a feature of Silverlight that would allow us to set properties on one object via properties defined on another object.  Most common example of them is Grid control in Silverlight.  If you add a child control to a Grid, you set its location by using Grid.Column or Grid.Row on child control itself, such as Textbox.  Properties that I am going to need are Command and CommandParameter as well as a property I can attach my behavior to.  I am again using Prism for my project.  Here is what my attached properties look like:

    public static class DataGridDoubleClick
    {
        private static readonly DependencyProperty DataGridDoubleClickCommandBehaviorProperty = 
            DependencyProperty.RegisterAttached(
                "DataGridDoubleClickCommandBehavior",
                typeof(DataGridMouseLeftButtonDownCommandBehavior),
                typeof(DataGridDoubleClick),
                null);
 
        public static readonly DependencyProperty CommandProperty = 
            DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(DataGridDoubleClick),
                new PropertyMetadata(OnSetCommand));
 
        public static readonly DependencyProperty CommandParameterProperty = 
            DependencyProperty.RegisterAttached(
               "CommandParameter",
               typeof(object),
               typeof(DataGridDoubleClick),
               new PropertyMetadata(OnSetCommandParameter));

 

I am defining call backs in order to be able to attach my behavior to the DataGrid in those.  The reason I cannot just put behavior inside XAML is because I need to pass DataGrid to my behavior as a parameter.  I am using attached property for the behavior because this makes it easy to store in static environment.

Here is how I am hooking up behavior in call back methods.


        private static void OnSetCommand
            (DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            DataGrid dataGrid = dependencyObject as DataGrid;
            if (dataGrid != null)
            {
                DataGridMouseLeftButtonDownCommandBehavior behavior = GetBehavior(dataGrid);
                behavior.Command = e.NewValue as ICommand;
            }
        }
 
        private static void OnSetCommandParameter
            (DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            DataGrid dataGrid = dependencyObject as DataGrid;
            if (dataGrid != null)
            {
                DataGridMouseLeftButtonDownCommandBehavior behavior = GetBehavior(dataGrid);
                behavior.CommandParameter = e.NewValue;
            }
        }

 

The final part is how to set the behavior.  Here is the short method for it:

        private static DataGridMouseLeftButtonDownCommandBehavior GetBehavior(DataGrid dataGrid)
        {
            DataGridMouseLeftButtonDownCommandBehavior behavior =
                dataGrid.GetValue(DataGridDoubleClickCommandBehaviorProperty) 
                    as DataGridMouseLeftButtonDownCommandBehavior;
            if (behavior == null)
            {
                behavior = new DataGridMouseLeftButtonDownCommandBehavior(dataGrid);
                dataGrid.SetValue(DataGridDoubleClickCommandBehaviorProperty, behavior);
            }
            return behavior;
        }

 

Now the final step – XAML for my data grid:

<UserControl
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  
   xmlns:command="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;
           assembly=Microsoft.Practices.Composite.Presentation"

   xmlns:converters="clr-namespace:CompanyModule.Converters"
   xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
   x:Class="CompanyModule.Views.CompanyListView"
   mc:Ignorable="d"
   d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" HorizontalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Content="Get Companies" command:Click.Command="{Binding GetCompaniesCommand}"/>
        <my:DataGrid 
           Grid.Row="1" 
           ItemsSource="{Binding CompanyList}" 
           HorizontalAlignment="Stretch"
           converters:DataGridDoubleClick.Command="{Binding Path=DoubleClickCommad}"
           converters:DataGridDoubleClick.CommandParameter="{Binding RelativeSource={RelativeSource Self},
             
Path=SelectedItem}"
           SelectionMode="Single">
           
        </my:DataGrid>
        <Rectangle Grid.RowSpan="2" 
                  Fill="LightBlue" 
                  Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}" 
                  Opacity="0.3"/>
    </Grid>
</UserControl>

 

Here is what my command looks like in ViewModel:

public DelegateCommand<object> DoubleClickCommad { get; private set; }

DoubleClickCommad = new DelegateCommand<object>(SelectCompanyForEdit);

 

private void SelectCompanyForEdit(object load)
{
  if (load != null && load is Company)
    {
      MessageBox.Show(((Company)load).CompanyName);
    }
}

 

And that is all there is to it.

Thanks.

Post to Twitter

First Stab at Reactive Framework

Today I made an attempt to make some sense of Reactive Framework(Rx).  Rx allows developers to write queries against events.  I know, I had hard time wrapping my head around this concept as well.  I hope the example below will help.

I downloaded and installed Rx extensions for Silverlight from the page above.  I created new Silverlight project and added references to three DLLs that are included with Rx:

System.CoreEx, System.Observable, System.Reactive.

In attempt to save time I created RIA Services project.  Rx is not as good of a fit for the Rx pattern, so my example is a bit contrived.

First, I am creating new instance of domain context

RXContext context;

Now, I am creating new query and starting the load for it:

            var talks = context.GetTalksQuery();


            var op = context.Load<Talk>(talks, LoadBehavior.RefreshCurrent, false);

Now, the fun part:  I am creating two event handlers by querying completed event with two different where clauses – one for error, the other for success:


    var events = Observable.FromEvent((EventHandler<EventArgs> eventInstance) =>
        new EventHandler(eventInstance),
            eventInstance => op.Completed += eventInstance,
            eventInstance => op.Completed -= eventInstance);
    var subsc = events.Where(ev => op.Error == null).Subscribe((args) =>
        { gridTalks.ItemsSource = op.AllEntities; });
    var errorSubs = events.Where(ev => op.Error != null).Subscribe((args) =>
        { MessageBox.Show(op.Error.ToString()); });

In the first statement I am converting regular event to observable event.  In the other two statement I am creating two event subscriptions with different where clauses.

Rx supports other clauses, such as group by as well.  I can see that Rx in general can result in cleaner, more readable code.  You can find more details at this Rx 101 page.

Post to Twitter

Tool Tip Usage in Silverlight Application

I have not blogged in a month.  What I found out in that time is that working 60-70 hours a week on two separate projects with deadlines is not very conducive to blogging :-).  Now that I am off one of the projects, I should have more time to get into the routine of blogging weekly which has been my goal for a while.

Tooltips are pretty common in business applications.  They save real estate on the screen for developers.  They also provide users with ability to see more details without any button clicks.

It is very easy to setup a simple tool tip.  Here is a quick example:

        <TextBox 
           TextWrapping  ="Wrap" 
           Text="{Binding Path=CurrentPerson.FirstName}" 
           d:LayoutOverrides="Width, Height" 
           Grid.Column="1" 
           ToolTipService.ToolTip="{Binding Path=CurrentPerson.FullName}"/>

In this example I am binding text of a TextBox to FirstName of my person class.  Here is what my person class looks like:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;

namespace SilverlightToolTipDemo
{
    public class Person
    {
        public Person()
        {
            LastName = "Barskiy";
            FirstName = "Sergey";
            FullName = "Mr. Sergey Barskiy";
            Occupation = "Programmer";
            MaritalStatus = "Married";
            BitmapImage image = new BitmapImage(new Uri("../Images/Sergey_Barskiy.jpg", UriKind.RelativeOrAbsolute));
            Photo = image;

        }

        public string LastName { get; set; }
        public string FirstName { get; set; }
        public string FullName { get; set; }
        public string Occupation { get; set; }
        public string MaritalStatus { get; set; }
        public ImageSource Photo { get; set; }


    }
}

This looks pretty boring though.  Too much like old WinForms :-).

Let’s now use Silverlight capabilities and jazz it up a bit.

In the simple case you can just assign a string to tool tip and it will be shown on mouse-over event.  However, ToolTip property of ToolTipService can do a lot more.  You can put a control inside of it!  In my case, I want to show full name, photo, occupation and martial status.  Sounds complicated?  It is not.  Here is what it should look like:

        <TextBox
            Text="{Binding Path=CurrentPerson.LastName}"
            Grid.Column="1"
            d:LayoutOverrides="Width, Height"
            Grid.Row="1">
            <ToolTipService.ToolTip>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Image
                        Source="{Binding Path=CurrentPerson.Photo}"
                        Grid.ColumnSpan="2"
                        Grid.Row="0"
                        Width="100"
                        Height="100"
                        Stretch="UniformToFill"/>
                    <TextBlock
                        Grid.Row="1"
                        Text="Full Name:"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Center"/>
                    <TextBlock
                        Grid.Row="1"
                        Text="{Binding Path=CurrentPerson.FullName}"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Center"
                        Grid.Column="1"/>
                    <TextBlock
                        Text="Occupaton:"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Center"
                        Grid.Row="2"/>
                    <TextBlock
                        Text="{Binding Path=CurrentPerson.Occupation}"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Center"
                        Grid.Column="1"
                        Grid.Row="2"/>
                    <TextBlock
                        Text="Marital Status:"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Center"
                        Grid.Row="3"/>
                    <TextBlock
                        Text="{Binding Path=CurrentPerson.MaritalStatus}"
                        d:LayoutOverrides="Width, Height"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Center"
                        Grid.Column="1"
                        Grid.Row="3"/>
                </Grid>
            </ToolTipService.ToolTip>
        </TextBox>

Pretty easy, hah?  When I move my mouse over this textbox, I will see my photo along with additional information:

image

You can download full sample application here.

Thanks.

Post to Twitter

ReMix Talk

As I posted previously, I talked at Atlanta ReMix 2010 conference past Saturday.  Entire event was a a success, we had over 200 people there.  We had great presenters and good topics.  My topic was “Microsoft Silverlight and Windows Azure: A Match Made for the Web”

You can download PowerPoint presentation here.  You can download solution here.  To get solution up and going, you need to have Visual Studio 2010 installed, along with Silverlight 4 tools and Azure tools.  You will also need to sign up for an account on Azure and SQL Azure.  You will need to update web.config file and ServiceReference.ClientConfig file.

Please let me know if you have any questions.

Thank you.

Post to Twitter

ElementName Binding Inside Silverlight DataGrid

If you ever used ComboBox inside a templated columns inside DataGrid in Silverlight, you probably encountered the following issue. 

If you use ElementName to bind ItemsSource for a ComboBox in this situation, you will find that ElementName cannot be resolved.  Typically, you have to put your items source inside Resources collection on your use control, and use binding with StaticResource.  This is quite a pain, especially if you are using MVVM pattern, such as Prism.  This problems has been a sore spot for me for a while, but I did not have time to come up with a good solution.

Today I gave it some thought, and it hit me.  I should use a behavior to solve the problem.  The approach I took is manually look for the bound element one the ComboBox is part of visual tree.  I can do this inside Loaded event.  Here is how I got started:

    public class ResolveElementName : TargetedTriggerAction<FrameworkElement>

    {

        protected override void OnAttached()

        {

            base.OnAttached();

            Target.Loaded += Target_Loaded;

        }

 

        protected override void OnDetaching()

        {

            base.OnDetaching();

            Target.Loaded -= Target_Loaded;

        }

 

        private void Target_Loaded(object sender, RoutedEventArgs e)

        {

I also added a Dependency Property:

        public string PropertyName

        {

            get { return (string)GetValue(PropertyNameProperty); }

            set { SetValue(PropertyNameProperty, value); }

        }

 

        public static readonly DependencyProperty PropertyNameProperty =

            DependencyProperty.Register("PropertyName", typeof(string), typeof(ResolveElementName), new PropertyMetadata(string.Empty));

 

        protected override void Invoke(object parameter)

        {

            // do nothing

        }

 

The next step is to look how I typically setup ComboBox inside data gird.  I would like to keep the code as close to usual setup as possible to minimize the learning of new functionality.  Here is XAML from my test program.  This also shows how behavior is setup.

        <grid:DataGrid

            ItemsSource="{Binding People}"

            x:Name="PoepleBox"

            Grid.Row="3"

            AutoGenerateColumns="False" >

            <grid:DataGrid.Columns>

                <grid:DataGridTemplateColumn>

                    <grid:DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <TextBlock Text="{Binding Path=Name}" Margin="7"/>

                        </DataTemplate>

                    </grid:DataGridTemplateColumn.CellTemplate>

 

                </grid:DataGridTemplateColumn>

                <grid:DataGridTemplateColumn>

                    <grid:DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <TextBlock

                                Text="{Binding Path=StatusID}"

                                Margin="7"/>

                        </DataTemplate>

                    </grid:DataGridTemplateColumn.CellTemplate>

 

                </grid:DataGridTemplateColumn>

                <grid:DataGridTemplateColumn>

                    <grid:DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <ComboBox

                                SelectedValue="{Binding Path=StatusID, Mode=TwoWay}"

                                DisplayMemberPath="StatusName"

                                SelectedValuePath="StatusID"

                                ItemsSource="{Binding ElementName=LayoutRoot, Path=DataContext.Statuses}" 

                                Margin="7"

                                Width="200" >

                                <i:Interaction.Triggers>

                                    <i:EventTrigger>

                                        <behavior:ResolveElementName PropertyName="ItemsSource" />

                                    </i:EventTrigger>

                                </i:Interaction.Triggers>

                            </ComboBox>

                        </DataTemplate>

                    </grid:DataGridTemplateColumn.CellTemplate>

 

                </grid:DataGridTemplateColumn>

            </grid:DataGrid.Columns>

        </grid:DataGrid>

Also, you will need to import name spaces to get this to work as following:

<UserControl x:Class="ResolveElementNameBehaviorDemo.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:local="clr-namespace:ResolveElementNameBehaviorDemo"

    xmlns:grid="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

    xmlns:behavior="clr-namespace:ResolveElementNameBehavior;assembly=ResolveElementNameBehavior"

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"  

 

Now, I would like to show you how I am updating ItemsSource binding by replacing element name binding with regular source based binding:

        private void Target_Loaded(object sender, RoutedEventArgs e)

        {

 

            if (Target != null)

            {

                var fields = Target.GetType().GetFields(

                    System.Reflection.BindingFlags.Public |

                    System.Reflection.BindingFlags.FlattenHierarchy |

                    System.Reflection.BindingFlags.Static);

                foreach (var field in fields)

                {

                    if (field.FieldType == typeof(DependencyProperty) &&

                        (field.Name == PropertyName ||

                        field.Name == string.Concat(PropertyName, "Property")))

                    {

                        DependencyProperty dp = field.GetValue(Target) as DependencyProperty;

                        var binding = Target.GetBindingExpression(dp);

                        string elementName = binding.ParentBinding.ElementName;

                        if (!string.IsNullOrEmpty(elementName))

                        {

                            DependencyObject boundToElement = GetElementBasedOnName(Target, elementName);

                            if (boundToElement != null)

                            {

                                Binding newBinding = new Binding();

                                Binding oldBinding = binding.ParentBinding;

                                newBinding.BindsDirectlyToSource = oldBinding.BindsDirectlyToSource;

                                newBinding.Converter = oldBinding.Converter;

                                newBinding.ConverterCulture = oldBinding.ConverterCulture;

                                newBinding.ConverterParameter = oldBinding.ConverterParameter;

                                newBinding.FallbackValue = oldBinding.FallbackValue;

                                newBinding.Mode = oldBinding.Mode;

                                newBinding.NotifyOnValidationError = oldBinding.NotifyOnValidationError;

                                newBinding.Path = oldBinding.Path;

                                newBinding.Source = boundToElement;

                                newBinding.StringFormat = oldBinding.StringFormat;

                                newBinding.TargetNullValue = oldBinding.TargetNullValue;

                                newBinding.UpdateSourceTrigger = oldBinding.UpdateSourceTrigger;

                                newBinding.ValidatesOnDataErrors = oldBinding.ValidatesOnDataErrors;

                                newBinding.ValidatesOnExceptions = oldBinding.ValidatesOnExceptions;

                                newBinding.ValidatesOnNotifyDataErrors = oldBinding.ValidatesOnNotifyDataErrors;

                                if (Target is ComboBox)

                                {

                                    ComboBox combo = Target as ComboBox;

                                    combo.SetBinding(dp, newBinding);

                                    combo.SetBinding(ComboBox.SelectedValueProperty,

                                        combo.GetBindingExpression(ComboBox.SelectedValueProperty).ParentBinding);

                                }

                                else

                                {

                                    Target.SetBinding(dp, newBinding);

                                }

                               

                            }

                        }

                    }

                }

            }

        }

 

Last step, let me show you how to look for an element with a specific name inside visual tree.  I will use a recursive function that will use VisualTreeHelper class:

        private static DependencyObject GetElementBasedOnName(DependencyObject startPoint, string elementName)

        {

            DependencyObject returnValue = null;

            if (startPoint != null)

            {

                DependencyObject parent = VisualTreeHelper.GetParent(startPoint);

                if (parent != null)

                {

                    FrameworkElement fe = parent as FrameworkElement;

                    if (fe != null)

                    {

                        if (fe.Name == elementName)

                        {

                            returnValue = fe;

                        }

                        else

                        {

                            returnValue = GetElementBasedOnName(fe, elementName);

                        }

                    }

                    else

                    {

                        returnValue = GetElementBasedOnName(fe, elementName);

                    }

                }

            }

            return returnValue;

        }

 

This is it.  There as couple of downsides of this approach.  First of all, there is a small flash when combo is bound.  It is hard to notice though.  The other downside is the overhead of looking for a parent.  However, this is not visibly noticeable.  I tested with a data grid with 100 items, and I do not see any hesitation when scrolling.

You can download the entire solution with behavior and test application here.

I also published it to Microsoft Expression Gallery.

Please let me know if you have any questions.. 

Post to Twitter

Windows Phone 7 Database

I just uploaded and published new CodePlex project I have been working on.  It is an Isolated Storage based database for Windows Phone 7.  I converted my existing Silverlight database project I published a long time ago and adapted it to Windows Phone 7. It supports multiple strongly typed tables, basic Linq based operations, addition and deletion of ranges of items, deletion of items based on condition.  You can also directly bind data to UI in Silverlight because base table inherits from ObservableCollection.  It supports encryption along with lazy loading of table. 

Please take a look at http://winphone7db.codeplex.com/

 

Here are key classes of the project.  ITable interface makes it easy to write generic code in Database class.  It is a simple interface as you can see:

using System;
using System.IO;

namespace SilverlightPhoneDatabase.Core
{
    /// <summary>
    /// Interface that is used for tables in a database
    /// </summary>
    public interface ITable
    {
        /// <summary>
        /// Type of object that database contains
        /// </summary>
        Type RowType { get; }

        /// <summary>
        /// Save table le to the Isolated Storage
        /// </summary>
        void Save();

        /// <summary>
        /// Write content of a table to a file stream
        /// </summary>
        /// <param name="stream">Stream to write table to</param>
        void WriteDTableToStream(Stream stream);

        /// <summary>
        /// Set internal variables data when a table is de-serialized
        /// </summary>
        /// <param name="databaseName">Database name that table belongs to</param>
        /// <param name="password">Password to use for encryption</param>
        void SetTableDefinition(string databaseName, string password);
    }
}

I use XML Serializer to store table to Isolated Storage:

using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        string fileName = string.Concat(_databaseName, ".", typeof(T).FullName);
#if SILVERLIGHT
                        if (store.FileExists(fileName))
                        {
                            store.DeleteFile(fileName);
                        }
#else
                        if (store.GetFileNames(fileName).Length > 0)
                        {
                            store.DeleteFile(fileName);
                        }
#endif
                        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.OpenOrCreate, store))
                        {
                            WriteDTableToStream(stream);
                        }
                    }

 

Writing data to stream is very easy:

 /// <summary>
        /// Write content of a table to a stream
        /// </summary>
        /// <param name="stream">Stream to write table to</param>
        public void WriteDTableToStream(Stream stream)
        {
            string content = string.Empty;
            using (StringWriter stringWriter = new StringWriter())
            {
                XmlSerializer serializer = new XmlSerializer(this.GetType());

                serializer.Serialize(stringWriter, this);
                stringWriter.Flush();
                content = stringWriter.GetStringBuilder().ToString();
                if (!string.IsNullOrEmpty(_password))
                {
                    content = Cryptography.Encrypt(content, _password);
                }
                stringWriter.Close();
            }

            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(content);
                writer.Flush();
                writer.Close();
            }
        }

The most interesting part of Database class is probably table loading.  This is done via generic function Table<T>:

/// <summary>
        /// FInd instance of a table that contains specific row type
        /// </summary>
        /// <typeparam name="T">Type of object that this table contains</typeparam>
        /// <returns></returns>
        public Table<T> Table<T>()
        {
            ITable returnValue = (from oneTable in Tables
                                  where oneTable.RowType == typeof(T)
                                  select oneTable).FirstOrDefault();
            if (_useLazyLoading && !_loadedTables[typeof(T)])
            {
                Type tableType = typeof(Table<>).MakeGenericType(new Type[] { typeof(T) });
                string fileName = string.Concat(_databaseName, ".", typeof(T).FullName);
                using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream tableStream = new IsolatedStorageFileStream(fileName, FileMode.Open, store))
                    {
                        LoadTable(tableStream, tableType);
                        tableStream.Close();
                    }
                }
                _loadedTables[typeof(T)] = true;
                returnValue = (from oneTable in Tables
                               where oneTable.RowType == typeof(T)
                               select oneTable).FirstOrDefault();
            }
            return (Table<T>)returnValue;

        }

 

I would very much appreciate comments and feature requests related to this project.

Thanks in advance for the feedback.

Post to Twitter

ReMix 2010 in Atlanta

If you have not registered for this fine event I blogged about previously, you have a week left.

You can register for it here: http://reMIXatlanta.org.  You can also check out the list of session that will be presented there.

Yours truly will be presented a session there as well.  The title will be “Microsoft Silverlight and Windows Azure: A Match Made for the Web”.

Here is what they session is about:

By combining the rich user experience of Silverlight with the scalability of Windows Azure compute and storage, you can build some incredible end-to-end web applications. In this session we will discuss the business advantages of running Silverlight applications in the cloud. We will cover the steps necessary to build Silverlight applications for deployment in Azure including: data access with SQL Azure, cloud storage, communication mechanisms and data access options. We will also demonstrate how the same approach works for Windows Phone 7 development.

I am just as excited about speaking as I am about attending other sessions.  One can always learn a ton at the community events.

Post to Twitter

Atlanta .NET Talk on Windows Phone 7

I had a privilege to present on Silverlight development for Windows Phone 7 at local Atlanta.NET Users Group today, March 29th 2010.

You can download PowerPoint presentation here.  Please email me any questions you have regarding the presentation.

Thanks.

Post to Twitter

Windows Phone 7 Application with OData

In this post I will continue exploring Windows Phone 7 development.  Almost any application needs a data source.  There are a few options available for Silverlight applications on Windows Phone.  You can use plain WCF service.  You can optionally put it on Azure.  You can also use Isolated Storage.  Essentially it becomes your custom database.  Of course, you have to write all the API in this case.  Or, you can use OData.  OData approach is the one I am exploring in this post.

First things first, you need to download CTP for OData on Windows Phone.  Here is the link for this download:

http://www.microsoft.com/downloads/details.aspx?FamilyID=b251b247-70ca-4887-bab6-dccdec192f8d&displaylang=en

Download and unzip the files into a folder.  You will need a DLL that is contained in this download – System.Data.Services.Client.Dll

You can follow my previous post and create new Silverlight application for Windows Phone.  There is small change you will need to make.  You need to select the following project template:

image

Now we need to pick an OData source.  I am going to look at www.OData.Org to find one.  I am picking Mix 2010, but you can select any other.  Here is the link I found on OData site – http://api.visitmix.com/OData.svc/

You can always browse the service.  In my case I am going to generate a proxy for this service by running the following command from Microsoft.NET/v4 directory on your local machine:

DataSvcutil.exe /uri:http://api.visitmix.com/OData.svc /DataServiceCollection /Version:2.0 /out:VisitMixClientTypes.cs

DataSvcuil is the .NET utility that generates proxies for ADO.NET Data Services or OData.

Once this is done, copy generated file (VisitMixClientTypes.cs) into the project folder and include it in the project.  What we have inside the file is the proxy for OData service.

Nest step is to update the XAML to match our proxy.  In my simple example I will use the list of sessions and show it on the front page.  Here is what my XAML looks like for my main page (MainPage.xaml)

 

 

<!--ContentGrid contains ListBox. Place additional content here-->
<Grid x:Name="ContentGrid" Grid.Row="1">
    <Grid.Projection>
        <PlaneProjection/>
    </Grid.Projection>
    <ListBox x:Name="ListBoxOne" MouseLeftButtonUp="ListBoxOne_MouseLeftButtonUp"
             Style="{StaticResource PhoneListBox}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel x:Name="DataTemplateStackPanel" Orientation="Horizontal">
                    <Border x:Name="DataTemplateBorder" Height="44" Width="44" BorderBrush="White"
                            BorderThickness="2.5" CornerRadius="100" Margin="10,16,0,0"
                            VerticalAlignment="Top">
                        <Path x:Name="DataTemplatePath" Height="16" Width="11" Fill="White"
                              Stretch="Fill" Margin="4,0,0,0" HorizontalAlignment="Center"
                              VerticalAlignment="Center" UseLayoutRounding="False"
                              Data="M337.59924,129.61948 L337.59924,141.51501 L345.5704,135.87381 z"/>
                    </Border>
                    <mpc:ListViewItem Layout="TextAndDetailsWithIcon" Text="{Binding Title}"
                                      Details="{Binding Body}" Style="{StaticResource PhoneListBoxItemLayout}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

I am only copying the main portion of UI, not entire page here.

I am also going to update the details page that is generated by the project wizard to match my data as well.  Here is what it looks like:

<Grid x:Name="LayoutRoot"
      Background="{StaticResource PhoneBackgroundBrush}"
      d:DataContext="{Binding Items[0]}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!--TitleGrid is the name of the application and page title-->
    <Grid x:Name="TitleGrid" Grid.Row="0">
        <Grid.Projection>
            <PlaneProjection/>
        </Grid.Projection>
        <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextPageTitle2Style}"/>
    </Grid>
    <!--ContentGrid contains the details-->
    <Grid x:Name="ContentGrid" Grid.Row="1">
        <Grid.Projection>
            <PlaneProjection/>
        </Grid.Projection>
        <TextBlock TextWrapping="Wrap" Text="{Binding Body}"
                   Style="{StaticResource PhoneTextBodyTextStyle}"/>
    </Grid>
</Grid>

Now, let’s work on code behind to call our OData service.  Here is entire code behind for MainPage.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using EventModel;
using System.Collections.ObjectModel;
using System.Data.Services.Client;
using System.Windows.Input;
namespace WindowsPhoneListApplication1
{
    public partial class MainPage : PhoneApplicationPage
    {
        object _selectedItem;
        EventEntities _entities = new EventEntities(new Uri("http://api.visitmix.com/OData.svc/"));
        public MainPage()
        {
            InitializeComponent();
            SupportedOrientations = SupportedPageOrientation.Portrait;
            Loaded += new RoutedEventHandler(MainPage_Loaded);
            PageTransitionList.Completed += new EventHandler(PageTransitionList_Completed);
            var query = _entities.CreateQuery<Session>("Sessions");
            query.BeginExecute(ar =>
            {
                DataLoaded(ar);
            }, query);
        }
        private void DataLoaded(IAsyncResult result)
        {
            try
            {
                DataServiceQuery<Session> query = result.AsyncState as DataServiceQuery<Session>;
                List<Session> sessions = query.EndExecute(result).ToList();
                Dispatcher.BeginInvoke(() =>
                    {
                        this.ListBoxOne.ItemsSource = sessions;
                    });
            }
            catch (Exception ex)
            {
                Exception thing = ex;
            }
        }
        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Reset page transition
            ResetPageTransitionList.Begin();
        }
        private void ListBoxOne_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // Capture selected item data
            _selectedItem = (sender as ListBox).SelectedItem;
            // Start page transition animation
            PageTransitionList.Begin();
        }
        private void PageTransitionList_Completed(object sender, EventArgs e)
        {
            // Set datacontext of details page to selected listbox item
            NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
            FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
            root.DataContext = _selectedItem;
        }
    }
}

The code above is fairly easy.  First, I create a DataSericeQuery of type Session.  Session type is part of our generated proxy.  It then call BeginExecute and pass it a handler.  Inside the handler (DataLoaded) I fire EndExecute, then set the items source for my ListBox.  I have to make sure to use Dispatcher for this call, otherwise I will get cross thread access exception because handler is not firing on UI thread.

That is it.  You can now run the application and see the list of sessions at the MIX 2010.  You can also click on an item to see the details.

Please post your questions here.

Thanks.

Post to Twitter

Getting Started with Windows Phone 7 and Silverlight

In this post I will go through the steps of creating my first Windows Phone 7 application using Silverlight.  It will be simple and will mostly concentrate on tools rather than phone specific functionality.  Of course, I will do more posts describing features that are specific to Silverlight for Windows Phone 7.

First thing I have to do is download the tools and install them on my machine.  You can find all appropriate link on www.Silverlight.net.  If you click on Getting Started menu, you can look for phone development tools.  You will download and install Visual Studio 2010 Express for Windows Phone.  Once you are done with that task, start the studio.

Here is what the screen look like.

image

Let’s go ahead and click on New Project link.  Let’s select Silverlight tree node, then Windows Phone application.  One side note – no VB.NET menu inside Studio for Phone.

image

Once project is created, you will see the screen that contains three parts by default – solution explorer, XAML view and Design view.

image

Now we can even run the application.  Let’s go ahead and do this.  What we will see is the Phone emulator as well as studio going to debug mode.  it will take a few minutes first time you run as emulator initializes.  You can resize the emulator by clicking on the menu that I have pointed to with a hand cursor on the picture below.  Eventually application loads, and you will the application just created, more precisely title and subtitle blocks.

image

Let’s add a few controls and some code now.  You will notice that when you stop debugging the studio that emulator keeps running.  This is good, and you want to keep it running in order to save deployment and initialization time. 

We will use the studio’s designer surface to add controls to the surface.  To do so, activate toolbox and pin it.

image

Let’s drag and drop a button onto design surface.  Here is what we will see now.

image

Let’s now add event handler for click event.  To do so, double-click on the button on design surface.  Code view will open and handler will be created.  We will do something really simple, we will change the title as follows:

 

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            this.textBlockPageTitle.Text = "I changed the title";
        }

Let’s run the application and see our code in action by clicking on the button.  Now, the step we are going to do is explore debugging.  To do so, set a breakpoint inside the event handler.

image

Run the application again from studio by clicking on debug button inside the studio.  I put hand cursor next the button.

image

Once the emulator loads the application, click on the new button inside the application we added.  Voila!  Our break    point got hit.

 

I illustrated in this post how to create a sample application inside Express Studio for Windows Phone, add controls to the design surface, write code behind and set breakpoints.

One last note.  You will notice that even new controls dropped onto design surface are styled certain ways to match overall phone design.  If you wonder why, it is because new project wizard comes preloaded with default styles for all basic controls.  To look at those styles, just open app.xaml.  For example, you can search for TargetType="ButtonBase" to see style for button.

There will be more to come as I explore phone specific features in Silverlight for Windows phone.

Thanks.

Post to Twitter

Silverlight 4 + COM + SQL Server = Cool!

Today is the day to talk about COM possibilities in Silverlight 4.  One would question the titles of my post.  COM and Cool in the same sentence?  Let me proof this title to you.

First, let me take a closer look at COM.  In order to access COM, you must install Silverlight application on a local machine.  The access to COM is not enabled when a Silverlight application is run in the browser.  So, first of all you have to enable this by checking “Enable running application out of browser” checkbox in project properties.  Second of all, you have to check “Require elevated trust…” checkbox in “Out-of-browser settings” area in project properties.  Now, you are ready to install you application and test COM support.  How about Word automation:

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
var doc = word.Documents.Add();
var paragraph = doc.Paragraphs.Add();
paragraph.Range.Text = "Some text";

Now, let’s talk about database access.  Parts of System.Data.SqlClient namespace are not exposed to COM by default.  So, to enable database access we must write an assembly that is exposed to COM that wraps database access.  To do so, check the property “Register for COM Interop” in project properties for the .NET (NOT Silverlight) based project that will fire off database queries for us.  Once the assembly is built, I can just use RegAsm to register my DLL with COM on a machine.  Of course, this would be a prerequisite to use Silverlight application for local data access.  The other prerequisite is to have .NET Runtime installed on that machine as well.  I could write an install project of course to make this process easier.

The next step is to write a Silverlight assembly that would use COM Interop similar to the one above for Word to talk to my database access .NET based assembly.

dynamic sqlDB = ComAutomationFactory.CreateObject("COMSQLClient.COMSqlDatabase");

Now the most exciting part.  I created and published the project on CodePlex that does exactly what I just talked about.  Check out the project and let me know what you think.  You can download the source code and look into the implementation details.  Here is the link to it:

http://silverlight4sqllib.codeplex.com/

Thanks.

Post to Twitter

Silverlight, MVVM and Animations

Yesterday I was asked about a way to play animations in MVVM environment.

So, I gave this some thought today, and came up with a few ideas.

First, and the easiest way is to separate ViewModel from animation by attaching an animation to a behavior.  Here is how we would write the behavior:

public class MVVMSimpleAnimationBehavior : TargetedTriggerAction<UIElement>

{

    protected override void Invoke(object parameter)

    {

        RunAnimation();

    }

 

    public Storyboard AnimationStoryBoard

    {

        get { return (Storyboard)GetValue(AnimationStoryBoardProperty); }

        set { SetValue(AnimationStoryBoardProperty, value); }

    }

 

    public static readonly DependencyProperty AnimationStoryBoardProperty =

        DependencyProperty.Register("AnimationStoryBoard", typeof(Storyboard), typeof(MVVMSimpleAnimationBehavior), new PropertyMetadata(null));

 

 

    private void RunAnimation()

    {

        if (AnimationStoryBoard != null)

        {

            AnimationStoryBoard.Begin();

        }

    }

}

 

Pretty simple approach.  Here is how would use animation in the XAML:

<Button Content="Behavior Test" Grid.Column="1">

    <i:Interaction.Triggers>

        <i:EventTrigger EventName="Click">

            <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}"/>

        </i:EventTrigger>

    </i:Interaction.Triggers>

</Button>

Now, I want to complicate the story a little bit.  I really want to trigger an animation in the UI via an event in my model.  I am going to start with a sample ViewModel.  I want to have an event there that I will later use as a trigger for my animation.  Here is what my ViewModel would look like:

public class SampleModel: INotifyPropertyChanged

{

 

    public event EventHandler StartAnimation;

 

    protected virtual void OnStartAnimation()

    {

        if (StartAnimation != null)

        {

            StartAnimation(this, EventArgs.Empty);

        }

    }

 

    public void RaiseEvent()

    {

        OnStartAnimation();

    }

 

    #region INotifyPropertyChanged Members

 

    public event PropertyChangedEventHandler PropertyChanged;

 

    protected virtual void OnPropertyChanged(string propertyName)

    {

        if (PropertyChanged != null)

        {

            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

 

    #endregion

}

My event is called StartAnimation.  Now it is time to develop a more complicate behavior to support my event driven animation from ViewModel.  I am going to actually combine new functionality with the simple behavior about and have multi-functional useful object.  Here is what the final product looks like:

using System;

using System.Windows.Interactivity;

using System.Windows;

using System.Windows.Media.Animation;

using System.ComponentModel;

using System.Reflection;

 

 

namespace SLMVVMAnimationBehavior

{

    public class MVVMAnimationBehavior : TargetedTriggerAction<UIElement>

    {

        private EventInfo info;

        protected override void Invoke(object parameter)

        {

            RunAnimation(this, EventArgs.Empty);

        }

 

        public Storyboard AnimationStoryBoard

        {

            get { return (Storyboard)GetValue(AnimationStoryBoardProperty); }

            set { SetValue(AnimationStoryBoardProperty, value); }

        }

 

        public static readonly DependencyProperty AnimationStoryBoardProperty =

            DependencyProperty.Register("AnimationStoryBoard", typeof(Storyboard), typeof(MVVMAnimationBehavior), new PropertyMetadata(null));

 

        public string EventName

        {

            get { return (string)GetValue(EventNameProperty); }

            set { SetValue(EventNameProperty, value); }

        }

 

        public static readonly DependencyProperty EventNameProperty =

            DependencyProperty.Register("EventName", typeof(string), typeof(MVVMAnimationBehavior), new PropertyMetadata(HandlModelChanged));

 

 

        public object Model

        {

            get { return GetValue(ModelProperty); }

            set { SetValue(ModelProperty, value); }

        }

 

        public static readonly DependencyProperty ModelProperty =

            DependencyProperty.Register("Model", typeof(object), typeof(MVVMAnimationBehavior), new PropertyMetadata(HandlModelChanged));

 

        private static void HandlModelChanged(object sender, DependencyPropertyChangedEventArgs e)

        {

            MVVMAnimationBehavior behavior = sender as MVVMAnimationBehavior;

            object model = behavior.Model;

            if (behavior.info != null)

            {

                behavior.info.RemoveEventHandler(model, Delegate.CreateDelegate(typeof(EventHandler), behavior, "RunAnimation"));

            }

            if (model != null && !string.IsNullOrEmpty(behavior.EventName))

            {

                behavior.info = model.GetType().GetEvent(behavior.EventName);

                behavior.info.AddEventHandler(model, Delegate.CreateDelegate(typeof(EventHandler), behavior, "RunAnimation"));

 

            }

        }

 

        private void RunAnimation(object sender, EventArgs e)

        {

            if (AnimationStoryBoard != null)

            {

                AnimationStoryBoard.Begin();

            }

        }

    }

}

 

 

As you can see, I added two mode dependency properties – one for event name that will trigger the animation, the other one for ViewModel ( I actually called it model).  Now the tricky part is to use a bit of reflection to attach an event handler to the event on my model.  This is done in HandlModelChanged routine that is called when Model or Event name is set.  I am getting an event, and attaching a handler to it.  The actual handler is located inside the behavior itself – RunAnimation method.  Here is what my fianl XAML looks like that is testing both animation approaches:

<UserControl x:Class="SLMVVMAnimationBehavior.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:local="clr-namespace:SLMVVMAnimationBehavior"

    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

    <UserControl.Resources>

        <Storyboard x:Name="TestStoryboard">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="textBlock" Storyboard.TargetProperty="(TextBlock.FontSize)">

                <EasingDoubleKeyFrame KeyTime="00:00:00.1000000" Value="24"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.2000000" Value="21.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="18.667"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.4000000" Value="16"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.5000000" Value="13.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.6000000" Value="16"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.7000000" Value="18.667"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.8000000" Value="21.333"/>

                <EasingDoubleKeyFrame KeyTime="00:00:00.9000000" Value="24"/>

                <EasingDoubleKeyFrame KeyTime="00:00:01" Value="26.667"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <local:SampleModel x:Key="CurrentModel" />

        <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}" Model="{StaticResource CurrentModel}" x:Key="Animation" EventName="StartAnimation"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="#FFF3EEEE" DataContext="{Binding Source={StaticResource CurrentModel}}">

        <Grid>

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition Width="Auto"/>

                <ColumnDefinition/>

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto"/>

                <RowDefinition/>

            </Grid.RowDefinitions>

            <Button x:Name="TestButton" Content="Click To Start Animation" d:LayoutOverrides="Height" HorizontalAlignment="Left" Click="TestButton_Click"/>

            <Button Content="Behavior Test" Grid.Column="1">

                <i:Interaction.Triggers>

                    <i:EventTrigger EventName="Click">

                        <local:MVVMAnimationBehavior AnimationStoryBoard="{StaticResource TestStoryboard}"/>

                    </i:EventTrigger>

                </i:Interaction.Triggers>

            </Button>

            <TextBlock x:Name="textBlock" Margin="0,0,0,6" Text="Sample Text" TextWrapping="Wrap" d:LayoutOverrides="Width, Height" Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="26.667"/>

        </Grid>

 

    </Grid>

</UserControl>

 

To summarize, I illustrate a couple of approaches to trigger animations in MVVM environment.  Of course, there is always code-behind, but many developers frown at this approach..

Please let me know if you have any questions.

Post to Twitter

WCF RIA Services Validation

Today I am continuing exploring WCF RIA Services.  I am going to discuss validation in RIA Services.

Any business application needs to validate user input.  I am going to start with a simple case.  In my sample application a user can enter a company information.  I would like to setup RIA Services to force the user to enter a company name before he or she can save the company.  In order to do so I am going to use Data Annotations.  First of all, I need to add a reference to System.ComponentModel.DataAnnotations DLL to all my projects.  RIA Services project should already have the reference. 

Now I need to edit my metadata file that corresponds to my data model under .NET version of RIA Services.  In my case it is RolodexDomainService.metadata.cs file in SilverlightRIAServicesLibrary.Web project.  In that file I need to find Companies class, then location company name property, then decorate the property with required attribute.  At the same time we will also put a limit on how many characters a user can enter:

[Required]

[StringLength(30)]

public string CompanyName;

 

If we want to see the results of our changes, we can run the application, then clear company name for an existing comp-any, then tab out of company name field.  Here we get visual feedback that our input was not valid:

image

Now, let’s create custom validation.  Fir example, I am going to force the date added to be no less that 1/1/2000.  To do this I will write a custom validation class like so:

public static class ValidationHelper

{

    public static ValidationResult DateAddedCheck(DateTime date)

    {

        ValidationResult result;

        if (date > new DateTime(2000, 1, 1))

        {

            result = new ValidationResult("");

        }

        else

        {

            result = new ValidationResult("Date is not valid");

        }

 

        return result;

    }

}

Validation method that I wrote is a static member.  It follows a specific signature that RIA Services requires.  For example, it returns Validation Result that contains specific information that validation infrastructure of RIA Services can parse.  Overall code is fairly simple.

In order to make this class available on the Silverlight side, I must include my validation class into Silverlight version of RIA Services library – SilverlightRIAServicesLibrary project in my case.  In order not to duplicate the code, I will include the same class as a link.  I right-click on the project, choose add existing item, navigate to my class, then click on down arrow on Add button, and select Add As Link.  Now I have the same validation on both .NET and Silverlight side.  To confirm, I just build and run the application.  Here is what my DateAdded attributes look like:

[Required]

[CustomValidation(typeof(ValidationHelper), "DateAddedCheck", ErrorMessage = "Date is not valid")]

public DateTime DateAdded;

On important thing to mention that in  order to see validation error in UI, we need to update our Binding to look as following:

<TextBox x:Name="CompanyNameTextbox" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" Margin="6,6,6,6" Text="{Binding Path=CompanyName, Mode=TwoWay, NotifyOnValidationError=True, ValidatesOnExceptions=True}" VerticalAlignment="Center"/>

There is one important thing to notice.  If you look at Silverlight side generated code, you will notice that validation occurs before the property value is set.  As a result, you cannot rely on property value being set if a validation exception is thrown.

Now, let’s look at saving code that we had to modify in order to validate user input.  Here is what it looks like:

try

{

    Validator.ValidateObject(this.Model, new ValidationContext(this.Model, null, null), true);

    if (this.Model.HasChanges)

    {

        ShowPleaseWaitMessage();

        _context.SubmitChanges(HandleSave, null);

    }

}

catch (ValidationException ex)

{

    MessageBox.Show(ex.Message);

}

Not really the cleanest code because we have to rely on exceptions being thrown. 

I covered all key area of validation, but there is more for you to explore.  Please let me know if you have any questions.

Post to Twitter

RIA Services (Cont.)

In this post I will cover the update process.

I am going to recap where I left off in the last post on RIA Services.  The last step was to retrieved based on ID from a read only company object.  Once this object is obtained in the VIewModel, we can create a screen to edit a company.

Here is how I am getting the company by ID in the ViewModel class:

var

companyQuery = _context.GetCompanyQuery(_companyID);

 

_context.Load<Companies>(companyQuery, (o1) =>

 

{

 

    HidePleaseWaitMessage();

 

    if (o.Error != null)

 

    {

 

        ErrorHandler.HandleException(o.Error);

 

    }

 

    else

 

    {

 

        this.Model = o1.Entities.First() as Companies;

 

    }

 

}, null);

Now that I have my Model property set, I can create a user control to edit the company.  Here is the part of the XAML for the edit form that shows the binding:

<UserControl x:Class

=”Rolodex.Silverlight.Views.CompanyEditView”

 

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

 

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

 

    xmlns:controls=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”

 

    xmlns:input=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls”

 

    xmlns:cal=”clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation”

 

    xmlns:core=”clr-namespace:Rolodex.Silverlight.Core”

 

    >

 

    <UserControl.Resources

>

 

       

 

    </UserControl.Resources

>

 

    <Grid x:Name

=”LayoutRoot”>

 

        <Grid.RowDefinitions

>

 

            <RowDefinition Height

=”*”/>

 

            <RowDefinition Height

=”Auto”/>

 

        </Grid.RowDefinitions

>

 

        <Grid x:Name=”EditGrid” DataContext=”{Binding Model

}”>

 

            <Grid.RowDefinitions

>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”1*”/>

 

                <RowDefinition Height

=”35″/>

 

                <RowDefinition Height

=”1*”/>

 

                <RowDefinition Height

=”35″/>

 

            </Grid.RowDefinitions

>

 

            <Grid.ColumnDefinitions

>

 

                <ColumnDefinition Width

=”Auto”/>

 

                <ColumnDefinition Width

=”200″/>

 

                <ColumnDefinition Width

=”*”/>

 

            </Grid.ColumnDefinitions

>

 

            <TextBlock Text=”Company Name:” TextAlignment=”Right” HorizontalAlignment=”Right” Grid.Column=”0″ Grid.Row=”0″ Margin=”6,6,6,6″ VerticalAlignment

=”Center”/>

 

            <TextBox x:Name=”CompanyNameTextbox” Grid.Column=”1″ Grid.Row=”0″ HorizontalAlignment=”Stretch” Margin=”6,6,6,6″ Text=”{Binding Path=CompanyName, Mode=TwoWay}” VerticalAlignment

=”Center”/>

 

            <TextBlock Text=”Date Added:” TextAlignment=”Right” HorizontalAlignment=”Right” Grid.Column=”0″ Grid.Row=”1″ Margin=”6,6,6,6″ VerticalAlignment

=”Center”/>

 

            <input:DatePicker x:Name=”DateAddedTextbox” SelectedDate=”{Binding DateAdded, Mode=TwoWay}” Grid.Column=”1″ Grid.Row=”1″ HorizontalAlignment=”Stretch” Margin=”6,6,6,6″ VerticalAlignment=”Center”/>

So far, I have an instance of a Companies object that is bound to the data context of my user control.  At this point a user can edit company name and date added fields.  Logically, the next thing a user would want to do is to save his changed – the nerve of him :-)

So, let’s take a look at the Save command in our view model object.

 

protected

override void BeginSave()

 

{

 

    ShowPleaseWaitMessage();

 

    _context.SubmitChanges(HandleSave, null);

 

}

 

 

 

private

void HandleSave(SubmitOperation operation)

 

{

 

    HidePleaseWaitMessage();

 

    if (operation.Error != null)

 

    {

 

        ErrorHandler.HandleException(operation.Error);

 

    }

 

}

Save is a two step process because all communication in Silverlight is asynchronous.  We are starting the save process in BeginSave, and we are checking for errors in HandleSave methods respectively.  The key part to this process is client side context of RIA Services that keeps track of all the changes that the user is making after the object has been initially retrieved via a call to the server.  The key work is done by the domain service object – LinqToEntitiesDomainService<RolodexEntities> in our case.  We can look at this code generated by the RIA Services wizard by looking at RolodexDomainService.cs class in my case.  There is a bug in current CTP that causes update to parent and child objects not being flushed properly.  In my case I have Companies object that contains a list of ComanyContacts objects.  Generated code has check for EntityState in UpdateCompanyContacts method that I had to remove to get the process to work.  Here is the final version of key methods of the Domain service class:

public

void UpdateCompanies(Companies currentCompanies)

 

{

 

    this.ObjectContext.AttachAsModified(currentCompanies, this.ChangeSet.GetOriginal(currentCompanies));

 

}

public

void UpdateCompanyContacts(CompanyContacts currentCompanyContacts)

 

{

 

    this.ObjectContext.AttachAsModified(currentCompanyContacts, this.ChangeSet.GetOriginal(currentCompanyContacts));

 

}

So, after this step all parts of the process are working – I can update companies and contacts.

Please email me any questions,

Post to Twitter

RIA Services (Cont.)

I am going to continue exploring the topic of RIA services and Silverlight.  I thought I was going to get into updates in this post, but there are a few topics I would like to cover first.  I am going to try to get to updates in the next post.

Today, I am going to explore two more topics.  I am going to cover extending RIA Services DomainContext with custom classes and working on including child objects when fetching a parent object using Entity Framework and RIA Services.

 

First, I am going to extend my DomainContext with a custom class.  In my case I have Company Object/Table with a number of columns.  In my Silverlight application I would like to have a list of companies that shows only company name.  When a user selected one company, I would like to fetch full company object with company contacts child object.  If I were to use the method that the wizard built for me – public IQueryable<Companies> GetCompanies(),I would get the full object with all columns.  So, I am going to build a custom class that only has company ID and name:

    public class ReadOnlyCompany

    {

        [Key]

        public int CompanyId { internal set; get; }

        public string CompanyName { internal set; get; }

    }

 

I am going to add this class to RIA Service project on .NET side (SilverlightRIAServicesLibrary.Web project in my case).  As you notice I did not have to decorate my class with DataContract attribute or decorate properties with DataMember attribute.  We do not actually need to do this, as RIA Services will take care of all that for us.  I do however need to use Key attribute or I would get a compile time error.  Each object is required to have a key (primary key) property.  Next step is to write a method in DomainService (RoldexDomainService in my case) class.  Here is what this would look like:

        public List<ReadOnlyCompany> GetReadOnlyCompanies()

        {

            return (from oneCompany in this.ObjectContext.Companies

                    orderby oneCompany.CompanyName

                    select new ReadOnlyCompany()

                    {

                        CompanyId = oneCompany.CompanyId,

                        CompanyName = oneCompany.CompanyName

                    }).ToList<ReadOnlyCompany>();

        }

 

Even though I return List object here, but RIA Services will actually return ReadOnlyObservableCollection<ReadOnlyCompany> on Silverlight side.  You have to remember that when you cast return value for RIA Services call to a specific object.  Here is what this call would look like on Silverlight side:

        private void GetCompaniesList()

        {

            ShowPleaseWaitMessage();

            var query = _context.GetReadOnlyCompaniesQuery();

 

            _context.Load<ReadOnlyCompany>(query, LoadBehavior.RefreshCurrent, (o) =>

            {

                HidePleaseWaitMessage();

                if (o.Error != null)

                    ErrorHandler.HandleException(o.Error);

                else

                {

                    this.Model = o.Entities as ReadOnlyObservableCollection<ReadOnlyCompany>;

                }

                    HidePleaseWaitMessage();

            }, null); ;

 

        }

Here I am putting up a please wait window, fire a query and interpret the results.  As I mention before, my next step is to get full Company object based on selected ID.  Again, I am adding a new method to DomainService class on .NET side:

        public Companies GetCompany(int companyID)

        {

            var returnValue = this.ObjectContext.Companies

                .Include("CompanyContacts")

                .Include("CompanyContacts.CompanyContactPhones")

                .Where(one => one.CompanyId == companyID).FirstOrDefault();

            return returnValue;

        }

Now, let’s see what this call looks like on Silverlight side.  This also demonstrates the use of parameters:

var companyQuery = _context.GetCompanyQuery(_companyID);

_context.Load<Companies>(companyQuery, (o1) =>

{

    HidePleaseWaitMessage();

    if (o.Error != null)

    {

        ErrorHandler.HandleException(o.Error);

    }

    else

    {

        this.Model = o1.Entities.First() as Companies;

    }

}, null);

As you can see, RIA services build us a query that already has the same company ID parameter for us.  Pretty cool!  However, if I look at return value (Companies object), I will notice that contacts property is actually null even though I did add .Include statement to my custom Entity Framework based method.  To get this to work, I have to modify the metadata class that RIA Services generated(RolodexDomainService.metadata.cs in my case).  I need to open this class file and look for Companies object.  I will find public EntityCollection<CompanyContactPhones> CompanyContactPhones property in it.  To get RIA Services to include child collection, I need to add Include attribute here as well:

[Include]

public EntityCollection<CompanyContactPhones> CompanyContactPhones;

I would have to take the same step to include phones collection for each contact.  If I run my code again, I will not get Company object with a list of Contacts, each containing a list of Phones.

I will try to cover update in my next post.

Thank you and do not hesitate to ask questions.

Post to Twitter

Getting Started with WCF RIA Services

I know many posts have been written on this subject by many people, but I am writing this one mostly for myself.  I find it very useful to type my thoughts on any subject and create a sample project to help me commit more information to memory.  So, here it goes.

What you need to get started.

  1. Visual Studio 2008 SP 1 (You can use 2010 as well)
  2. WCF RIA Services Beta for Visual Studio 2008 SP1 (http://www.microsoft.com/downloads/details.aspx?FamilyID=76bb3a07-3846-4564-b0c3-27972bcaabce&displaylang=en)

Here is what needs to be done next.

Create new Silverlight project.  To do so just create new project and select Silverlight.  Make sure to create a host web site as well.

image

On the next wizard screen select an option to create new host web site and enable .NET RIA Services.

image

 

Now, add new project to the solution, selecting WCF RIA Services Library under Silverlight projects.

image

Here is what your solution will look like:

image

Go ahead and delete Class1.cs from both RIAServicesLibrary projects.  What you see here are two new project.  RIAServicesClassLibrary1.Web will be server side project, the other RIA project is client side.  Now you need to establish references.  Add a project reference to SilverlightApplication1 and point it to RIASerivcesLibrary1 project.  Add a project reference to SilverlightApplication1.Web and point it to RIAServicesLirbary1.Web.

 

Now you need to create Entity Framework item inside the RIAServicesLibrary1.Web project.

image

Follow all the step of that wizard, generating a model from the database and pointing to a new or existing server connection.  You can select all or some tables from a database.

Go ahead and build your solution now.

Now add another new item to RIAServicesLirbary1.Web project and select Domain Service Class

image

Select the Entity Framework model you just created in that wizard and select tables you would like to use on the client.

image

Rebuild the solution once more to generate Silverlight side hidden classes that support RIA Services.  You can see that code if you click on Show All Files button in Solution Explorer:

image

Now, I am going to test the setup by adding the following code to MainPage.xaml.cs.  I am going to simulate the login process by getting a specific user from my Users table and checking the password:

using System.Windows.Ria;

using System.Linq;

public partial class MainPage : UserControl

    {

        DomainService1 _context = new DomainService1();

        public MainPage()

        {

            InitializeComponent();

            Login();

        }

 

        private void Login()

        {

            var query = _context.GetUsersQuery().Where(one => one.UserName == "admin");

 

            _context.Load<Users>(query, LoadBehavior.RefreshCurrent, (o) =>

            {

                if (o.Error != null)

                    MessageBox.Show(o.Error.ToString());

                else

                {

                    if ((o.AllEntities.Count() == 1) &&

                        (o.AllEntities.First() as Users).Password == "admin")

                    {

                        MessageBox.Show("Login successfull.");

                    }

 

                    else

                    {

                        MessageBox.Show("Login failed.");

                    }

                }

            }, null); ;

        }

    }

Next we need to update web.config in SilverlightApplication1.Web project using app.config from RIAServicesLirbary1.Web project as an example.  Make sure to paste all appropriate data into correct places:

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <connectionStrings>

        <add name="RolodexEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\sql2008;Initial Catalog=Rolodex;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

    </connectionStrings>

    <system.serviceModel>

        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />

    </system.serviceModel>

    <system.web>

        <httpModules>

            <add name="DomainServiceModule" type="System.Web.Ria.Services.DomainServiceHttpModule, System.Web.Ria, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

        </httpModules>

    </system.web>

</configuration>

Run the application now to confirm that everything is working properly.  In the next post I will explore the subject of updating the data on the server.

Post to Twitter

Windows Azure Application

This is purely a bragging post :-)

I just deployed a test application to the cloud (Microsoft Azure): http://rolodex.cloudapp.net/

Here is the technology stack for it:

  1. Windows Azure
  2. SQL Azure
  3. CSLA 3.8.1
  4. Silverlight
  5. Entity Framework
  6. WCF
  7. Prism (Composite Application Guidance)
  8. Silverlight Toolkit

I promise to write a blog entry in the near future, the steps one has to follow through to create an Azure application.

Post to Twitter

Dynamically Styling Silverlight Applications

I spoke at GGMUG (Gwinnett Georgia Microsoft Users Group) on Thursday.  I was speaking about dynamically styling Silverlight applications using Implicit Style Manager from Silverlight Toolkit

Silverlight toolkit comes with about a dozen themes that anyone can use to style there applications.  In the example I am posting I use four of them,  A theme file is essentially a XAML file that contains styles for all native Silverlight controls as well as all Toolkit controls.  Implicit style manager allows developers to dynamically (or statically) load a theme and apply it to any FrameworkElement in the visual tree. 

There are only a few steps you need to do to implement this type of styling.

1.  Download and install Toolkit.

2.  Create new Silverlight application.

3.  Create new folder under applications (UserThemes in my example) and copy some or all themes from toolkit (C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Oct09\Themes is the default folder) into that folder.  Once you include all the themes into the project, set compile action to Content.

4.  Now write a few lines of code in key places to apply a chosen theme.  Here is what this code would look like:

        private void ApplyeTheme(string themeName)

        {

            Uri uri = new Uri(string.Concat("UserThemes/", themeName, ".xaml"), UriKind.Relative);

            ImplicitStyleManager.SetResourceDictionaryUri(this, uri);

            ImplicitStyleManager.SetApplyMode(this, ImplicitStylesApplyMode.OneTime);

            ImplicitStyleManager.Apply(this);

        }

5.  You can even allow application user to select a theme by creating for example a combo box loaded with available themes.

Implicit style manager does carry some overhead with it.  To minimize the overhead try to use apply mode of OneTime.  Ap0ply mode of Auto will watch for LayoutUpdated event and restyle attached element.  If you use this mode, you can apply this code to your shell (outer application frame), and any loaded control will be styled.  It sounds easy, but it will slow down your application.

As you can see, you cheaply and easily implement dynamic styling using free! software from Silverlight Toolkit.

You can download full example here.

Post to Twitter

Silverlight 3 – CollectionViewSource and Navigation

I am killing two birds with one stone in this post, covering both CollectionViewSource and Navigation framework in Silverlight 3.

To create new Silverlight application that uses Navigation framework, simply create new project in Visual Studio, and you will find Silverlight Navigation Application project template under Silverlight node.  Navigation framework in Silverlight three allows developers to create navigation structure that mimics the one of ASP.NET (or any web allocation for that matter).   In other words, this framework provide for URI driven navigation, using Uri routing feature similar to ASP.NET MVC framework.  Of course, this is really from end user perspective, not developer.  Obviously, Silverlight application cannot navigate from one to another XAML page using browser natively.  As a result, navigation framework utilizes browser bookmark feature in order to provide the user with Next/Previous navigation using actual browser buttons.  Routing engine enables the mapping between short Uri and actual XAML page that is supposed to handle the navigation event to this Uri.  Here is what this routing looks like:

            <navigation:Frame x:Name="ContentFrame" Style="{StaticResource ContentFrameStyle}"

                             Source="/Home" Navigated="ContentFrame_Navigated" NavigationFailed="ContentFrame_NavigationFailed">

                <navigation:Frame.UriMapper>

                    <uriMapper:UriMapper>

                        <uriMapper:UriMapping Uri="" MappedUri="/Views/Home.xaml"/>

                        <uriMapper:UriMapping Uri="/{pageName}" MappedUri="/Views/{pageName}.xaml"/>

                        <uriMapper:UriMapping   

                           Uri="ProductDetail/{ProductId}"   

                           MappedUri="/Views/ProductDetail.xaml?ProductId={ProductId}"/>

                    </uriMapper:UriMapper>

                </navigation:Frame.UriMapper>

            </navigation:Frame>

Here is how we read this code.  The core part of navigation is Frame control.  It handles browser interaction and provide Uri mapping.  If we look at the mapper XAML, we will see that short Uri, such as “” (blank) maps to Home.Xaml.  Home.Xaml is not User Conrol, it inherits from Page control, another part of navigation framework.  Any XAML page that is supposed to handle navigation must inherit from Page.  The mapper supports tokenization as well, that is how {pageName} is mapped to /Views/{pageName}.xaml.  So, if we navigate to Uri “Home”, /Views/Home.xaml will be loaded into the frame. For example, we have HyperLinkButton as follows:

                    <HyperlinkButton x:Name="Link2" Style="{StaticResource LinkStyle}"

                                    NavigateUri="/About" TargetName="ContentFrame" Content="about"/>

In this case when user clicks on this button, he/she will be navigated to /Views/About.xaml that will be shown in Frame called ContentFrame.

Navigation framework also supports parameters, and incidentally it took me an hour to figure those out.  In the example above our ProductDetail mapping supports parameter called PrductId.  So, far pretty easy.  The hard part is to figure out how to set that Url.  In my case, I have a product object, and I am setting the Url in it to match my mapping.  Here is full source code for Product class and collection of products:

using System;

 

namespace SilverlightNavigationApp

{

    public class Product

    {

        public string ProductId { get; set; }

        public string ProductName { get; set; }

        public string ProductDescription { get; set; }

        public Uri Url { get; set; }

    }

}

using System;

using System.Collections.ObjectModel;

 

namespace SilverlightNavigationApp

{

    public class ProductList : ObservableCollection<Product>

    {

        public ProductList()

        {

            Add(new Product() { ProductId = "1", ProductName = "Bread", ProductDescription = "Wheat bread.", Url = new Uri("ProductDetail/1", UriKind.Relative) });

            Add(new Product() { ProductId = "2", ProductName = "Milk", ProductDescription = "Whole milk.", Url = new Uri("ProductDetail/2", UriKind.Relative) });

            Add(new Product() { ProductId = "3", ProductName = "Potatoes", ProductDescription = "Red potatoes.", Url = new Uri("ProductDetail/3", UriKind.Relative) });

            Add(new Product() { ProductId = "4", ProductName = "Water", ProductDescription = "Bottled water.", Url = new Uri("ProductDetail/4", UriKind.Relative) });

            Add(new Product() { ProductId = "5", ProductName = "Cake", ProductDescription = "Chocolate cake.", Url = new Uri("ProductDetail/5", UriKind.Relative) });

        }

    }

}

So far so good.  You can see how Url must be formatted to match product Id. I am showing product list inside a page using DataGrid.

<navigation:Page x:Class="SilverlightNavigationApp.Views.ProductList"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:local="clr-namespace:SilverlightNavigationApp"

   xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

   xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

   >

    <UserControl.Resources>

 

        <CollectionViewSource Source="{StaticResource ProductList}" x:Key="ViewSource" Filter="MyFilter"/>

    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="*"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto"/>

            <ColumnDefinition Width="*"/>

        </Grid.ColumnDefinitions>

        <TextBlock Text="Fitler:"/>

        <TextBox Grid.Column="1" TextChanged="TextBox_TextChanged" x:Name="FilterBox" Text=""/>

        <data:DataGrid

           ItemsSource="{Binding Source={StaticResource ViewSource}}"

           AutoGenerateColumns="False"

           Grid.Row="1"

           Grid.ColumnSpan="2">

            <data:DataGrid.Columns>

                <data:DataGridTextColumn Binding="{Binding ProductId}" Header="Product ID"/>

                <data:DataGridTextColumn Binding="{Binding ProductName}" Header="Product Name"/>

                <data:DataGridTextColumn Binding="{Binding ProductDescription}" Header="Description"/>

                <data:DataGridTemplateColumn>

                    <data:DataGridTemplateColumn.CellTemplate>

                        <DataTemplate>

                            <Button Content="Details" Tag="{Binding Url}" Click="Button_Click"/>

                        </DataTemplate>

                    </data:DataGridTemplateColumn.CellTemplate>

                </data:DataGridTemplateColumn>

            </data:DataGrid.Columns>

        </data:DataGrid>

    </Grid>

</navigation:Page>

You can see that I am setting the tag for the button to Url property of the Product object.  Here is how I am processing this information in click event:

        private void Button_Click(object sender, RoutedEventArgs e)

        {

            NavigationService.Navigate(((Button)sender).Tag as Uri);

        }

Here is what we can do with this in the Details page:

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)

        {

            string productId = this.NavigationContext.QueryString["ProductId"].ToString();

            SilverlightNavigationApp.ProductList list = (SilverlightNavigationApp.ProductList)App.Current.Resources["ProductList"];

            Product product = (from one in list

                               where one.ProductId == productId

                               select one).FirstOrDefault();

            this.DataContext = product;

        }

Alternatively, I can use propertied of HyperLinkButton to do the same if I do not need to use dynamic parameters.  Look above for About navigation.

Now, let’s talk about ColllectionViewSource.  It suports grouping, sorting and filtering.  In the example I will use filtering technique.  The filtering is pretty easy – we just subscribe to filter event, evaluate each object, and decide whether or not show it:

    <UserControl.Resources>

        <CollectionViewSource Source="{StaticResource ProductList}" x:Key="ViewSource" Filter="MyFilter"/>

    </UserControl.Resources>

        private void MyFilter(object sender, FilterEventArgs e)

        {

            Product product = e.Item as Product;

            if (FilterBox != null)

            {

                e.Accepted = product.ProductName.ToUpper().Contains(FilterBox.Text.ToUpper()) ||

                    product.ProductDescription.ToUpper().Contains(FilterBox.Text.ToUpper());

            }

            else

                e.Accepted = true;

        }

All that is left is to call refresh when we want to response to use actions:

        <TextBox Grid.Column="1" TextChanged="TextBox_TextChanged" x:Name="FilterBox" Text=""/>

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)

        {

            CollectionViewSource source = this.Resources["ViewSource"] as CollectionViewSource;

            source.View.Refresh();

        }

Pretty simple.  You can download full example here.

Post to Twitter

Silverlight 3.0 Behaviors – Part 2

Today I am going to explore Silverlight three behaviors a little more.  In this post I am going to look at different events that can trigger an action in a behavior.  Essentially, we can specify any event on a target element to invoke a behavior. 

Again, we are going to use TargetedTriggerAction base class. This time however we are going to enable this behavior to be able to be used on a larger suite of targets.  We are going to use UIElement as the target type: TargetedTriggerAction<UIElement>.  We are only going to override one method – InvokeAction.  Here is what the class looks like:

    public class MakeLargerSmallerAction : TargetedTriggerAction<UIElement>

    {

        protected override void Invoke(object parameter)

        {

            StoryBoardHelper.PlayControlAnimation(Target, Percent);

        }

Here are a couple of things I need to explain. 

  1. This behavior is going to perform one function – change dimensions (increase or decrease the size) of the target control base on an event.  We are going to add a property that would allow our behavior to specify the factor by which the target’s size needs to increase or decrease.
  2. We are going to use animations to perform this function.  We will build animations in code.
  3. We will invoke animations based on event specified in XAML.

Here is full source code for behavior class:

using System;

using System.Windows.Interactivity;

using System.Windows;

 

namespace Behaviors

{

    public class MakeLargerSmallerAction : TargetedTriggerAction<UIElement>

    {

        protected override void Invoke(object parameter)

        {

            StoryBoardHelper.PlayControlAnimation(Target, Percent);

        }

 

        public double Percent

        {

            get { return (double)GetValue(PercentProperty); }

            set { SetValue(PercentProperty, value); }

        }

 

        public static readonly DependencyProperty PercentProperty =

            DependencyProperty.Register("Percent", typeof(double), typeof(MakeLargerSmallerAction), new PropertyMetadata((double)1));

 

 

    }

}

Here is source code for animation controller:

using System;

using System.Windows;

using System.Windows.Media;

using System.Windows.Media.Animation;

 

namespace Behaviors

{

    public static class StoryBoardHelper

    {

        public static void PlayControlAnimation(UIElement controlToAnimate, double factor)

        {

            Storyboard story = new Storyboard();

 

            //stretch horizontally

            DoubleAnimationUsingKeyFrames scaleXAnimation = new DoubleAnimationUsingKeyFrames();

            scaleXAnimation.BeginTime = TimeSpan.FromMilliseconds(0);

            scaleXAnimation.KeyFrames.Add(CreateFrame(factor, 100));

            Storyboard.SetTarget(scaleXAnimation, controlToAnimate);

            Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));

            story.Children.Add(scaleXAnimation);

 

            //stretch vertically

            DoubleAnimationUsingKeyFrames scaleYAnimation = new DoubleAnimationUsingKeyFrames();

            scaleYAnimation.BeginTime = TimeSpan.FromMilliseconds(0);

            scaleYAnimation.KeyFrames.Add(CreateFrame(factor, 100));

            Storyboard.SetTarget(scaleYAnimation, controlToAnimate);

            Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));

            story.Children.Add(scaleYAnimation);

 

            if (!(controlToAnimate.RenderTransform is TransformGroup))

            {

                TransformGroup group = new TransformGroup();

                ScaleTransform transform = new ScaleTransform();

                transform.ScaleX = 1;

                transform.ScaleY = 1;

                group.Children.Add(transform);

                controlToAnimate.RenderTransformOrigin = new Point(0.5, 0.5);

                controlToAnimate.RenderTransform = group;

            }

            story.Begin();

 

 

        }

 

        private static SplineDoubleKeyFrame CreateFrame(double value, double duration)

        {

            SplineDoubleKeyFrame frame = new SplineDoubleKeyFrame();

            frame.Value = value;

            frame.KeyTime = TimeSpan.FromMilliseconds(duration);

            return frame;

        }

    }

}

Here is how we are setting up behaviors in XAML:

        <TextBox x:Name="FirstBox" TextWrapping="Wrap" Margin="20,0,0,7" d:LayoutOverrides="Height">

            <i:Interaction.Triggers>

                <i:EventTrigger>

                    <Behaviors:SelectOnFocusAction/>

                </i:EventTrigger>

                <i:EventTrigger EventName="GotFocus">

                    <Behaviors:MakeLargerSmallerAction Percent="1.2"/>

                </i:EventTrigger>

                <i:EventTrigger EventName="LostFocus">

                    <Behaviors:MakeLargerSmallerAction Percent="1"/>

                </i:EventTrigger>

            </i:Interaction.Triggers>

        </TextBox>

In the XAML above we are setting up three different behaviors.  First one I covered in previous post.  The second trigger increases the size of the control by factor of 1.2 – 20 %.  This action is executed when GotFocus event fires.  The last trigger changes the control’s size back to original size.

You can download full sample project here.

Post to Twitter

Unable to debug Silverlight applications

I have run into this issue numerous times, but from time to time I keep forgetting what causes this issue.

The symptom is that your breakpoints inside Silverlight application cannot be hit, and the information message states that “No symbols have been loaded for this document.”  What is usually strange that I was able to debug just a little while ago.

The most common cause is that Silverlight debugging is not turned on on web site project that hosts Silverlight application.  However, I have not run into this issue.  My number one problem is that ClientBin folder stops being updated.  This can be caused by the fact that somehow the folder is checked into source control and compiler cannot overwrite the XAP file any longer.  Or, file is being held by OS, maybe because Visual Studio crashed at some point before.  To troubleshoot, just check your XAP from ClientBin folder and check source controls.

Post to Twitter

Dynamically setting initialization parameters in Silverlight application

One of the properties on object tag for Silverlight control in initParams or initialization parameters:

 

 <object name="objSilverlight" data="data:application/x-silverlight-2," type="application/x-silverlight-2"

            width="100%" height="100%">

            <param name="source" value="ClientBin/SilverlightInitParams.xap" />

            <param name="onError" value="onSilverlightError" />

            <param name="background" value="white" />

            <param name="minRuntimeVersion" value="3.0.40624.0" />

            <param name="autoUpgrade" value="true" />

            <param name="initParams" value="key=value,key1=value1"/>

            <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none">

                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"

                    style="border-style: none" />

            </a>

        </object>

We can use this parameter to inform our Silverlight application about a specific piece of data it may need.  To access this data inside Silverlight application, you would need to use arguments from application startup event:

private void Application_Startup(object sender, StartupEventArgs e)

        {

            MainPage page = new MainPage();

            var paramList = e.InitParams.ToList();

Our initial parameters collection is exposed as a dictionary off Startup Event Arguments.

The next step it to dynamically set the parameter.  The problem is that the object tag / Silverlight application creation occurs on the client side, which has no access to server data.  We are going to play a trick here and modify our aspx page to delegate creation of actual parameters string to the page itself:

<param name="initParams" value="<%=GetInitParameter() %>" />

The next step is to write a method in our page that returns a string in format key=value.  Here is entire code behind for our aspx page:

    public partial class _Default : System.Web.UI.Page

    {

        private string _params = string.Empty;

 

        protected void Page_Load(object sender, EventArgs e)

        {

            // put a fake variable into session.  Ordinarily, we are just getting

            // data from somewhere on the server. 

            // could even be a database call if necessary

            Session["User"] = "Sergey Barskiy";

 

            //now set a variable

            _params = string.Concat("User=", Session["User"].ToString());

        }

 

        public string GetInitParameter()

        {

            return _params;

        }

    }

Here is what we do inside our Startup routine in Silverlight application:

 

        private void Application_Startup(object sender, StartupEventArgs e)

        {

            MainPage page = new MainPage();

            var paramList = e.InitParams.ToList();

            page.Key.Text = String.Format("{0} = ", paramList.First().Key);

            page.Value.Text = paramList.First().Value;

 

            RootVisual = page;

 

        }

You can download this sample application here.

Post to Twitter

Silverlight 3.0 Behaviors – Part 1

In this post I will start exploring behaviors in Silverlight 3.0.  This topic is very large, and it will take me a few posts to cover at least key aspects of behaviors.

A little background on the subject.  Silverlight, unlike WPF does not natively support triggers that would allow the developer to change UI based on criteria or data.  In Silverlight 3.0 we now have a facility to support similar behavior.  One key usage scenario for behaviors is to allow a designer to support UI changes based on user actions without writing any code.

To extend an existing behavior base class we need to add a reference to System.Windows.Interactivity DLL.  We will start with a simple behavior.  By default Silverlight Textbox does not select all the text when it gets focus.  This however us a desirable behavior from a user perspective in many scenarios.  So, for our first excursion into Silverlight behaviors we will write “Select All Text On Focus in Textbox” behavior.

We will start by extending an existing class in SilverlightTargetedTriggerAction<C>.  In our case we are supplying generic type for our behavior – Textbox - TargetedTriggerAction<TextBox>. 

We are specifying Textbox as the target type for our behavior.  Typically, we would specify an action and an event that would invoke the action on the behavior.  In our case we however want to make sure that they only event that invokes the behavior is GotFocus event.  So, we are leaving our Invoke method blank.  Here is the final version of the class:

using System;

using System.Windows.Controls;

using System.Windows.Interactivity;

 

namespace Behaviors

{

    public class SelectOnFocusAction : TargetedTriggerAction<TextBox>

    {

        protected override void OnAttached()

        {

            base.OnAttached();

            Target.GotFocus += Target_GotFocus;

        }

 

        void Target_GotFocus(object sender, System.Windows.RoutedEventArgs e)

        {

            Target.SelectAll();

        }

        protected override void OnDetaching()

        {

            base.OnDetaching();

            Target.GotFocus -= Target_GotFocus;

        }

 

        protected override void Invoke(object parameter)

        {

            //do nothing

            // we are handling specific event we are interested in

            // by attaching events to the target text

        }

       

    }

}

 

You can download the sample project with this behavior and text page here.

Post to Twitter

Silverlight 3.0 – Perspective 3D

I am continuing covering new features in Silverlight 3.0.  The subject of this post is Silverlight 3.0.

Perspective 3D is new type of transforms available in Silverlight 3.0.  It allows developers to create a 3D projection of a two-dimensional object.  A key power of this new feature is the fact that any UI element in Silverlight can be used as a target for this feature.  This means you can rotate a control in thee dimensional space around any axis.  In my example I am using this Plane Projection to rotate a calendar:

image

I am rotating the calendar control around X axis with center of rotation at x=0, y=0.5.  These values are set as relative values with 0.5 being the middle of the plane.  This allows us to create a rotation similar to an actual wall calendar’s page  turned by a person.  You can rotate around multiple axis in multiple planes, create nice visual effects.  Pretty cool.

 

You can download the sample project here.

Post to Twitter

Assembly caching in Silverlight 3.0

I am continuing discussing new features on Silverlight 3.0.  Current topic is assembly caching. 

In Silverlight 2.0 all assemblies that your application needed would have to be included in your XAP file(s).  In Silverlight 3 you can force browser to cache one or more assemblies that your application needs.  In case of caching your can tell Silverlight runtime to pull these cached assemblies from a predefined location.  This location can be the same folder as your Silverlight XAP file or anywhere else on the internet.  To cache assemblies, you can turn on caching option in project properties:

image

What you will notice if you do that, that Microsoft assemblies such as System.Windows.Controls.Data (contains DataGrid) will not be included in your XAP file.  Instead if you look at the manifest file inside your XAP file, you will notice that this DLL is pulled at runtime from the same folder as your application.  The information about this is incluided in assembly manafiest in your main XAP file.  Here what it would look like:

<Deployment
xmlns=http://schemas.microsoft.com/client/2007/deployment
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
EntryPointAssembly="CompanySLApp"
EntryPointType="CompanySLApp.App"
RuntimeVersion="3.0.40624.0">
  <Deployment.Parts>
    <AssemblyPart x:Name="CompanySLApp" Source="CompanySLApp.dll" />
  </Deployment.Parts>
  <Deployment.ExternalParts>
    <ExtensionPart Source="System.Windows.Controls.Data.zip" />
    <ExtensionPart Source="UtilityFunctions.zip" />
    <ExtensionPart Source="System.Windows.Controls.Data.Input.zip" />
    <ExtensionPart Source="System.Windows.Data.zip" />
    <ExtensionPart Source="System.ComponentModel.DataAnnotations.zip" />
  </Deployment.ExternalParts>
</Deployment>

If you try to do the same with your assembly (for example you have a common assembly shared between two Silverlight applications), your will notice that it is still included.  The reason for that is that compiler is looking for XXX..extmap.xml where XXX is your assembly names without DLL extension.  So, all your need to do is create one.  You can look for an example in C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client folder for any extmap files for Microsoft assemblies.  You can use a utility to generate your own too.  (http://www.devcorner.info/Sources/Emm.zip).  Once you generate extmap file for your assembly, make sure it is located in the same folder as the assembly dll.  Once you rebuild your solution, you will find XXX.zip file in ClientBin folder that contains your XXX.dll assembly file.  Now, at runtime browser will cache that assembly for you, saving download time during application start up time.  Of course, this depends on how caching is setup for virtual directory that contains your Silverlight application.  You can also pass addition parameters to emm.exe utility and force it to setup download URL for your included assembly that point to an absolute URL somewhere else.  Using this feature for example, you can host assemblies that you can include in many applications on a separate server with a predefined URL.

Please feel free to ask questions about this feature.  You can upload sample application that uses assembly caching here.

Post to Twitter

Silverlight And N-Tier Data Access using Entity Framework

As I mentioned before I talked at GGMUG last Thursday.  I talked about Entity Framework in general and specifically in N-Tier applications, such as Silverlight applications.  I think I got a few folks excited about using Entity Framework.  The key thing to remember when using EF in N-Tier applications is that EF keeps track of changes in the context object.  Unfortunately, this object does not survive the trips between client and the server.  As a result, my recommendation is to use EF in conjunction with a business layer framework, such as CSLA. You can download slides and sample project here.  Please feel free to post comments or questions.

Post to Twitter

ElementName Binding in Silverlight 3

As I mentioned before, I will be working on a series of posts on new features in Silverlight 30.  This post is all about ElementName binding.

Probably my favorite feature in Silverlight 3 that affects developers writing business applications is addition of ElementName property to Binding object.  This features existed in WPF since version 1, but was missing from Silverlight 2.0.  The basic strategy behind the feature is the ability to bind a property on one UI element to a property on another UI element.  Here is a very common scenario in a business application that this features makes much simpler to implement.  Say, you have two co-dependent combo boxes.  For example, you have a combo box  with a listing of states, and once a state is selected, second combo box is populated with a list of cities for that state.

The basic syntax for ElementName binding is as follows:

ItemsSource="{Binding ElementName=ParentCombo, Path=…

In my case, I am going to illustrate the feature by having a list of dozens, each with a list of numbers that belong to that dozen.  Here are my classes:

    public class Each

    {

        public string Name { get; set; }

        public int Id { get; set; }

 

        public static Each GetEach(int id)

        {

            Each newEach = new Each();

            newEach.Id = id;

            newEach.Name = id.ToString();

            return newEach;

        }

    }

    public class Eaches : List<Each>

    {

 

    }

    public class Dozen

    {

        public string Name { get; set; }

        public int Id { get; set; }

        public Eaches Items {get;set;}

 

        public static Dozen GetDozen(int id)

        {

            Dozen newDozen = new Dozen();

            newDozen.Id = id;

            newDozen.Name = id.ToString();

            newDozen.Items = new Eaches();

            for (int i = 1; i <= 12; i++)

            {

                newDozen.Items.Add(Each.GetEach(((id – 1) * 12) + i));

            }

            return newDozen;

        }

    }

    public class Dozens : List<Dozen>

    {

        public Dozens()

        {

            for (int i = 1; i < 10; i++)

            {

                Add(Dozen.GetDozen(i));

            }

        }

    }

Now, I am going to add my Dozens class as a resource to a xaml page:

<UserControl x:Class="SilverlightApplication7.MainPage"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

   xmlns:local="clr-namespace:SilverlightApplication7"

   mc:Ignorable="d"

   d:DesignWidth="640"

   d:DesignHeight="480"

   >

    <UserControl.Resources>

        <local:Dozens x:Key="data"/>

    </UserControl.Resources>

The last step is to tie two combo boxes together:

  <Grid x:Name="LayoutRoot">

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="30"/>

            <RowDefinition Height="Auto"/>

        </Grid.RowDefinitions>

        <ComboBox x:Name="ParentCombo" Width="300" HorizontalAlignment="Left" ItemsSource="{StaticResource data}" DisplayMemberPath="Name"/>

        <ComboBox x:Name="ChildCombo" Grid.Row="2" Width="300" HorizontalAlignment="Left" ItemsSource="{Binding ElementName=ParentCombo, Path=SelectedItem.Items}" DisplayMemberPath="Name"/>

    </Grid>

Here is the summary of what we did.  We used Dozens class (the list of Dozen objects) that was populated when its constructor was invoked as part of resources collection initialization.  Then we used this object to populate ParentCombo with data.  We set DisplayMemberPath to show a desired property in combo box.  Then we used SelectedItem property from ParentCombo to be the source of items in ChildCombo.  As the user selects an item in ParentCombo, we can see that list of items inside ChildCombo is changing without any code-behind.  We also use dotted syntax (Path=SelectedItem.Items), so we can tie the eaches collection in dozens object to be the item source for another UI element.  In our case SelectedItem of ParentCombo is actually an instance of a Dozen object.  Items property of it gives us eaches collection.  Simple, yet very powerful feature.

You can download this sample project here.

Post to Twitter

I will be talking at GGMUG on Thursday, September 10th

I will be presenting at the next Gwinnett Georgia Microsoft Users Group this coming Thursday.  The topic of my presentation will be Entity Framework in general and its applications to Silverlight development.  I will be posting the zip file with slides and sample application immediately after the presentation.

I hope to see you there!

Post to Twitter

Atlanta Silverlight Fire Starter Event

Atlanta Silverlight Fire Starter event yesterday was awesome!  There were over 100 people attending.  The vast majority stayed there for the entire length of the event that lasted from 8am until 6pm.  All presenters did a great job.  All attendees were great.  They actively participated in all discussions, asking many questions.  Many thanks to all the event sponsors who helped make Fire Starter possible,  The event was truly a communal effort pulled off by many people excited about the technology and willing to share their knowledge and experience.  Please see Silverlight Atlanta site for more details about the event and its sponsors.

I posted my presentation about Deploying Silverlight Applications that I presented at the Fire Starter here.  The zip file contains sample project, database backup and PowerPoint presentation.

I was also going to chat for a couple of minutes about reporting in Silverlight and localization in Silverlight, however we of ran out of time by the end of the day.  I pushed an example in localization into the zip file above.  Just look at how title is setup on the main screen.  If you are interested in reporting in Silverlight, just find the blog entries on this topic on this blog.  There is also a sample project here on that showcases reporting in Silverlight.

I’d like to thank again to all involved in Fire Starter event, presenters, attendees and sponsors alike.

Post to Twitter

Bug Fix Release for SilverlightDatabase project

I just posted a new release for SilverlightDatabase project on CodePlex : http://silverdb.codeplex.com/

There was an issue with the latest release – you could potentially get an error when adding data to a table previously saved.  I posted a bug fix release for this that also includes unit test to verify that the issue is resolved.

Please download this release if you are using this project.

Thank you.

Post to Twitter

Webinar (Reporting in Silverlight) download

Recording of the webinar I presented is now up on Magenic web site.  Here is the address: http://www.magenic.com/Default.aspx?tabid=635

Since I am not sure if the sample project is available, I decided to post the zip file with the sample project here.

Please let me know if you have any questions. 

Post to Twitter

More on CodePlex project

I could not have been more pumped about my Silverlight database project (See my post from a week ago for details).  I searched CodePlex for “Silverlight”, and now my project is number 20 on the list sorted by relevance out of total  622 projects.  It is also listed on Silverlight MSDN main page today: http://msdn.microsoft.com/en-us/silverlight/default.aspx.  It got 68 downloads and 311 visits in just four days this week.  Awesome!

I just posted another update to this project on CodePlex.  Silverlight Database now supports encryption and compression.

Post to Twitter

A small localization gripe for Silverlight

I just installed Silverlight 3 last Friday.  One feature that I was hoping to see fixed was localization in Silverlight.  Ideally, I like to bind localized data, such as labels in XAML.  For example:

<UserControl.Resources>

<resources:ModuleResources x:Key="LanguageResource" />

then,

<TextBlock HorizontalAlignment="Center" Margin="7,0,7,0" VerticalAlignment="Center" Text="{Binding Source={StaticResource LanguageResource}, Path=SomePropertyName}"></TextBlock>

This works great, but there is one issue.  Even though I mark the resource as public, any time I add a new value or edit and existing value, ModuleResources .Designer.cs gets re-written, and its constructor is marked as internal, not public.  If I run the app, I get the dreaded unknown type exception.  At that point I have to manually edit designer file and mark constructor as public.  Not a major problem, but I would like not to have to do this.

Post to Twitter

CodePlex project

I just uploaded and published new CodePlex project I have been working on.  It is an Isolated Storage based database for Silverlight.  It supports multiple strongly typed tables, basic Linq based operations, addition and deletion of ranges of items, deletion of items based on condition.  You can also directly bind data to UI in Silverlight because base table inherits from ObservableCollection.  I am planning to put encryption and compression support into it next along with lazy loading of table.  Currently all tables are loaded into memory when database is opened.

Please take a look at http://silverdb.codeplex.com/

I would very much appreciate comments and feature requests related to this project.

Thanks in advance for the feedback.

Post to Twitter

Silverlight 3 Features

I am planning to write some posts on new features in Silverlight 3.0.

I decided to start with the easiest one – out of browser support.  Start by creating new Silverlight application in Visual Studio.  Once it is created, go to properties of the Silverlight application project.  You will see this window:

image

Check “Enable running application out of browser”, then click on Out-of-Browser Settings button.  You will see this screen.

image

Once you fill in all the settings, you are ready to go.  All settings from this screen are stored in XML file called OutOfBrowserSettings.xml.  The actual fact that a particular application is enabled for out-of-browser support is stored in .csproj file.

Once you run the application, if you right-click on the application, you will see context menu with additional option – install on desktop.  If application is already installed, the option changes to remove application.

The installed application can be now run from the computer from the shortcut.  When you run the app from the shortcut, it is not going run in the browser, instead it is run in sllauncher.exe, a special program designed to host Silverlight application.  At that point, you do not have access to browser based functionality.  So, before you reach to HtmlPage.Window, check to see if application is running in browser.  You can do this by checking App.Current.IsRunningOutOfBrowser property.

Post to Twitter

Webinar on reporting in Silverlight

I am presenting a webinar on July 28th on reporting in Silverlight.  This webinar is hosted by my employer, Magenic Technologies.  If you would like to register and watch this event, please follow this link: http://guest.cvent.com/EVENTS/Info/Invitation.aspx?e=6ca01a01-e2bd-4a77-a057-a63ab2208e81

There should be some tome allocated for questions and answers as well.

Thank you.

Post to Twitter

Status Update

I am very tired, but Silverlight application our team has been working on for 6+ months is now officially live!  We saw that someone used it over the weekend!

More reflections on the project are to come in the next few weeks.

Post to Twitter

Setup Silverlight application with WCF service to run over HTTPS/SSL

Here are the steps in achieving this task.

1. Setup WCF service.

To do this you have to alter web.config file for the web site that hosts the service.  You have to add security setting to basisHTTP binding that is used by Silverlight application to connect to the WCF service.  Here is an example of the entire server side system.serviceModel section of web.config file

<system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfPortalBehavior">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                    <compression/>
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <bindings>
            <basicHttpBinding>
                <binding name="basicHttpBinding_IWcfPortal_HTTPS"
                        maxReceivedMessageSize="2147483647"
                        receiveTimeout="00:30:00"
                        sendTimeout="00:30:00"
                        openTimeout="00:10:00"
                        closeTimeout="00:5:00">
                    <readerQuotas
                        maxBytesPerRead="2147483647"
                        maxArrayLength="2147483647"
                        maxStringContentLength="2147483647"
                        maxDepth="1024"/>
            <security mode="Transport">
                <transport clientCredentialType="None"/>
            </security>

                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service name="RootNamespace.Library.Wcf.Host"
                     >

                <endpoint binding="basicHttpBinding"
                          contract="RootNamespace.Library.Wcf.Silverlight.IWcfPortal"
                          bindingConfiguration="basicHttpBinding_IWcfPortal_HTTPS">

                </endpoint>
            </service>
        </services>

    </system.serviceModel>

2.  Configure Silverlight application to use HHTPS.

To do this you have to alter ServiceReference.ClientConfig and add security setting.  Here is an example of the entire file

<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding    name="basicHttpBinding_IWcfPortal"
                            maxBufferSize="2147483647"
                            maxReceivedMessageSize="2147483647"
                            receiveTimeout="00:10:00"
                            sendTimeout="00:10:00"
                            openTimeout="00:2:00"
                            closeTimeout="00:2:00">
                     <security mode="Transport" />

                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint    address="https://www.examplesite.com/WcfSilverlightPortal.svc"
                        binding="basicHttpBinding"
                        bindingConfiguration="basicHttpBinding_IWcfPortal"
                        contract="RootNamespace.Library.Wcf.Silverlight.IWcfPortal"
                        name="BasicHttpBinding_IWcfPortal" />
        </client>
    </system.serviceModel>
</configuration>

3.  Setup client access policy for the web site.

This is done by editing file at the root of your domain.  For example, if you are hosting everything in a virtual directory called Portal, your clientaccesspolicy.xml still needs to reside at the root of the domain, not in that virtual directory.  You can locate the physical path to that in properties of the root web site in IIS.  Here is an example of the entire file that enables HTTP access

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from http-request-headers="*">
                <domain uri="http://*"/>
                <domain uri="https://*"/>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

You can further restrict access by updating resource node or allow-from node.

You can verify the correctness of clientaccesspolicy.xml location in SilverlightSpy.  Go to Tools->Cross-domain access policy valuator an enter your domain there, for example http://www.examplesite.com

You can also hit your service directly.  If you follow the example in step 2, you can type in the following into your browser:https://www.examplesite.com/WcfSilverlightPortal.svc

Post to Twitter

Downloading Silverlight application over HTTPS

I encountered an interesting problems today.  I was trying to setup a Silverlight application to run over https.  I was able to successfully run it over HTTP prior to this task.  However, when I switched URL to https://www.mysite.com, I got the error 2104 “Could not download the Silverlight application”.  The solution that I had to experiment with to discover (Google was not help) was setting expiration time to 1 minute.  It worked perfectly fine with expire immediately setting for http protocol, but not https.

Post to Twitter

Customizing look of a Silverlight button

During my Introduction to Silverlight presentation at the Atlanta .NET users group, someone suggested that I show how make a button with rounded corners in Silverlight.  I was a bit short on time, and it was getting late, so I decided to write a blog post on the subject matter instead.  So, here it goes.

Goal – make Silverlight button that has rounded corners using Blend

Step by step how to:

  1. Create new Silverlight application
  2. Save it
  3. Now you should have Page.xaml open in Visual Studio
  4. Open the same application in Blend
  5. Open Page.xaml
  6. Add a button to it.  If Button control is not visible, click on Assets(>>) button, select button
  7. Now double-click on button in toolbar to add it to Page.xaml
  8. Right-click on the button, select Edit Control Parts (Template), then Edit a Copy.  This way we will retain preloaded template, but will only change small parts of it
  9. Type is key for newly create style, such as RoundedButtonStyle
  10. Select application for Define In option.  This way you can use this style for any button in application
  11. Now, you should have app.xaml open with button control visible
  12. Expand everything in Template tree in Objects and Timeline window
  13. Click on element called Background, set CornerRadius in Properties window to 10,10,10,10
  14. Click on element called BackgroundAnimation, set CornerRadius in Properties window to 10,10,10,10
  15. Click on element called BackgroundGradient , set RadiusX and RadiusY in Properties window to 10
  16. Click on element called DisabledVisualElement, set RadiusX and RadiusY in Properties window to 10
  17. Click on element called FocusVisualElement, set RadiusX and RadiusY in Properties window to 10
  18. Save all
  19. Flip back to Visual Studio and run the application
  20. You can now see your rounded button in action

Your XAML for the button should look something like this:

<Button Content="Button" Margin="5,10,5,0" Style="{StaticResource RoundedButtonStyle}"/>

If you have template set instead, just change the XAML to use the style

All done and easy as pie!

In this little excersize we did not change the look drastically.  To do that instead of choosing edit a copy in step 8, choose Create Empty.  Now you will need to add visual elements yourself.  For a quick and dirty rounded button from scratch, add a rectangle and set Radius X and Y to the values of your liking.  This of course will not give you mouse over effects, disabled and focus effect etc…  You will still need to code those using visual states.  You can see those in Interaction window if you click on a button.  If you do not see the states, you may need to click on little drop down on top of the screen and choose Edit Control Parts –> Edit Template

Please feel free to ask questions if you cannot find a particular option.

Post to Twitter

Introduction to Silverlight

I just posted the sample project I used for “Intro to Silverlight” presentation at the Atlanta .NET Users group meeting yesterday on SkyDrive.  Please follow this link to get the sample project:

I would like to thank everyone who attended the meeting.

Post to Twitter

Atlanta .NET Users Group

It is official now.   I will be speaking at the next Atlanta .NET Users Group (http://atldotnet.org/).  The topic is Introduction to Silverlight.  It has been a while since I got an opportunity to talk in front of Atlanta users group, and I am quite excited about it.

Post to Twitter

RIA Services for Silverlight

I downloaded the CTP of RIA Services for Silverlight along with accompanying documentation this morning.  I have read the documentation and wanted to share a few thoughts on this product.

The product looks very promising to me.  Here is an overview of the key features.  You can configure RIA Services to use ether Linq to SQL or Entity framework as data access layer, which gives you flexibility along with possibility to use services over non-SQL Server databases.  You can quickly generate service class directly off your EF or LTS data model.  This means direct support for RAD application development.  There is no difference in accessing the service from Silverlight client in comparison to plain WCF service.  The RIA Services also support validation via custom attributes.  It has built-in attributes such as required field or minimum / maximum string length attribute.  These attributes are setup on  metadata class that corresponds to the entity class it is designed to validate and enhance.  In addition to pre-built attributes you can create custom validation via custom validation attribute.  You can also share classes between client and server side via shared class (decorated with Shared attribute).  You can also define custom queries on your data context.  You can use the following Linq clauses for querying: where, orderby and skip or take.  You also have support to delete, insert and update operations.  All CRUD operations are supported either via attributes or naming conventions for access methods.  There is also built-in change tracking and ability to revert changes via interfaces: IEditableObject, IChangeTracking, IRevertibleChangeTracking,  IEditableCollection.  There is also support for authorization via custom attributes as well.

One interesting thing to notice is that the code for client side is entirely generated by RIA Services framework.  So, on the client side you do not see any code – it is in hidden classes under the project.  Very nifty trick.

One last note – RIA Services framework seem to implement a lot of the features that CSLA for Silverlight has.  Almost feels like the authors of RIA Services were quite familiar with CSLA for Silverlight :-)

Post to Twitter

Silverlight 3.0

I read a few notes from Mix 09 about Silverlight 3.0.  It has a lot of great new features.  Read for yourself if you would like.  Here is a link to a free short eBook that covers parts of new functionality.

http://download.microsoft.com/download/3/0/5/3055A230-B06F-4A58-AC93-B7CFD2184A70/FirstLookSL3Moroney.pdf

Post to Twitter

Working with resources in Silverlight

Localizing a Silverlight application is a pretty trivial task if you use resources.  Once you create a resource file you are working with, you can use the code-behind class in XAML and bind to properties from that class that contain localized strings.  First, import the namespace that is used for resx file, typically Application\Resources

xmlns:Localized="clr-namespace:MyApplication.Resources"

Then add an instance of a specific resx code-behind class to resources in your user control

<UserControl.Resources>
    <Localized:SpecificFile x:Name="LocalizedStrings"/>

In this case SpecificFile corresponds to SpecificFile.resx.  Now that this is done, you can bind labels to it

<TextBlock Text="{Binding Path=MyPropertyFromResourceFile}/>

There is one issue though, if you edit resource file again in resources editor, and save it, the constructor scope in code behind is set to internal.  This in turn will cause an exception (AG_E_PARSER_UNKNOWN_TYPE  ) when you try to load this user control.  All you have to do to fix it is edit code behind file for you resource file and change its constructor to public.  Unfortunately, you have to do it every time you edit the file in resources editor.

Post to Twitter

Atlanta Code Camp 2009

This year’s code camp is upon us.  I have volunteered to speak at this code camp.  My topic is “Building Silverlight Business Applications using CSLA.NET for Silverlight”.  Please check out the Code Camp web site for more details.  As always, I am excited to speak in front of my fellow coders.

Download presentation and sample project here.

Post to Twitter

Editing Silverlight’s DataGrid’s templates in Blend

Blend has a small issue when it comes to editing of column templates for DataGrid.  If you define the template in-line as part of column definition, there is no way to edit that in Blend.  There is an easy workaround however.  You need to define DataTemplate as part of user control’s resources.  Once you open the user control in Blend, you can flip to resources tab and click on that template in order to edit it. 

Post to Twitter

Deploying Silverlight applications that use CSLA for Silverlight

Here are a few steps that need to be taken in the process

  • Update XAP file for Silverlight application in order to set deployment time IP address/name
  • Make sure to install .NET framework version 3.5 SP1 on the application server that hosts WCF service
  • Check and create if missing MIME types for virtual directory that hosts Silverlight web application:
    • Extension: .xap MIME type:application/octet-stream
    • Extension: .xaml MIME type: application/xaml+xml
  • Set execute permissions on virtual directory to scripts only
  • Set content expiration to desired setting – I set mine to expire immediately
  • Update SQL server (or other database) connection string WCF host web.config file.  If you are using IP protocol, then here is an example: Data Source=127.0.0.1\SQL2008;Initial Catalog=MyDBName;User ID=myUser;Network Library=dbmssocn

Post to Twitter

Binding to Silverlight WrapPanel

I had recently investigated the use of WrapPanel for Silverlight.  You can download it along with other controls as part of Silverlight Toolkit.  Example on the web site does not demonstrate the binding to it, so here is how you would do it.

You cannot bind to WrapPanel directly because it does not have property to bind a list of items to.  So, you have to use it as part or a control that inherits from ItemsControl.  In the following example we are setting up ItemsPanel for ItemsControl to be WrapPanel.  Then we also define a template for each individual items contained within the list.  I am binding to SelectedItems property of a an object that ItemsControl’s DataContext property is pointing to.  This property contains a list of items as List<T>.  Each item has properties MyImage1, MyImage2, MyImage3, Name.  So each item within the wrap panel has a title (Name) and three pictures.  Here is the XAML for it:

<ItemsControl ItemsSource="{Binding SelectedItems}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <toolkit:WrapPanel>
                        </toolkit:WrapPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="5,5,5,5" >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <PersonalysisSilverlightApplication:SLBackBoxUserControl />
                            <TextBlock FontSize="12" Foreground="#FFFFFFFF" Text="{Binding Path=Name}" TextWrapping="NoWrap" FontFamily="Arial" VerticalAlignment="Top" Grid.Row="0" Margin="5,5,5,0" HorizontalAlignment="Left" />

                            <Image Source="{Binding Path=MyImage1, Converter={StaticResource ConvertImage}}" Grid.Row="1" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />

                            <Image Source="{Binding Path=MyImage2, Converter={StaticResource ConvertImage}}" Grid.Row="2" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />
                            <Image Source="{Binding Path=MyImage3, Converter={StaticResource ConvertImage}}" Grid.Row="3" Margin="5,0,5,2" VerticalAlignment="Top" HorizontalAlignment="Left" />

                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

– Sergey

Post to Twitter

Showing images from database in in Silverlight

You can show images in Silverlight using Image control.  You can furthermore bind Source property of the image to byte[] type property of a business object.  You would think this is sufficient, but it is not.  You will need a converter to convert byte array into image source.

Here is the class for converter

public class ImageSourceConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        BitmapImage bitmap = new BitmapImage();
        bitmap.SetSource(new MemoryStream((Byte[])value));
        return bitmap;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Here is how this class is used in a control:

<UserControl.Resources>
       <helpers:ImageConverter x:Key="ConvertImage"/>
   </UserControl.Resources>

<Image Source="{Binding Path=MyByteArrayPropertyName, Converter={StaticResource ConvertImage}}" />

Post to Twitter

Design surface in Silverlight

If you are working on a resizable user control in Silverlight, you usually do not specify height and width of any elements in order to ensure that all controls resize properly when application size changes.  For example if you use Grid as your layout base, you can specify relative sizes for columns and rows in format of Width=”1*” or Height=”1*”.  Runtime will interpret  the numbers next to * and will use them as ratios.  As a result, you cannot see this control in Blend because the default size is zero.  So, how do you deal with this?  You have to specify design size (width and height).

Here is area from header of such control:

<UserControl x:Class="MyNamespace.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignWidth="581" d:DesignHeight="355">

Once this is done, you can easily estimate final layout in Blend.   Blend automatically adds this code to controls you design in it.

Post to Twitter

Full screen toggling in Silverlight

If you would like to push browser in and out of full screen mode from Silverlight application, you can do this very easily.

To go full screen:

Application.Current.Host.Content.IsFullScreen = true

To go to normal display:

Application.Current.Host.Content.IsFullScreen = false

Since Application.Current.Host.Content.IsFullScreen is a property, you can also test for current mode.

Post to Twitter

Reporting in Silverlight

Reporting in Silverlight environment has one major problem.  Silverlight does not have a report viewer control for either SQL Server reporting services or Crystal reports.  As a result, one has to come up with a workaround that uses existing report viewer controls.  Luckily both Crystal and SSRS have report viewer controls designed for the web.  So, all we need to do is cleanly integrate these controls into a Silverlight application, using browser integration capabilities of Silverlight.  By cleanly, I mean as cleanly as possible :-).

We have two options to do this.  We can launch another browser window from Silverlight and open the report in new ASPX page or we can embed a new web page that hosts report viewer control inside the web page that hosts Silverlight application.  I will demonstrate these options in the following manner.  Launch a new web page that hosts SSRS report viewer and embed a web page that hosts Crystal reports viewer.

This post builds on top of previous post I had about SSRS implementation.

SSRS implementation

Create ASPX page for report viewer:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportViewerForm.aspx.cs"
    Inherits="MyWeb.ReportViewerForm" %>
<!–
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">–>
<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
    <title>Report</title>
</head>
<body>
    <form id="form1" runat="server" style="height:100%" >
    <div style="height:100%" >
        <rsweb:ReportViewer ID="MainReportViewer" runat="server" 
            AsyncRendering="false"
            ProcessingMode="Remote"
            Width="100%"
            ShowExportControls="True"
            ShowFindControls="True"
            ShowParameterPrompts="False"
            ShowPromptAreaButton="False"
            ShowRefreshButton="False"
            BackColor="White">
            <ServerReport DisplayName="MainReport" ReportServerUrl="" />
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

Create a class to launch a report with the following routine:

public static void LaunchReport(string reportName)
       {
           Uri sourceUri = new Uri(HtmlPage.Document.DocumentUri, Application.Current.Host.Source.ToString().Substring(0, Application.Current.Host.Source.ToString().IndexOf("ClientBin") – 1) + "/ReportViewerForm.aspx?ReportName=" + reportName);

           if (ArePopupsAllowed())
           {
               System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
               codeToRun.Append("window.open(");
               codeToRun.Append("\"");
               codeToRun.Append(sourceUri.ToString());
               codeToRun.Append("\",");
               codeToRun.Append("\"");
               codeToRun.Append("\",");
               codeToRun.Append("\"");
               codeToRun.Append("width=1100,height=900,scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
               codeToRun.Append("\");");
               try
               {
                   HtmlPage.Window.Eval(codeToRun.ToString());
               }
               catch (Exception ex)
               {
                   // do something               }
           }

           else
              //inform the user that popups need to be enabled
       }

ArePopupsAllowed function tests if popups are allowed in the browser.  Contact me if you need this code.

If you need to pass in parameters, you can easily pass them in as query parameters and parse them inside  ReportViewerForm.aspx just like the report name itself.  Here is code in Load event for this web page:

protected void Page_Load(object sender, EventArgs e)
        {
            MainReportViewer.ProcessingMode = ProcessingMode.Remote;
            MainReportViewer.ServerReport.ReportPath = "/MySSRSReports/" + this.Request.QueryString["ReportName"];
            MainReportViewer.ServerReport.ReportServerUrl = new Uri("http://localhost:8080/ReportServer_SQL2008");
            List<ReportParameter> parameters = new List<ReportParameter>();
            List<string> values = new List<string>();
            values.Add("1");
            values.Add("2");
            values.Add("3");
            ReportParameter oneParamter = new ReportParameter("ParmeterName", values.ToArray());
            parameters.Add(oneParamter);
            MainReportViewer.ServerReport.SetParameters(parameters.ToArray());
            MainReportViewer.ShowParameterPrompts = false;
            MainReportViewer.ServerReport.Refresh();
        }

In the example above I do hard code parameter values, but you get the idea.  Just add your parameters to the URL for ReprotViewerForm and have the form add them to each report.

Of course you also need to create SSRS report as well, but this is a separate subject.

Crystal Reports implementation

First thing is to create a crystal report.  You do have the usual options here to have the report get data directly from database (which is what I am using) or you can write more code to get data into a DataSet for example, using additional .NET classes and pass DataSet to the report.  We have to create a web page here as well to host report viewer.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ReportView.aspx.cs" Inherits="MyApp.Web.ReportView" %>

<%@ Register assembly="CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" namespace="CrystalDecisions.Web" tagprefix="CR" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server"
            AutoDataBind="true" />
    </div>
    </form>
</body>
</html>

Again, you have to put some code to Load event to interpret report name and parameters as well as setup connection information

protected void Page_Load(object sender, EventArgs e)
        {
            string filter = Request.Params["param"];
            CrystalReportViewer1.Attributes.Add("Width", "100%");
            CrystalReportViewer1.Attributes.Add("Width", "100%");

            CrystalDecisions.CrystalReports.Engine.ReportDocument doc = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
            doc.Load(Server.MapPath("MyReport.rpt"));
            foreach (CrystalDecisions.CrystalReports.Engine.Table item in doc.Database.Tables)
            {
                CrystalDecisions.Shared.ConnectionInfo connection = new CrystalDecisions.Shared.ConnectionInfo();
                connection.ServerName = "(local)";
                connection.UserID = "myUser";
                connection.Password = "myPassword";
                connection.DatabaseName = "MyDatabase";
                CrystalDecisions.Shared.TableLogOnInfo logInfo = new CrystalDecisions.Shared.TableLogOnInfo();
                logInfo.ConnectionInfo = connection;
                item.ApplyLogOnInfo(logInfo);
            }

            CrystalDecisions.Shared.ParameterField param = new CrystalDecisions.Shared.ParameterField();

            CrystalDecisions.Shared.ParameterDiscreteValue discreteVal = new CrystalDecisions.Shared.ParameterDiscreteValue();

            discreteVal.Value = filter;
            param.ParameterFieldName = "@Test";
            param.CurrentValues.Add(discreteVal);
            doc.SetParameterValue(param.ParameterFieldName, param.CurrentValues);

            this.CrystalReportViewer1.ReportSource = doc;
        }

So far pretty easy.  How the Silverlight part.  In this case we do not want to have a popup, but instead have our page appear to be a part of Silverlight application.  Let’s see what web page looks like that hosts Silverlight application.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="MyApp.Web._Default" %>

<%@ Register Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
    TagPrefix="asp" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="height: 100%;">
<head id="Head1" runat="server">
    <title>Report</title>
</head>
<body style="height: 100%; margin: 0;">
    <form id="form2" runat="server" style="height: 100%;">
    <asp:ScriptManager ID="ScriptManager2" runat="server">
    </asp:ScriptManager>
    <div style="height: 100%;">
        <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/MySilverlightApp.xap" MinimumVersion="2.0.30523"
            Width="100%" Height="80%" Windowless="true"/>
    </div>
    <iframe id="reportFrame" style="position:absolute; width:0px; height:0px; visibility:hidden"></iframe>
    </form>
</body>

</html>

As you can see, we are using frames in this case to show the report.  Now, the Silverlight code to launch a report:

private void ShowReportButton()        {
            HtmlElement m = HtmlPage.Document.GetElementById("reportFrame");
            if (m != null)
            {
                int top, left, width, height;
                top = (int)this.outerGrid.RowDefinitions[0].ActualHeight;
                left = (int)(this.outerGrid.ColumnDefinitions[0].ActualWidth + this.outerGrid.ColumnDefinitions[1].ActualWidth);
                width = (int)this.outerGrid.ActualWidth – left;
                height = (int)this.outerGrid.ActualHeight – top;
                m.SetStyleAttribute("left", left.ToString());
                m.SetStyleAttribute("top", top.ToString());
                m.SetStyleAttribute("width", width.ToString());
                m.SetStyleAttribute("height", height.ToString());
                m.SetAttribute("src", "ReportView.aspx?param=P");
                m.SetStyleAttribute("visibility", "visible");
            }
        }

In the code about outerGrid is the control that hosts main Silverlight application.  So, since our Silverlight application is located at position (0,0) in the web page (top left corner), we can compute the coordinates and size of report frame by using actual height and width of our Silverlight controls.  Once that is done, we can control the location of the frame and its size to make it appear as part of Silverlight application.  You would also need to listen to resize events of the browser in order to control the size of the report window.

This is my attempt to write a comprehensive guide to Silverlight reporting.

Post to Twitter

GGMUG Presentation on Silverlight Data Access

Today I did a presentation at the GGMUG (Gwinnett, GA Microsoft Users’ Group) meeting on Silverlight’s data access.  Download presentation and project here.

Post to Twitter

Integrating Reporting Services (SSRS) 2008 into Silverlight applications

Task of the day: create SSRS reports that can be shared between desktop (WPF) and Silverlight applications.

Silverlight does not have SSRS report viewer.  So what should we do?  The cleanest (and easiest) solution is to utilize ASP.NET capabilities.  ASP.NET does have web based controls for viewing SSRS reports.  So, we will create an aspx page in the web application that hosts Silverlight application.  We will set it up as follows:

<%@ Register Assembly="Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
    Namespace="Microsoft.Reporting.WebForms" TagPrefix="rsweb" %>
<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<head runat="server">
    <title>Report</title>
</head>
<body>
    <form id="form1" runat="server" style="height:100%" >
    <div style="height:100%" >
        <rsweb:ReportViewer ID="MainReportViewer" runat="server" 
            ProcessingMode="Remote"
            Width="95%"
            Height="700"
            ShowExportControls="True"
            ShowFindControls="True"
            ShowParameterPrompts="False"
            ShowPromptAreaButton="False"
            ShowRefreshButton="False"
            BackColor="White">
            <ServerReport DisplayName="MainReport" ReportServerUrl="" />
        </rsweb:ReportViewer>
    </div>
    </form>
</body>
</html>

Now the next step is to make sure this web page can parse query parameters and show appropriate report:

protected void Page_Load(object sender, EventArgs e)
        {
            MainReportViewer.ProcessingMode = ProcessingMode.Remote;
            MainReportViewer.ServerReport.ReportPath = "/SSRSReports/" + this.Request.QueryString["ReportName"];
            MainReportViewer.ServerReport.ReportServerUrl = new Uri("http://localhost:8080/ReportServer_SQL2008");
            List<ReportParameter> parameters = new List<ReportParameter>();
            List<string> values = new List<string>();
            values.Add("1");
            values.Add("2");
            values.Add("3");
            ReportParameter oneParamter = new ReportParameter("MyParameter", values.ToArray());
            parameters.Add(oneParamter);
            MainReportViewer.ServerReport.SetParameters(parameters.ToArray());
            MainReportViewer.ShowParameterPrompts = false;
            MainReportViewer.ServerReport.Refresh();
        }

Code above contains hard-coded report parameters.  But, as you can see those can be easily passed in as part of query string as well.

Now, code from Silverlight application:

private void Button_Click(object sender, RoutedEventArgs e)
    {

        Uri sourceUri = new Uri(HtmlPage.Document.DocumentUri, Application.Current.Host.Source.ToString().Substring(0, Application.Current.Host.Source.ToString().IndexOf("ClientBin") – 1) + "/ReportViewerForm.aspx?ReportName=DevelopmentPlanAction");

        if (true == HtmlPage.IsPopupWindowAllowed)
        {
            System.Text.StringBuilder codeToRun = new System.Text.StringBuilder();
            codeToRun.Append("window.open(");
            codeToRun.Append("\"");
            codeToRun.Append(sourceUri.ToString());
            codeToRun.Append("\",");
            codeToRun.Append("\"");
            codeToRun.Append("\",");
            codeToRun.Append("\"");
            codeToRun.Append("width=1000,height=900,scrollbars=yes,menubar=no,toolbar=no,resizable=yes");
            codeToRun.Append("\");");
            try
            {
                HtmlPage.Window.Eval(codeToRun.ToString());
            }
            catch
            {
                MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
            }
        }
        else
            MessageBox.Show("You must enable popups to view reports.  Safari browser is not supported.", "Error", MessageBoxButton.OK);
    }

This code simply creates a javascript that is using the same web URL, but adds the address to our report viewer web page we just created.  Ideally, we should have use  built-in Silverlight function HtmlPage.PopupWindow, but it does not honor options, always creating non-resizeable browser window.  So, I am resorting to javascript instead that does create a resizeable window, but without menu, etc…  The only sad part is that Siliverlight application does launch another window, but there is no way to workaround this issue.  Overall I am pretty happy with this solution.  What is also pretty cool is that the same SSRS report can be called from WPF application.  In that case we use WinForm SSRS viewer that we host inside WindowsFormsHost  control like so:

<winForms:WindowsFormsHost x:Name="ViwerHost" Grid.Row="1" Background="White">
            <reports:ReportViewer x:Name="ReportViewerControl">
            </reports:ReportViewer>
        </winForms:WindowsFormsHost>

The code to launch the report is pretty much identical to the one for ASP.NET

Cool, hah?

Post to Twitter

Reusable WPF/Silverlight Animations

As I was working on fixing some animations that got broken due to splitting on one control into multiple controls, I came up with an idea of creating a single animation that could be apply to multiple controls.  In my case, the animation was two-fold.  As control came into view, it should fade into the view as well as "bounce".  Essentially, this animation utilizes scale transform and opacity transform.  Here is the new class I wrote.  The cool thing is that this class can be called with any UI element or control.As a matter of fact, the control does not even need to have transform group defined for it, as the class will create one on the fly to support desired animation.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media;

namespace App.Animation
{
    public static class InitialControlAnimation
    {
        public static void Play(UIElement controlToAnimate)
        {
            Storyboard story = new Storyboard();

            // opacity animation
            DoubleAnimationUsingKeyFrames opacityAnimation = new DoubleAnimationUsingKeyFrames();
            opacityAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.8, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            ((SplineDoubleKeyFrame)opacityAnimation.KeyFrames[2]).KeySpline = new KeySpline(0, 1, 1, 1);
            Storyboard.SetTarget(opacityAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath(UIElement.OpacityProperty));
            story.Children.Add(opacityAnimation);

            //stretch horizontally
            DoubleAnimationUsingKeyFrames scaleXAnimation = new DoubleAnimationUsingKeyFrames();
            scaleXAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleXAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleXAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));
            story.Children.Add(scaleXAnimation);

            //stretch vertically
            DoubleAnimationUsingKeyFrames scaleYAnimation = new DoubleAnimationUsingKeyFrames();
            scaleYAnimation.BeginTime = TimeSpan.FromMilliseconds(0);
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(0.95, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1.08, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(200))));
            scaleYAnimation.KeyFrames.Add(new SplineDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300))));
            Storyboard.SetTarget(scaleYAnimation, controlToAnimate);
            Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
            story.Children.Add(scaleYAnimation);

            if (!(controlToAnimate.RenderTransform is TransformGroup))
            {
                TransformGroup group = new TransformGroup();
                group.Children.Add(new ScaleTransform(1, 1, controlToAnimate.RenderSize.Height / 2, controlToAnimate.RenderSize.Width / 2));
                controlToAnimate.RenderTransform = group;
            }
            story.Begin();

        }
    }
}

Post to Twitter

CSLA .NET for Silverlight webcast on 11/13

Magenic is sponsoring a webcast about CSLA .NET for Silverlight on November 13. I will be doing this presentation.  I am very excited about this opportunity.  I think very highly of Silverlight/WPF technologies.  I have also being using CSLA for almost 2 years now on nearly daily basis.  As you may have noticed from other posts, I got an opportunity to work with Rocky Lhotka on CSLA for Silverlight for about three months.  I am hopeful that I can share my excitement and get people interested in CSLA for Silverlight.  I honestly believe that Silverlight can revolutionize business application development for the web, and CSLA can play a very big role in this process as the very first (to my knowledge) business framework for Silverlight.

Post to Twitter

CoDe magazine article

I have been working on CSLA for Silverlight project with Rocky Lhotka, Justin Chase, Nermin Dibek, and Mark Steinberg for about three months.  I really enjoyed this challenging and interesting work.  It has been a great opportunity for me to work with the latest technologies and great, smart and super knowledgeable people.  About a month ago Rocky invited Justin and I to help write an article for CoDe magazine on CSLA for Silverlight.  As you can imagine,  both of us jumped at this opportunity.  As Justin just informed me, the article has been published!  I am super (and I mean SUPER) excited.  Read "Using CSLA .NET for Silverlight to Build Line-of-Business Applications" article online here.

Yeay, I am a published author!

Post to Twitter

Silverlight Error Code 4001 AG_E_NETWORK_ERROR

I encountered this error today, working on a custom Silverlight application.  According to Silverlight.Net this is not a bug.  However, I think it is an issue with Silverlight 2.0 RTW release.  Based on other posts the following situation causes this issue.  You have two images one next to another in your XAML that have the same image file name as source.  Image is actually displayed properly even with the error.  This is exactly what I have in my page.  Here is a workaround that I found.  I had to add the following code to the ASPX page that hosts Silverlight control.

<script type="text/javascript">
    function tellerror(msg, url, linenumber) {
        if (msg.toString().indexOf("Image") >= 0 && msg.toString().indexOf("4001") >= 0) {
            return true;
        }
        else {
            alert('Error message= ' + msg + '\nURL= ' + url + '\nLine Number= ' + linenumber)
            return true;
        }
    }

    window.onerror = tellerror;
</script>

Post to Twitter