« August 2008 | Main | October 2008 »

September 30, 2008

Part 1: Manage Page level states with VisualStateManager in Silverlight

Silverlight 2.0 Beta 2 introduced the concept of Visual State Manager (VSM). If you haven't checked it out still, here are some articles that will get you started.

VSM not only helps keep the looks and behavior of a control separate, it allows you to manage the various states the control can be in, along with the transitions, in a very clean and effective manner. Though most of the examples online today show this in context of a specific control and working with its control template, there is no reason why this can't be applied to the UserControl itself, i.e. at the Page level. You can very easily create custom states for your page and manage transitions between the states. In fact this can actually help reduce the total animations that you may have to write and also simplify the backend code.

In this two part blog post, I will explain this with a small sample. I am assuming basic understanding of Silverlight animations and VSM as well. In this first part I will explore how you would build an application without VSM and in part 2, create a similar experience but with using VSM. 

Let's start with taking a simplistic case where we will have 3 buttons on my Page which act like menu control.  On clicking a particular button, it will animate downwards, thus showing the active button. We will assume that the rest of the page has content filled up based on which button was clicked. To start with the here's the XAML with 3 buttons in a Grid.

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

        <Button HorizontalAlignment="Left" Margin="8,8,0,0" x:Name="btn1" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Content="Button 1" Click="btn1_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

        <Button HorizontalAlignment="Left" Margin="80,8,0,0" x:Name="btn2" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Content="Button 2" Click="btn2_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

        <Button HorizontalAlignment="Left" Margin="150,8,0,0" x:Name="btn3" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Content="Button 3" Click="btn3_Click">

            <Button.RenderTransform>

                <TransformGroup>

                    <ScaleTransform/>

                    <SkewTransform/>

                    <RotateTransform/>

                    <TranslateTransform/>

                </TransformGroup>

            </Button.RenderTransform>

        </Button>

    </Grid>

Next is to add the required animation so that a button can move to the new location. For this we can use Blend and add Button1Animation, which moves the button down. We use the TranslateTransform property and modify the Y value to 40. The animation storyboard is as below.

        <Storyboard x:Name="Button1Animation">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="40"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

While this animation moves the button down, we will need another animation to move the button back to its original position when another button is moved down. To do this, Blend offers an easy way by which we can create a duplicate animation and then reverse it from the Objects and Timeline panel. See the figure below.

duplicate.jpg

Using this approach, we get the Button1Animation_Copy animation.

        <Storyboard x:Name="Button1Animation_Copy">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

On similar lines we can create additional animations for the other two buttons to move them down and then back up. These are as below. 

        <Storyboard x:Name="Button2Animation">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="40"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="-72"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button2Animation_Copy">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-72"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button3Animation">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="40"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="-142"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

        <Storyboard x:Name="Button3Animation_Copy">

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="40"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="btn3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">

                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="-142"/>

                <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>

            </DoubleAnimationUsingKeyFrames>

        </Storyboard>

The next step is to stitch this together so that when we click a button, it moves down and the one already down moves back to its original position. For this the code will be something like below.

    public partial class Page : UserControl

    {

        enum MenuButton

        {

            None,

            One,

            Two,

            Three

        }

 

        MenuButton _current;

        public Page()

        {

            InitializeComponent();

            _current = MenuButton.None;

        }

 

        private void btn1_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.One)

            {

                AnimateOut(_current);

                Button1Animation.Begin();

                _current = MenuButton.One;

            }

        }

 

        private void btn2_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.Two)

            {

                AnimateOut(_current);

                Button2Animation.Begin();

                _current = MenuButton.Two;

            }

        }

 

        private void btn3_Click(object sender, RoutedEventArgs e)

        {

            //if the current button is different than the one clicked, animate it back and then animate this button in

            if (_current != MenuButton.Three)

            {

                AnimateOut(_current);

                Button3Animation.Begin();

                _current = MenuButton.Three;

            }

        }

 

        //animate the button back to its original location

        private void AnimateOut(MenuButton btn)

        {

            switch (btn)

            {

                case MenuButton.One:

                    Button1Animation_Copy.Begin();

                    break;

                case MenuButton.Two:

                    Button2Animation_Copy.Begin();

                    break;

                case MenuButton.Three:

                    Button3Animation_Copy.Begin();

                    break;

            }

        }

    }

If you run the application now and click any button, you will see it animate down and the previous button will animate and move back. This concludes part 1. In part 2 we will look at how using VSM, we can simplify this application and reduce the amount of code we have to write.

September 29, 2008

Silverlight 2.0 RC0 Installation

You would already be aware of the release of RC0 of Silverlight 2.0. If not check Scott's blog here. The details on the links for downloading these latest bits can be found in the same blog.

Note that unlike the previous Beta 2, this version doesn't comes with a go live license and if you visit the Silverlight installer page online, you will see that it still points to the earlier Beta 2 version (2.0.30523.8).  

Another aspect that Scott has explained, but may not be clearly understood by all is that this RC0 version will not work with the Blend 2.5 June Preview. It will work with Blend 2.0 SP1 only and if you try to install it with the June or any other beta/preview version you will get an error like below during installation. 

 SLRc0.jpg

Since I wanted to play around with this version, I uninstalled Blend 2.5 June preview and being an MVP, I have access to MSDN Subscriber downloads from where I downloaded and installed Expression Blend. Then I installed Blend SP1 preview (the link is given earlier in the blog) and finally ran the Silverlight RC0 setup (first uninstalled the previous Beta 2 bits).

The setup completed successfully, though initially it took a couple of min to show any update on the "Download Status". In fact for the first few min it didn't budge at all and I started suspecting if there was an issue with the installation package itself. But then it suddenly jumped to 100% and said "Download time remaining: 0:00:00". The installation after this took few more min and finally I was ready to try out SL RC0.

Quick test app creation and I had no issues in running it. The ASPX now shows the version as 2.0.30923. Interestingly if you visit the Silverlight installer page now, it says

"installed version 2.0.30523.9
requested version Silverlight 2 Beta 2 GDR 1 (2.0.30523.8)"

So it fails to recognize the new bits, which is as Scott mentioned in his blog. Let me get going with checking out this release and will share my experiences soon. Keep watching this space.

September 26, 2008

WPF: Gadget-Style User Experience

Building an application as a ‘gadget’ is a nice way to get away from standard, rectangular window based user experience. The Gadget approach allows the freedom to build applications with custom chrome and fun shapes. Let us look at simple steps to build engaging gadget-style applications in WPF.

With gadgets, designers can build shapes and animations to introduce subtle, metaphorical references about the application’s functionality.  Gadgets can be built in such a way that they look like objects ‘floating’ in your workspace. You can make them capable of being dragged around so that the user can position them on their desktop according to their preference.
For the purpose of this post, I have developed some XAML code using Microsoft Expression Blend that mimics the look of a plasma TV screen. Interested people can use my previous posts to host or run live videos using this ‘TV’ widget.


To begin with,
a.        First set your windows’ WindowStyle to None. This removes the all the Chrome elements associated with your base window.
b.       Now, set AllowsTransparency property to True. This step helps you to give that floating effect that adds to the unique gadget user experience.
c.        Next up, set Windows’s background to Transparent. This is the key step to get away from the default rectangular window paradigm. These three steps give you the cool gadget look you are looking for.
d.       Ideally, you should provide for a way to close the gadget running on your desktop. With the default window missing, you do not have the standard close window button on a custom gadget. Add a button and enable the closing on gadget using code-behind file.  
e.       One other thing you need to address is the ability to move the window around so that the user has flexibility in positioning the gadget anywhere on the desktop. For this, a good way to handle this is call window’s DragMove method.
Here is the XAML file for such a TV widget implemented in WPF.

 

XAML:
<Window
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                x:Class="infy_blog_on_widget.Window1"
                x:Name="Window"
                Title="Window1"
                Width="640" Height="480" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" WindowStyle="None" AllowsTransparency="True" Background="Transparent" MouseLeftButtonDown="Window_MouseLeftButtonDown">

 

                <Grid x:Name="process_panel" RenderTransformOrigin="0.5,0.5" Width="771.007" Height="311">
                                <Grid.RenderTransform>
                                                <TransformGroup>
                                                                <ScaleTransform ScaleX="1" ScaleY="1"/>
                                                                <SkewTransform AngleX="0" AngleY="0"/>
                                                                <RotateTransform Angle="0"/>
                                                                <TranslateTransform X="0" Y="0"/>
                                                </TransformGroup>
                                </Grid.RenderTransform>
                                <Rectangle Fill="#FFA4AFE4" Stroke="{x:Null}" RadiusX="20" RadiusY="20" Margin="82.757,-20.5,278.25,56.5" Width="410" Height="275"/>
                                <Rectangle Stroke="{x:Null}" RadiusX="20" RadiusY="20" Margin="83.723,-22.326,280.285,58.326" RenderTransformOrigin="0.5,0.5" Width="407" Height="275" d:LayoutOverrides="Margin">
                                                <Rectangle.RenderTransform>
                                                                <TransformGroup>
                                                                                <ScaleTransform ScaleX="0.995" ScaleY="0.98"/>
                                                                                <SkewTransform AngleX="0" AngleY="0"/>
                                                                                <RotateTransform Angle="0"/>
                                                                                <TranslateTransform X="0" Y="0"/>
                                                                </TransformGroup>
                                                </Rectangle.RenderTransform>
                                                <Rectangle.Fill>
                                                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                                                <GradientStop Color="#FF000000" Offset="1"/>
                                                                                <GradientStop Color="#FFE7EBF9" Offset="0.004"/>
                                                                                <GradientStop Color="#FFDFE2E8" Offset="0.004"/>
                                                                </LinearGradientBrush>
                                                </Rectangle.Fill>
                                </Rectangle>
                                <Rectangle Stroke="{x:Null}" RadiusX="20" RadiusY="20" Margin="80.941,-14.554,278.066,55.554" RenderTransformOrigin="0.5,0.5" Width="412" Height="270">
                                                <Rectangle.RenderTransform>
                                                                <TransformGroup>
                                                                                <ScaleTransform ScaleX="0.995" ScaleY="0.995"/>
                                                                                <SkewTransform AngleX="0" AngleY="0"/>
                                                                                <RotateTransform Angle="0"/>
                                                                                <TranslateTransform X="0" Y="0"/>
                                                                </TransformGroup>
                                                </Rectangle.RenderTransform>
                                                <Rectangle.Fill>
                                                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                                                                <GradientStop Color="#FFD1D3DC" Offset="1"/>
                                                                                <GradientStop Color="#FFC3D5F2" Offset="0.375"/>
                                                                                <GradientStop Color="#3FA4BBF0" Offset="0"/>
                                                                </LinearGradientBrush>
                                                </Rectangle.Fill>
                                </Rectangle>
                                <Rectangle Stroke="{x:Null}" RadiusX="5" RadiusY="5" Margin="102,11.5,299.007,79.5" Fill="#FF000000"/>
                                <Button HorizontalAlignment="Right" Margin="0,-12.5,299.007,0" VerticalAlignment="Top" Width="28" Height="17" Content="Close" Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}" FontSize="8" Click="Button_Click"/>
                </Grid>
</Window>

 

And here is the code-behind piece to handle closing and drag-moving.

 

public partial class Window1 : Window
      {
            public Window1()
            {
                  this.InitializeComponent();
                 
                  // Insert code required on object creation below this point.
            }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
        }
      }

September 24, 2008

WPF - Displaying enums in ComboBox control

Displaying enums in ComboBox in WPF isn't really rocket science. The issue however comes when you want to display user friendly strings against the enum values. Enum unfortunately doesn't support this by a simple override to the ToString method.

The usual approach people take is the use the DescriptionAttribute. This attribute is assigned to each enum value and at runtime, using reflection, the value of the attribute is queried and is then displayed. The approach is definitely worth considering and I found an implementation of the same and a custom WPF ComboBox that will display such user friendly enum strings here.

However reflection does mean a bit of performance impact and depending on the size of the enum, this can vary. In the above implementation, the values are hence cached for any reuse and improve efficiency. However if the binding happens only once, this has no effect.

I was hence wondering on how to do this without having to use reflection. I then hit upon an idea of using a dictionary object with the enum as the key and the value as the user friendly string. It was then a matter of binding this with the ComboBox and set the DisplayMemberPath appropriately. In order to ensure that the enum and this dictionary collection go hand in hand, I decided to encapsulate them in a single class. There is definitely a maintenance overhead of ensuring that appropriate key value pair is added to the dictionary for each enum. See the code for this class below.

    internal class Utility

    {

        static Utility()

        {

            //initialize the collection with user friendly strings for each enum

            _monthCol = new Dictionary<Months, string>(){

                {Months.Jan, "January"},

                {Months.Feb, "February"},

                {Months.Mar, "March"},

                {Months.Apr, "April"},

                {Months.May, "May"},

                {Months.Jun, "June"},

                {Months.Jul, "July"},

                {Months.Aug, "August"},

                {Months.Sep, "September"},

                {Months.Oct, "October"},

                {Months.Nov, "November"},

                {Months.Dec, "December"}};

 

        }

 

        public enum Months

        {

            Jan,

            Feb,

            Mar,

            Apr,

            May,

            Jun,

            Jul,

            Aug,

            Sep,

            Oct,

            Nov,

            Dec

        }

 

        private static Dictionary<Months, string> _monthCol;

        public static Dictionary<Months, string> MonthCollection

        {

            get

            {

                return _monthCol;

            }

        }

    }

and in XAML, this Utility class can be instantiated as a resource and then referenced in the ComboBox creation.  

            <ComboBox ItemsSource="{Binding Source={StaticResource monthCollection}, Path=MonthCollection}" SelectedIndex="0" DisplayMemberPath="Value" SelectedValuePath="Key" />

Note that the SelectedValuePath property has also been set to point to the Key in the dictionary. with this, it is easy to handle the selection changed event and the combobox's SelectedValue property will then be the enum value and you can then easily use a switch/case block to handle it appropriately. If  you don't do it, you can still easily cast this to get to the enum value as below

            switch(((KeyValuePair<Utility.Months, string>)cmbBox.SelectedValue).Key)

            {

                //your case statements here

                default:

                    //custom logic

                break;

            }

 Comments welcome !

 

 

 

September 22, 2008

Hiding from Debugger

When writing trivial get/set type properties, I have seen many developers still struggle during debugging since if they do a step into (typically F11), they end up going into the getter and setter methods as well.

Debugger related attributes have been available since early times, but somehow people seem unaware. Typically one can use DebuggerHidden or DebuggerStepThrough attributes, as shown in the following code snippet.

        public int MyIntProperty

        {

            [DebuggerStepThrough]

            get { return myVar; }

            [DebuggerHidden]

            set { myVar = value; }

        }

This functionality has been further simplified in VS 2008 by virtue of a setting that by default is set to step over properties and operators. See the figure below (VS - Tools - Options).

PropertyDebug.jpg

The issue with this however is that it works globally so if for some properties one wishes to step into and for some one doesn't, this setting will not help and one needs to revert back to using the specific attributes.

An interesting benefit of using the automatic property feature, added with C# 3.5, is that the debugger automatically steps over such property declarations.

        public int MyIntProperty { get; set; }

So apart from making the code concise and one having to think of less variable names, one can also get this side benefit of debugger step through without having to assign any attributes or enabling the setting in VS tools options dialog.

September 20, 2008

Emotional Design and Rich Interactive Applications

Last week, we considered the need to derive UX differentiation by deploying RIA technologies (Silverlight, WPF, Flash, AIR and the likes) to address real user aspirations. We also took notice of the fact that very often; these user aspirations are about making the digital technology around them more life-like.

This week, let us dig a little deeper to understand why the users aspire for life-like interactive experiences; and how this has helped us identify the key principles behind ALIVE Design approach.

As eloquently explained by on Don Norman in his brilliant book, Emotional Design  


“we are social creatures, biologically prepared to interact with others, and the nature of that interaction depends very much on our ability to understand another’s mood. We have a tendency to read emotional responses into anything, animate or not. We have evolved to interpret even the most subtle indicators.  And we use the same source or faculty to interpret inanimate objects as we use for interpreting animate objects like people and even animals around us. This might seem bizarre, but the impulses to interpret inanimate objects come from the same source as used for animate world!


We interpret everything we experience. Much of this interpretation is in human terms. This is called as anthropomorphism, the attribution of human motivation, belief and feelings to animals and inanimate things. Examples of this are all around us. We treat tennis rackets, balls, hand tools, computer hardware as well as software as animate beings, verbally praising when they do a good job and blaming them when they refuse to the job.


We cannot control those initial interpretations for they come automatically.  It is extremely important that designers (particularly the designers engaged in building rich, interactive applications) keep in mind the human predisposition to anthropomorphize and be guided by how it works. The principles for designing pleasurable, effective interactions between humans and products are the same that support pleasurable and effective interactions between individual humans.


RIA technologies are uniquely positioned to deliver pleasurable interactions because of their technical prowess,. But for pleasure to be a reality, the technical prowess needs to deliver interactive experiences very close to effective interactions between individual humans. This is the core idea driving ALIVE design methodology.

There are three overarching principles, rooted in anthropomorphism and associated with human behavior that ALIVE design tries to focus on and deliver against. They are Connectivity, Responsiveness and Natural interactivity.


Connectivity: Connectivity is critical, even just to begin the interaction. It is the first stage in getting engaged. In our social interaction with animate world, we ‘connect’ well with certain people because in their behavior we get all the right clues that make us think that the person is ‘sociable’. Same is true for inanimate, interactive objects.  We will look at these clues and their relevance for design in more detail in upcoming articles. But for now, we will define connectivity as that set of qualities in an interactive artifact that makes it as easy to connect, and stay connected with - just as you would with an individual you find easy to ‘connect’.


Responsiveness: Responsiveness is what sustains interaction – mainly by sustaining the interest. When something interacts with us, we ‘interpret’ that interaction.  The more responsive it is to us through its body actions, language, taking of turns and general reciprocity, the more we treat it like a ‘social actor’. Therefore, responsiveness is an essential ingredient to make an interactive artifact more like an individual we look forward to interacting with. We will look at more details on how to build this level of responsiveness in the follow up postings.


Natural interactivity: Natural interactivity is about judiciously leveraging subtle or direct real life metaphors for semantic communication.  Metaphors like ‘Desktops’ and ‘File Systems’ have helped enormously in making daily computing tasks accessible to novice users. This is because users have a clear mental model of ‘how this works’.  Natural interactivity takes this approach further and applies it to interactions. Designers can build clues, feedbacks or mappings that evoke a strong feeling of ‘having positively experienced this before’. While connectivity and responsiveness feed and arouse our basic anthropomorphic tendencies, natural interactivity affirms those very tendencies. It makes the interactive experience ‘engaging’ by reinforcing our tacit belief that we are interacting with something real and sociable.


If Rich Interactive Applications (RIAs) on new platforms like Silverlight and WPF are designed with these principles in mind, we may be able to break away from stereotypes about how user experience should look and feel. For example, take the case of ‘Help’ user experience.  Flashy Help systems that still rely on users reading though a bunch of ‘Help’ documents fall way short of real potential of platforms like WPF and Silverlight. Why not build video based support materials that users can better connect and interact with?


Such innovations, driven by ALIVE Design principles, could lead to meaningful differentiation – differentiation that users would appreciate.  We will look at more potential areas for ALIVE Design driven user experience innovations in follow-up posts.

September 18, 2008

Windows 7

Back in June I had mentioned about Windows 7 and that there is lack of information and a changed stance from Microsoft. If you haven't noticed, there is now a blog (about a month now) by the Windows 7 team called Engineering Windows 7. The likes of Jon DeVaan and Steven Sinofsky, along with other team members blog here.

If you want to know what goes behind creating something like a Windows operating system, this will give you a good perpective.

September 15, 2008

Unable to add reference to assemblies in GAC from VS

Recently someone asked me about an issue he was facing in being able to add reference to an assembly in GAC from Visual Studio. This is a question that somehow keeps coming back. If you search online you will surely get pointers on how to solve this. The typical way is to provide the path to where your specific assemblies are by adding a registry key pointing to it, or add it to the already known standard paths and you will start to see your assembly in the .NET tab of the Add Reference dialog. See more details here. VS picks up files found in this path also - C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies.

Now if you are satisfied by this, you have really only addressed the symptoms, but not the root cause. What is still unanswered is why VS didn't allow you add assemblies from GAC in the first place and went about it in a roundabout way?

In my opinion, there are really two aspects to this. The first is more about the fact that GAC isn't really organized the way it is seen as! Hmm, sounds a bit philosophical. In case you aren't aware .NET comes along with a Windows shell extension called Shfusion.dll. This DLL is found in your framework install path (on my machine the path is C:\Windows\Microsoft.NET\Framework\v2.0.50727).  The typical view that you see that lists the name, version, culture, public key token and processor architecture is a view managed by this shell extension. Incidentally if you didn't know which is GAC folder, it is c:\windows\assembly or you can just type assembly in start/run and view this folder.

I am surprised that people don't automatically realize this for the simple fact that in a window's folder, you can't have two files with the same name. We can store multiple assemblies in GAC which have same name, but different assembly version. This by itself should be sufficient to point out that the folder structure has to be different than what is seen.

So, if you remove the shell extension, you can see the true folder structure. There are registry values that you can tweak (set HKLM\Software\Microsoft\Fusion\DisableCacheViewer [DWORD] to 1), but I personally prefer the simpler option of unregistering the shfusion.dll. You can run regsvr32.exe with -u command line option to unregister shfusion.dll (something like regsvr32 -u  C:\Windows\Microsoft.NET\Framework\v2.0.50727\shfusion.dll). After this if you view the GAC in your windows explorer you will see the real structure which looks something like below.  

GAC.jpg

The framework assemblies and other assemblies in GAC actually reside inside of a sub directory called GAC_MSIL. Within this a folder is created by the name of the assembly and then another folder inside of that with the version number. So each version actually sits inside of a folder named by the version and hence you are able to copy as many files with the same names but different versions in GAC. BTW, if you want to view GAC, without even bothering to unregister the shfusion.dll, you can use the good old command prompt and navigate to C:\Windows\Assembly and view the directories, sub directories and the files in this folder.

When you want to add a reference to an assembly for VS to use, it needs to know the path so that it can access that and the compiler can also access the assembly during compilation. Since GAC's actual directory structure is hidden behind the shell extension, VS can't really show the actual folder structure. You may argue that one can write code to query the folders and sub folders and then display the assemblies, but this will be a significant overhead while showing the Add Reference dialog. An easier approach would be to just put the assemblies in some other known path and load from there and that's exactly what is done. Hence you will find two copies of all the framework assemblies. One set is in GAC and another is in C:\Windows\Microsoft.NET\Framework\v2.0.50727 (or C:\Program Files\Reference Assemblies\Microsoft\Framework for 3.0 and 3.5). Also as mentioned earlier, the registry settings allow you to configure your own path that VS uses to show the files.

The second aspect more deals with the purpose of GAC itself. You would surely be already aware that GAC is a place to put shared assemblies i.e. assemblies used by many applications are put here. We already saw how GAC allows you to place multiple versions of the assemblies as well. So what this mean? If you pay little attention to detail, you would realize that the idea of shared assemblies for applications really is to do with the run state of the application. What I am trying to say is that when an application is running, it may pick up assemblies from GAC along with those that are privately deployed. While this is dealing with runtime behavior, VS is really a developer tool and is more about design time and build process. Why should anyone be bothered about GAC at this time? All developers need is to be able to add reference to the appropriate assemblies and compile and build against them. The deployment will take care of ensuring that all required assemblies (private and shared) are appropriately deployed and it is at this time that the CLR will probe GAC if it can't find an assembly required by the application in the private probing path. Hence in my opinion, the question "I can't add reference to assemblies in GAC in VS" is really invalid, since you should not be doing it anyway.

Hope this helps. Any comments are most welcome.

September 12, 2008

Meaningful Differentiation for Rich Interactive Applications and the ALIVE Design Manifesto

Back in April 08, I posted a blog article, Demystifying the ‘Differentiated’ User Experience (UX)”. In that article, I tried to shed some light on the new buzzword (or buzz-phrase), ‘differentiated UX’, used by Microsoft evangelists to promote emerging UX technologies like Silverlight and WPF. I suggested that the entire ‘differentiation argument’ seemed to focus on the ‘means’ and not the ‘ends’ to be met. I also promised a few more posts to suggest a way forward to correct this and achieve meaningful differentiation.

This article is the first in a series of articles I plan to write to take this topic forward.


In this article, we will consider the rational for having a new approach - 'ALIVE' Design as we call it - to achieve this UX differentiation. 


Differentiated or otherwise, when one talks about ‘user experience’, it important to keep in mind that the term gets used (and at times abused) in different ways by different people. While I like the broad, more holistic reach this term gives as compared to user interface design or interaction design, there are some pitfalls. Two key lessons I have learned through all my years in design practice.


1.       User experience is a deeply personal thing. How people ‘experience’ a product – interactive or otherwise -is rooted in their past and present experiences, and also in their aspirations about future experiences. Genuine understanding and empathy about those past, present and future experiences is the key. Only by understanding what experiences people dream of and aspire to can we hope to develop meaningfully differentiated user experiences.


2.        Latest user experience technologies give us the capabilities to build cool user experiences. But user experience differentiation does not happen when it is built and ready. It can only happen when it is consumed and experienced. With clever manipulation of design technology faculties, there is a lot that the designer can do to guide the kind of experiences and emotions the design will evoke. Great designers have almost made a science out of this. But even they agree, they can only build and hope. The ultimate experience is personal, and so may defy all the logic used for differentiation.


This is why all the talk about building differentiated user experiences, with all its stress on technology, needs a rethink. What we need is a methodology that deploys technology to address user aspirations.  Silverlight, WPF or any other RIA technology should not be reduced to building ‘flashy’ interactive toys. They should be put to use to make the digital world around us more like what we aspire it to be.

Very often, these aspirations are about making the digital technology more life-like. This way, the barriers between the man and the machine – borne out of interpretations and translations - start to disappear. This is what ALIVE design tries to get its inspiration from.

September 9, 2008

Role of Claims based Authentication in Federated Security -- 3

With the basics of Cryptography discussed in the previous blog, we will now look at the Certificates and how the certificate chain is built. This is an important concept as the Claims based Authentication works in similar lines.

A certificate is an electronic document used to identify an individual, a server, a company, or some other entity and to associate that identity with a public key  It typicall contains the following information

• Certificate Version
• Certificate Serial Number.
• Digital Signature algorithm used by user.
• Information about the CA
• Information about the entity using the certificate
• Public key of the entity using the certificate
• Certificate expiration date
• Digital Signature Algorithm used by the CA.
• A digital signature of the certificate contents signed by the CA

I would like to emphasize on the last point. Digital Signature of the contents by CA. This ensures that anybody who wants to validate the contents and who the issuer is, it is eaisly possible as in DS only the person with private key could have signed, thus verifying CA. In this way a chain of trust can be built. For Example, if Prashanth Govindaiah has a certificate issues by his department CA, ABC and if ABC is issues by Infosys CA and if Infosys CA certificate is issues by say Verisign. the verifier of my certificate through DS, will first get to know that this is issued by ABC, Since it does not trust ABC, it checks the DS and gets to know that Infosys has issues ABC. Since it does not trust Infosys, it checks DS and gets to know Verisign has issued it and since it trusts verisign, it  in turn trusts other certificates in the chain. The same can be diagrammatically represented as

CAChain.JPG 

September 8, 2008

How to write custom Main method for a WPF application?

If you have been working with WPF applications you know that the current default behavior for adding the entry point (Main) method is via codegen. You don't write it yourself. The method is generated when you compile your application. A typical WPF project contains App.xaml which is marked as ApplicationDefinition in the csproj file.

    <ApplicationDefinition Include="App.xaml">

      <Generator>MSBuild:Compile</Generator>

      <SubType>Designer</SubType>

    </ApplicationDefinition>

It is due to this tag, that MSBuild when compiling the project adds the Main method to App.g.cs that is created in the obj/debug (or obj/release) folder. The generated file looks something like below. See details here.

    public partial class App : System.Windows.Application {

 

        /// <summary>

        /// InitializeComponent

        /// </summary>

        [System.Diagnostics.DebuggerNonUserCodeAttribute()]

        public void InitializeComponent() {

 

            #line 4 "..\..\App.xaml"

            this.Exit += new System.Windows.ExitEventHandler(this.Application_Exit);

 

            #line default

            #line hidden

 

            #line 4 "..\..\App.xaml"

            this.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);

 

            #line default

            #line hidden

        }

 

        /// <summary>

        /// Application Entry Point.

        /// </summary>

        [System.STAThreadAttribute()]

        [System.Diagnostics.DebuggerNonUserCodeAttribute()]

        public static void Main() {

            DummyApp.App app = new DummyApp.App();

            app.InitializeComponent();

            app.Run();

        }

    }

 

Hence, If you try to directly add code for Main method in App.xaml.cs, you will end up compiler error stating that there is already a definition of Main method. To add your own implementation, there are various approaches and you can pick that works best for you

Approach 1
You can delete the existing App.xaml and App.xaml.cs and add a new class file and maybe call it App.cs. In this you can define the App class and write your own Main method as below.

    public class App : System.Windows.Application

    {       

        [STAThread]

        public static void Main()

        {

            App app = new App();

            app.StartupUri = new System.Uri("Window1.xaml", System.UriKind.Relative);

            app.Run();

        }

    }

 

Approach 2
You will run into issues with Approach 1 if you are adding resources and resource dictionaries to your App.xaml. Since the App.xaml is no longer present you will have to write code in your App.cs itself to manage the resources and the merged dictionaries. However this can be more easily handled by modifying the .csproj file and marking App.xaml as Page instead of ApplicationDefinition 

    <Page Include="App.xaml">

      <Generator>MSBuild:Compile</Generator>

      <SubType>Designer</SubType>
    </Page>

 

 

Due to this change, the default entry point is no longer generated and you can write your own which can be something like below. For detailed discussion on this check Dr. WPF's blog.

 

    public partial class App : System.Windows.Application

    {

        [STAThread()]

        static void Main()

        {

            App app = new App();

            app.InitializeComponent();

            app.Run();

        }

    }

 

Approach 3
If you have resources and hence want to have App.xaml, but don't like to tamper with .csproj file, then you can include another class in your project that defines the Main method as below.

 

    class Startup

    {

        [STAThread]

        static void Main()

        {

            App app = new App();

            app.MainWindow = new Window1();

            app.MainWindow.Show();

            app.Run();

        }

    }

 

However compilation will result in error stating that the EXE now has multiple entry points. You can then use the /main compiler option to identify the class whose main you want the application to use as entry point. This can be done via the project properties. In the Application tab, modify the Startup object properties from the drop down. See figure below.

 

startup.jpg

 

Each approach will result in the desired behavior of having a custom entry point defined instead of using the default code generated method. You can pick any approach that works for you.

September 5, 2008

IE 8 Beta 2 - Your last browsing session closed unexpectedly

IE8.jpg

Are you seeing something like this with IE 8 Beta 2? I have been getting this on and off and just realized when this occurs. If you are debugging a web based project (ASP.NET or Silverlight) from VS and then stop debugging from VS, the next time you open the browser, you will get this message. No harm done. You just select the "Go to your home page" option.

Interestingly, this doesn't occur if you are debugging, but instead of stopping debugging from VS, you directly close the browser window. 

Targeting .NET framework 3.5 SP1

If you working with VS 2008 you must be already aware about how to target your application to run on different .NET frameworks. With .NET framework 3.5 SP1 now available, I wanted to target my application for this version, but surprisingly VS 2008 doesn't shows this in the list of target .NET frameworks. Harish describes how to get this done. Check it out here.

It would have been much simpler to just provide this option in the existing drop down itself !

September 4, 2008

Debugging into .net source code

You may be aware of the availability of .net source code for debugging. Scott Guthrie had mentioned this along with release of VS 2008. Though Reflector still remains my personal favorite for quickly checking the .net source code during my regular work, it can't help much during debugging.

Recently the .net 3.5 SP1 code was also made available. In case you haven't checked this out, here are the instructions on how you can configure and use this feature from VS 2008. I tried this and it is awesome to be able to debug straight into .net source code and see what is really happening in there. Do note, however, as Shawn also mentions, the initial load time can be pretty high and i had to wait almost 30 min before I could start on with debugging. However since the symbols and the .cs files are cached locally, it is very fast thereafter. Go ahead and give it a try !

September 2, 2008

Role of Claims based Authentication in Federated Security -- 2

In Continuation of my earlier blog, In this blog we will see some of the basics of Cryptography in this entry. This inlcudes Symmetric and Asymmetric Encryption, Digital Signatures

Symmetric Encryption: As the diagram shows the same key is used for encrypting and decrypting the message

 Sym.JPG

Asymmetric Encryption:As the diagram shows, here 2 keys are used for encrypting and decrypting. Either of the 2 can be used for encrypting and decrypting and the purpose drives which is used when. When the criteria is confidentiality like in the case of https communication, public key is used for encryption and private key is used for decryption. Inc ase where Data Integrity, Non reudiation is the criteria, private key is used for encryption and the public key is used for decryption as in the case of Digital Signatures.  

ASym.JPG

Digital Signature (DS): Before I mention DS, let me define hashing. Hashing is a one way mathematical function which generates a standard size one way hash also called check sum. This is encrypted using the private key of the party to generate a digital signature.

DS.JPG

Role of Claims based Authentication in Federated Security

In my last blog I discussed Claims Based Authentication details in comparison with Roles based Authentication. In the next couple of blogs including this, I will discuss more about the role of Claims based Authentication in building a Single Sign On Solution/Federated Security in an organization or even across organizations

Before we get into the details of this, I would like to briefly touch upon the concepts of Federated Authentication and why it is so important.

One of the biggest challenges the organizations have today is the fact that Authentication in part and parcel of the Application and each Application can have its own way of storing credentials and authenticating users. This not only adds maintenance overheads to the maintenance folks, but also for the users who access these application as they will have to remember the credentials of all the applications they access. The issue will have a multiplier effect if the organization has applications on different platforms.

The solution that naturally evolved for this problem is to abstract out the Authentication Mechanism out of the Application and leave only the Authorization related stuff to the Application. Hence the end user is always directed to a central authority for Authentication and goes to the Application with the tokens issues by the authority to the end application. In the Microsoft world there are already a couple of solutions which evolved and failed to make a foot print. Passport is one of them which failed for the simple reason that nobody was ready to trust MS as the authority for storing all the credentials. Similarly WCS (Windows Card Space) evolved as part of the .Net 3.0 where in any party can act as Authority. But the issue with this is that all the parties involved will need to understand WCS. The new solution which is currently in the process of evolution is Zermatt which can take in any form of credentials and build token accordingly.

In the next blog we will see some of the basics of cryptography which plays an important role in understanding Zermatt, the new Single Sign On Solution which is in Betas today.

Interesting installation experience on 64 bit machine

The other day a team approached me stating that they had some issues in running and accessing a .net application on their newely configured Win2K3 64 bit dual core server. They were getting some sort of access denied when they moved their app from 32 bit to 64 bit. I told them that just by moving to 64 bit can't result in such issue and asked them to cross check and install .net 2.0 framework for 64 bit.

They had not installed it but soon reverted with another error while trying to do the installation - "Error creating process <C:\Docume~1\user\local settings\temp\1\IXP000.TMP\Install.exe>. Reason: C:\SYSROOT\system32\advpack.dll". I then refered them to this forum thread. 

The team came back with another interesting error that said - "The image file c:\netfx64\install.exe is valid, but is for a machine type other than current machine.". The message seemed to hint that this wasn't a 64 bit machine, but the team confirmed that indeed it was.

So I asked them to verify if they were using a 64 bit OS by pointing to this support article, and interestingly it turns out that they were actually working with a 64 bit machine but with a 32 bit OS setup on it. If you read the support article you will realize that there is a minor difference in the way the System details are shown. In a 32 bit system it reads Microsoft Windows Server 2003 Enterprise Edition, while in a 64 bit system it reads Microsoft Windows Server 2003 Enterprise x64 Edition.

I am waiting for the team to install teh 64 bit OS and then get back to me. In the meantime I thought to share this to highlight that be careful of what OS you are really running on your 64 bit system to avoid unpleasant surprises.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter