Archive of entries posted on October 2009

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.

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.

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.

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.

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.

C# 4.0 (.NET 4.0) Features

As part of our first ALEMUG meeting I did a presentation on some of the new features in C# 4.0.  Here is what I talked about.

First topic was on optional and named parameters in C#.  Here is how you would define a function with optional parameters:

public static int AddTwoOrThreeOrFourNumbers(int numberOne = 0, int numberTwo = 0, int numberThree = 0, int numberFour = 0)

{

    int returnValue = numberOne + numberTwo + numberThree + numberFour;

    return returnValue;

}

All you need to do to define optional parameters is to provide a default value for each one. Here is how you could call this function by providing values only for some parameters:

ClassWithOptionalParameters.AddTwoOrThreeOrFourNumbers(1, 2)

As you see, I only supplied two out of three parameters.  All the magic is preformed by the compiler.  If you look at disassembled code, you will find that call to the function actually has all three parameters defined, just the last one is zero.

Another related feature is named parameters.  You can actually specify the name and the value for each parameters explicitly and out of order even:

ClassWithOptionalParameters.AddTwoOrThreeOrFourNumbers(numberOne: 1, numberFour: 4)

 

There are a few great uses for named / optional parameters.  One is COM Interop, specifically Office Interop.  Many functions in the Office take a number of optional parameter.  Right now you have to specify all of them.  With C# 4.0 you can specify just the ones you need.  Here is an example for SavedAs:

var format = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97;

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();

var doc = word.Documents.Add();

doc.SaveAs(FileName: fileNameSaved, FileFormat: format);

In general, there are many features in C# to make Office development easier.  One of them (pointed out by Jim Wooly)  is No PIA – No Primary Interop Assembly distribution. To use this feature just go to properties of office interop assembly in the references window and set Embed Interop Types to True.  If you do, you do not have to distribute Interop assembly! 

Another features I talked about is dynamics.  Here is you declare a dynamic variable:

dynamic person = ExpandoClass.GetExpando();

Looks very similar to var, doesn’t it?  There is a big difference though between vars and dynamics.  The key difference is the resolution time.  Vars are resolved at compile time, and they are actually strongly typed in the running program.  Dynamics on the other hand are resolved at run time.  As a result, you can compile pretty much any code that refers to dynamics.  For example, you can type

dynamic thing = GetSomeDynamicObject();

thing.SomeProperty = 1;

SomeProperty actually does not exist anywhere in the source code, it is called dynamically at run time and it will succeed as long as whatever object is returned by GetSomeDynamicObject function has this property.  Very powerful feature when it comes to interacting with objects unknown at compile time.  You can use it to interact with dynamic languages such Python or COM objects or even other .NET objects.  Here is some code I came up with (not that I would write something like this, but it demonstrate the power of the feature) – universal sorter that can sort any collection:

    public static class DynamicDemo

    {

        public static IEnumerable<dynamic> GetSortedData(IEnumerable<dynamic> initialCollection, Func<dynamic, dynamic> sortExpression)

        {

            dynamic retVal = (from one in initialCollection

                              orderby sortExpression(one)

                              select one);

            return retVal;

        }

Dynamics is a very powerful features, but can be easily abused.  Also, anything can be dynamic, not just objects.  You can also have dynamic properties and methods and their parameters.

Another related feature is ExpandoObject.  This is a dynamic object that can be “expanded” at run time to contain custom properties and values:

dynamic expando = new System.Dynamic.ExpandoObject();

expando.Name = "Sergey Barskiy";

expando.Age = 18;

Seems pretty weird – I actually define the object at run time.

You can download sample solution (requires VS 2010) here.

ALEMUG.net meeting

Atlanta Leading Edge Microsoft Users Group is meeting tomorrow.  Our topic will be new features in C# 4.0 and .NET Framework 4.0.  Some of the topics are contra-variance and co-variance, dynamic types, office interop, named and optional parameters, code contracts.

Please join us tomorrow for an exciting meeting.  See the website for directions and times – www.alemug.net.

See you tomorrow.

SQL Saturday #25

I spoke yesterday at SQL Saturday event in Gainesville, GA.  My topic was CLR Integration in SQL Server. 

CLR stands for Common Language Runtime or .NET Framework.  This SQL Server 2005 or higher feature allows developers to write .NET assemblies and deploy them in SQL Sever.  You can implement scalar and table-values functions, stored procedures, triggers, user defined types and aggregates.

In my talk I spoke of features that I worked or had a need for.  Those included interacting with OS, such as file access or registry access.  I also talked about implementing fuzzy matching logic, creating custom bitmaps and utilizing them in SSRS reports.

You can download the sides and sample project here.

Thank you.

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.