Sunday, November 1, 2009

[2009.11.01] I spent a Week in PRISM

I had heard of Prism a while ago but never really investigated. When I did take a look at it about a month ago, in all honesty I felt overwhelmed. However, recently I had two interesting conversations and that prompted me to sit down and really get into Prism. I am glad I did as I have learned so much and it has shown me how much more I need to learn as well.

I suppose I am more of a code monkey rather than an architect or a designer. That will change from now on. There is no point in me banging out code when I am only aware of part of the system I am writing for. Going through the Prism docs touches on a lot of concepts that I was not familiar with in the first place. All in all, I know I can't get it all in one reading of the doc, but it's a start. I am much more comfortable with terms like Inversion of Control, Dependency Injection, Delegate Commands (well I got this from learning about Model-View-ViewModel), Event Aggregator, Modules, Bootstrapper, and some Design Patterns. Thus far, all I have done is the basic Hello World in Prism but I hope to do more in the near future. I would like to reference some additional resources that in my opinion, will supplement learning not just Prism, but design and architecture in general.

Prism Related

Supplemental Information

Monday, October 12, 2009

[2009.10.12] WPF: Change the color of the selected item in a ListBox control

A question that may come up at some point in the life of a WPF developer is: "How to change the color of the selected item in a ListBox control?". Going with just the word "selected" you would imagine that there is some property with that name that lives in ListBox. Close, but no dice.

There is, however, an IsSelected dependency property registered to the ListBoxItem control. Recall that ListBox implicitly wraps each of its items in a ListBoxItem, which is a ContentControl.

There are three ways that I know of that you can accomplish what you want - the first two requires knowledge of the template that makes up the ListBoxItem, whereas the last one, not so much. Let's look at the first two. Since the template is necessary, let's start by taking a look at the template for a ListBoxItem in Listing 1. I have removed the parts that are not relevant to the problem at hand so you are just seeing a slimmed down version of the real thing.
Note: I am using a tool called Show Me The Template! Feel free to use whatever works.

  1: <ControlTemplate TargetType="ListBoxItem" 
  2:                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3:                      xmlns:s="clr-namespace:System;assembly=mscorlib" 
  4:                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  5:     <Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
  6:                 Padding="{TemplateBinding Control.Padding}" 
  7:                 BorderBrush="{TemplateBinding Border.BorderBrush}" 
  8:                 Background="{TemplateBinding Panel.Background}" 
  9:                 Name="Bd" SnapsToDevicePixels="True">
 10:         <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
 11:                               ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" 
 12:                               ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" 
 13:                               HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
 14:                               VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
 15:                               SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
 16:     </Border>
 17:     <ControlTemplate.Triggers>
 18:         <Trigger Property="Selector.IsSelected">
 19:             <Setter TargetName="Bd" 
 20:                     Property="Panel.Background" 
 21:                     Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
 22:         </Trigger>
 23:     </ControlTemplate.Triggers>
 24: </ControlTemplate>

Listing 1. Slimmed down control template for a ListBoxItem

We are interested in Lines 18-21.

What we have in Line 18 is that when the IsSelected dependency property is triggered, it sets the Value of the Background property of the Border (with Name="Bd") to some predefined system level resource called HighLightBrushKey. Now we know that this refers to the ugly blue color we see when we select something from a ListBox.

At this stage you have a handle as to the structure of the template, and what property you need to modify to change the color. Now let's look at the ways in which we can go about accomplishing our little task.

[1] Override the HighLightBrushKey resource

This is by far the most painless method as it can be done in the Resources section of your Window or Page. Listing 2 shows how this is done using a LinearGradientBrush and the result is in Fig. 1. Pay special attention to the highlighted portion of the code in Line 7.


  1: <Window x:Class="WpfUnleashed01.Window1"
  2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:         xmlns:gundam="clr-namespace:WpfUnleashed01" 
  5:         Title="Changing ListBox color selection" Height="100" Width="300">
  6:     <Window.Resources>
  7:         <LinearGradientBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
  8:                              StartPoint="0,0" EndPoint="0,1">
  9:             <GradientStop Offset="0" Color="LightPink" />
 10:             <GradientStop Offset="0.3" Color="Red" />
 11:             <GradientStop Offset="0.7" Color="Red" />
 12:             <GradientStop Offset="0.9" Color="LightPink" />
 13:         </LinearGradientBrush>
 14:     </Window.Resources>
 15:     <StackPanel>
 16:         <ListBox>
 17:             <TextBlock Text="Using a LinearGradientBrush" />
 18:             <TextBlock Text="to change the color of" />
 19:             <TextBlock Text="the ListBox selected item" />
 20:         </ListBox>
 21:     </StackPanel>
 22: </Window>

Listing 2. Overriding a predefined resource


[2009.10.12].01.ListBox.01
Fig. 1. Using the override method

Basically that is all there is to it - a super quick, easy way to change the selection color!

[2] Modifying the ControlTemplate of ListBoxItem

This method goes a bit deeper as it actually tweaks the default template that is used to render the ListBoxItem. The code is pretty simple to follow as shown in Listing 3. The result is shown in Fig. 3.

  1: <Window x:Class="WpfUnleashed01.Window1"
  2:         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3:         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4:         xmlns:gundam="clr-namespace:WpfUnleashed01" 
  5:         Title="Template Editing" Height="100" Width="300">
  6:     <Window.Resources>
  7:         <!--style will automatically apply to ListBoxItems-->
  8:         <Style TargetType="{x:Type ListBoxItem}">
  9:             <!--modify the Template property-->
 10:             <Setter Property="Template">
 11:                 <Setter.Value>
 12:                     <ControlTemplate TargetType="{x:Type ListBoxItem}">
 13:                         <Border Name="Bd" Padding="2" SnapsToDevicePixels="True">
 14:                             <ContentPresenter />
 15:                         </Border> 
 16:                         <ControlTemplate.Triggers>
 17:                             <Trigger Property="IsSelected" Value="True">
 18:                                 <Setter TargetName="Bd" Property="Background" Value="Yellow" />
 19:                             </Trigger> 
 20:                         </ControlTemplate.Triggers>
 21:                     </ControlTemplate>
 22:                 </Setter.Value>
 23:             </Setter>
 24:         </Style>
 25:     </Window.Resources>
 26: 
 27:     <StackPanel>
 28:         <ListBox>
 29:             <TextBlock Text="Using a LinearGradientBrush" />
 30:             <TextBlock Text="to change the color of" />
 31:             <TextBlock Text="the ListBox selected item" />
 32:         </ListBox>
 33:     </StackPanel>
 34: </Window>

Listing 3. Just changing the Value property in Line 18 produces the desired results

[2009.10.12].02.ListBox.02
Fig. 2. Editing the ControlTemplate of the ListBoxItem

While this method was a bit more involved, it nonetheless did what you wanted to do, plus since you were editing the structure of the control's template, you also have the freedome to do a lot more.

[3] Using Expression Blend

The last method I will look at is using Expression Blend to make the necessary changes to the template to get the desired result. This may appeal to those who live in Blend most of their time and aren't too keen on coding in XAML.

After starting your new Blend project, select the ListBox control from the Asset Panel and put it where ever you want in your project. This is shown in Fig. 3. Once you are done making the tweaks you can delete the item. In addition, I have added two TextBlocks to the ListBox for testing purposes.

[2009.10.12].03.ListBox.in.blend.01
Fig. 3. Getting a ListBox from the Asset panel

With our ListBox in place, the next step is to edit the template. However, ListBox has several templates. If you right click on the ListBox either in the Objects and Timeline panel or on the object in the scene, you will see two menus giving you access to the templates you can modify as in Fig. 4.

[2009.10.12].04.ListBox.in.blend.02
Fig. 4. ListBox template options

The first choice is Edit Template, but we don't want this as this is the template for the ListBox. Recall from above that the property we are seeking lives in the ListBoxItem control, which ListBox uses to wrap items added to its collection. The second submenu, Edit Additional Templates has what we are looking for, namely the Edit Generated Item Container (ItemContainerStyle). Refer to Fig. 5.

[2009.10.12].05.ListBox.in.blend.03
Fig. 5. Editing the ListBoxItem's ControlTemplate via a Style

Actually, we are doing Step 2 in Blend! We are using a style to modify the underlying template to suit our needs. Either way, choose Edit a Copy..., name it and choose whether to place it in the Resource collection of the Window, Application or added to a ResourceDictionary. Feel free to choose any option, I will leave mine with the default settings as in Fig. 6.

[2009.10.12].06.ListBox.in.blend.04
Fig. 6. Adding a resource to your project in Blend

Now Blend switches to template editing mode as in Fig. 7.

[2009.10.12].07.ListBox.in.blend.05
Fig. 7. Template mode

What we are interested in is the Trigger menu and the IsSelected = true property setting. If you click on that (the red box in Fig. 7), you will notice two things:

  • The main work area has a red border with the heading:
    IsSelected = True trigger recording is on
  • The IsSelected = true now had a red "recording light" next to itself which basically says that whatever changes we make to this property will wipe out its old value and "record" our new choice (you still have to Save your project of course!)

Fig. 8 illustrates this.

[2009.10.12].08.ListBox.in.blend.06
Fig. 8. Changing the property trigger

The Properties when active heading is our focus, namely the second option:

Bd.Background = {x:Static SystemColors.HighlighBrushKey}. If you click this option while recording is on, the Properties tab shows the brush that is used to set the Background property of an element called Bd (it's actually a Border). Refer to Fig. 9 to see what I am talking about.

[2009.10.12].09.ListBox.in.blend.07
Fig. 9. Default brush used

Now you can simply turn off that brush, as in Fig. 10 and select your own.

[2009.10.12].10.ListBox.in.blend.08
Fig. 10. Turn off default brush

You are free to now add whatever you want. For example, I will add a simple RadialGradientBrush as my new Background property. See Fig. 11.

[2009.10.12].11.ListBox.in.blend.09
Fig. 11. Changing the default brush to a radial gradient

At this point you can click the "record light" button either in the main work area or under the Triggers tab to turn off recording. In addition, you can jump out of Template Editing Mode as shown in Fig. 12.

[2009.10.12].12.ListBox.in.blend.10
Fig. 12. Back to normal mode

Build and run the application to see the results in Fig. 13.

[2009.10.12].13.ListBox.in.blend.11
Fig. 13. Running to application - new selected color!

Now if you add another ListBox to your window and you want to add that style for the ListBoxItem, right click on the ListBox and follow the highlights indicated in Fig. 14.

[2009.10.12].14.ListBox.in.blend.12
Fig. 14. Adding the style to another ListBox

Have fun, happy coding (or not).

Sunday, October 11, 2009

[2009.10.11] JAOO 2009: An Introduction to F# by Don Syme

JAOO 2009: An Introduction to F# by Don Syme

Abstract:
F# is a succinct and expressive typed functional programming language for the .NET platform, and Microsoft will be supporting F# as a first class language in Visual Studio 2010. We'll take a look at what you need to know to start having fun with F#, and how to use it productively. We'll also look at some sample applications of F# and functional programming and cover aspects of parallel, reactive and asynchronous programming with F#.

Get the slides, code, etc from Don's Blog.

Thursday, October 1, 2009

[2009.10.01] Some Haskell features for F#

I learned a bit of both Haskell and F#. I love them both but I don't think I am going to get a job with either of them anytime soon! Either way, in my quest for knowledge, there were some features of Haskell I wished were in F#. Of course, I am sure the F# folks have their reasons why things are the way they are. Moving on...

[1] Function signature and definition

In Haskell, you can simply write down your function definition and follow that with your implementation as shown in Line 1

  1: fibonacci :: Int -> Int
  2: fibonacci 0 = 0
  3: fibonacci 1 = 1
  4: fibonacci n = fibonacci(n-1) + fibonacci(n-2)

In F# however, you cannot add the function definition at the start of the function implementation. Instead, you need to add it to a separate F# Signature File. As such the same definition in F# is:

  1: let rec fibonacci = function
  2:     | 0 -> 0
  3:     | 1 -> 1
  4:     | n -> fibonacci(n-1) + fibonacci(n-2)

[2] Haskell is more explicit about side effects

If you want to deal with Input/Output (IO) in Haskell, you have to be explicit about it. For instance, the definition of the putStrLn function is given as: String -> IO() This clearly states that this function has side effects and it is identified from the get go by the IO parameter. However, in F# you can write a function that has side effects but the function signature may not tell you that.

[3] Functions as equations

Looking back at the two fibonacci functions defined both in Haskell and F#, I can say I prefer the Haskell way of doing things. While the F# way is very close, I like the fact that in Haskell I can set up function conditions as a set of equations. You cannot use the same function name more than once in F# as in Haskell.

This was just a short post based on some of my observations. With that said, it's time to get back into the F# game.

Monday, September 21, 2009

[2009.09.21] The Periodic Table in WPF using MVVM

When the idea of doing this project came to me, at first I thought I would do it the same way as I did my previous WPF Writing one. I am doing this to simply to put into practice some of the concepts I have learnt previously. But using the same methods would not really prove much - at least to me. Since then I have learned much more and as such I wanted to use newer/updated tools, technologies and concepts to build this application.

Download the Code!

Technologies and Concepts used in this project:

  • Visual Studio 2008 SP1 + .NET Framework 3.5 SP1
  • Microsoft Expression Blend 3 + Sketchflow
  • Model-View-ViewModel (MVVM)
  • Actions, Behaviors and Triggers
  • Visual State Manager
  • Data binding
  • User Controls
  • Styles
  • Templates

The Prototype

Before an application is written, it may be helpful to have a decent, working prototype to sort of pitch/sell the idea of the project. Expression Blend 3 SketchFlow is the tool for the job. It will let you do rapid prototyping and provide a means to provide feedback on the initial prototype. My design will not be very complicated as this particular application will not have a whole lot of navigational needs. Basically the main window will show each element, a mouse over will bring up a summary for the element and clicking the control representing the element will bring up a details pane. Again, not a ton of interaction.

First, let's take a look at what the main UI may look like with a little bit of interaction in Fig. 1. Basically each element will have an attached GoToStateAction which will vary the Opacity of the SummaryUserControl. The states will react to the MouseEnter and MouseLeave events of the control.

[2009.09.21].01.Sketchflow.main.ui
Fig. 1. SketchFlow of the Main UI

If the user wants detailed information on the particular element, then clicking the control that represents the element will navigate to a Details window as in Fig. 2.

[2009.09.21].02.Sketchflow.details.ui
Fig. 2. SketchFlow of the Details UI

Fig. 3 is the SketchFlow map of the overall project. Notice that the MainUI screen has the SummaryUserControl Component linked to it and the DetailsUI has the Details Component linked to itself. The MainUI screen is also linked to the DetailsUI and the DetailsUI is linked back to the MainUI. As such you can use the NavigateForwardAction and NavigateBackAction to move between the screens.

[2009.09.21].03.Sketchflow.map
Fig. 3. SketchFlow Map of the project

The Design and Implementation

Fig. 4 is the Class Diagram of the overall application. Based on that, I will talk about each subsection as necessary. Fig. 5 is the hierarchy of the project.

[2009.09.21].04.PeriodicTable.ClassDiagram.01
Fig. 4. Class Diagram

[2009.09.21].05.Project.hierarchy
Fig. 5. Project Hierarchy

Given that my prototype passed and I have all the feedback necessary, then I would want to design next. This is where I would want to put some patterns and industry practices into play. I will use the Model-View-ViewModel pattern here, which I feel is appropriate for an application of this scale. Also, I want to use it to better acquaint myself with the pattern.

Model

The raw data would be an XML file that I have made up using the properties for the particular element. Since I have not used a lot of LINQ or XML processing in .NET, instead of using attributes and nested nodes, I have opted to use one level of nesting for all the nodes. Fig. 6 shows this.

[2009.09.21].06.model.01.xml.file
Fig. 6. XML Data File

The MVVM pattern completely separates the data from the rest of the application, so in order to expose the XML data, I have created a public class, ElementModel.cs whose sole purpose is to expose the data (nodes) of the XML data file as a set of public properties which can then be manipulated and data bound to. All this class does is declare a set of properties which mirror the data from the XML file. It supplies a single constructor that takes all these parameters in to create an instance of the class. In addition, there is a helper class called ElementModelFileLoader.cs which provides a single method that returns a List of ElementModel by using LINQ to load, parse and create the list. The List<ElementModel> can then be referenced by the ViewModel sections to be interacted with.

View

The MVVM kit will automatically create a MainView.xaml for a MVVM application. I will keep that view and add user controls and additional views as necessary. So the MainView will contain several ElementUserControl which will make up the periodic table. In addition, I have a second window called DetailsView.xaml which is loaded and displayed if the user clicks on an ElementUserControl. This window holds a DetailsUserControl.xaml. Both of these user controls use Data Binding to populate the necessary TextBlock fields that make them up.

Since I am on the topic, I have used Actions and Behaviors, some new features of Blend 3, as well as the Visual State Manager, to quickly add interactivity to my user controls. An Action is just a piece of code that runs after being triggered. For instance, Blend has a GoToStateAction which as its name implies, transitions the element it is attached to go to a specified state as defined by the VSM. For example, I have defined some states that will make the Border surrounding the ElementUserControl changes its Opacity property by listening for MouseEnter and MouseLeave events. See Fig. 7.

[2009.09.21].07.actions.in.blend3
Fig. 7. Using Actions in Blend 3

I have an earlier blog post that has more information on Actions and Behaviors.

According to the MVVM pattern, a View will have a reference to its corresponding ViewModel, which it can set to be its data context ( myView.DataContext = myViewModelInstance ). In this way, bindings defined in the View, which references properties exposed by the ViewModel will be resolved. I will go into more detail when I discuss the ViewModels. Fig. 8 shows a representation of the MainView and Fig. 9 that of the DetailsView.

[2009.09.21].08.mainview
Fig. 8. The MainView view of the application

[2009.09.21].09.detailsview
Fig. 9. The DetailsView view of the application

ViewModel

Ideally, each of the Views listed above would have their own corresponding ViewModel file, which would be pure C# as shown in Fig. 5 above. Actually, I did not need a separate ViewModel for the DetailsView, but I added one one to bind to commands that is relevant to the DetailsView only. However, as of this writing, it is a redundant class as its functionality was not what I expected. I hope to fix it in the future.

Since most of the action happens in the MainViewModel, I will talk about that. Since this is what the View is bound to, it is the ViewModel that exposes properties and commands for the view to bind to. In this case, the MainViewModel wraps each List<ElementModel> into an ObservableCollection<ElementModelViewModel>. This may seem a bit confusion but the ElementModelViewModel is actually the ViewModel which represents the ElementModel. If you recall, the ElementModel was the class that exposes the data in the XML file. However, in the ElementModelViewModel you can choose exactly what properties you want to expose to your Views. For example, ElementModel could expose 10 properties, but out of those 10, the ElementModelViewModel class chooses only exposes 5 to its View. Since the View cannot "see" the model, then all it knows about is the 5 properties it is allowed to bind to.

In addition to custom object properties, the ViewModel also exposes Commands that the View can bind to. So in summary, the MainViewModel class exposes the properties of the Model as a collection and commands.

Since the code has lots of comments you can easily understand what is happening. A good deal of plumbing magic takes place in the OnStartup() event handler of the App code behind file - App.xaml.cs file. This is shown in Listing 1.

  1: using System.Collections.ObjectModel;
  2: using System.Windows;
  3: using PeriodicTable.ViewModels;
  4: using PeriodicTable.Views;
  5: 
  6: namespace PeriodicTable
  7: {
  8:     /// <summary>
  9:     /// Interaction logic for App.xaml
 10:     /// </summary>
 11:     public partial class App : Application
 12:     {
 13:         MainView view;
 14:         MainViewModel mainViewModel;
 15:         DetailsView detailsView;
 16:         DetailsViewViewModel detailsViewModel;
 17: 
 18:         public App()
 19:         {
 20:             view = new MainView();
 21:             mainViewModel = new MainViewModel();
 22: 
 23:             detailsView = new DetailsView();
 24:             detailsViewModel = new DetailsViewViewModel();
 25: 
 26:         }
 27:         private void OnStartup(object sender, StartupEventArgs e)
 28:         {
 29:             // Call the Load method in the MainViewModel call
 30:             // This finds the XML file, loads the data, create a CLR object
 31:             //  to represent the XML data, create a collection of these 
 32:             //  objects and create a public property to expose this collection
 33:             mainViewModel.LoadElementsFromFile(@"Models\periodicTable.xml");
 34: 
 35:             ObservableCollection<ElementModelViewModel> col = mainViewModel.ElementCollection;
 36: 
 37:             // Since my user controls for the elements are not in a container
 38:             //  that knows how to bind each element as an item in the container
 39:             //  I have to manually iterate and set each control's data context property
 40:             //  (ex: ListBox - if you set the ItemsSource to the property exposing
 41:             //       the ObservableCollection, then each ListBoxItem is bound to
 42:             //       one item in the collection)
 43:             for (int i = 0; i < col.Count; i++)
 44:             {
 45:                 // use data binding to populate each user control
 46:                 ElementUserControl euc = (ElementUserControl)view.elementsGrid.Children[i];
 47:                 if (euc.Name == col[i].ElementName)
 48:                 {
 49:                     euc.DataContext = col[i];
 50:                     euc.symbolText.Text = col[i].Symbol;
 51:                     euc.atomicNumberText.Text = col[i].AtomicNumber;
 52: 
 53:                     // respond to these events to do some bindings
 54:                     euc.MouseEnter += new System.Windows.Input.MouseEventHandler(euc_MouseEnter);
 55:                     euc.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(euc_MouseLeftButtonDown);
 56:                 }
 57:             }
 58: 
 59:             // set a higer level datacontext to get acccess to the Commands
 60:             // defined in the ViewModel
 61:             view.DataContext = mainViewModel;
 62: 
 63:             view.Show(); // show the main window
 64:         }
 65: 
 66:         // Handler for the MouseLeftButtonDown event which will show the DetailsView window
 67:         void euc_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
 68:         {
 69:             //detailsView.LayoutRoot.DataContext = (sender as ElementUserControl).DataContext;
 70:             detailsView.Owner = view;
 71:             if (detailsView == null)
 72:             {
 73:                 detailsView = new DetailsView();
 74:                 detailsView.Show();
 75:             }
 76:             else
 77:             {
 78:                 detailsView.Show();
 79:             }
 80:         }
 81: 
 82:         // Handler for the MouseEnter event which set the data context of each
 83:         //  both the Summary and Detail UserControls
 84:         void euc_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
 85:         {
 86:             view.summaryUC.DataContext = (sender as ElementUserControl).DataContext;
 87:             detailsView.LayoutRoot.DataContext = (sender as ElementUserControl).DataContext;
 88:         }
 89:     }
 90: }

Listing 1: App code behind

In the constructor of the App class, instances of both the MainView and the DetailsView views are created and instantiated. Within the OnStartup() handler, the XML file is loaded, the collection of data is created and each ElementUserControl in the MainView has some of its compositional control values bound to properties of the objects in the collection of data items (Lines 43-51). The code is pretty much self explanatory.

Fig. 10 shows the overall operation of the application.

[2009.09.21].10.overall.app
Fig. 10. The app in action
Current unresolved problems

The first problem I ran into was having a command execute when a certain event fires. I got around this problem using the CommandBehavior from Tor Langlo. The problem after was that I wanted a CloseCommand that the DetailsView can bind to, which will cause the details window to close. Even though the command works when I tested it out in the main window, it does not work here.

The second problem was even though the CloseCommand did not work, I resolved to use an event in the DetailsView code behind (yes, I know) to close the window. However, once the window was closed, I could not reopen it. I found a workaround by responding to the Closing event and injecting a Hide() method on the application dispatcher queue. Basically, instead of closing the details window, I merely hide it until it is requested to be shown again. I am not satisfied with this but it will do for now.

Finally, this project was done with the idea that it can be extended. The fact is, I do not have any desire to create a complete XML file to represent periodic table elements. Thus far all I have are two elements. The infrastructure is there is anyone wants to add to the XML file. An idea to remedy this would be to add a window that will allow a user to add to the XML file. Maybe in the future I will add this.

Download the Code!

Monday, September 14, 2009

[2009.09.14] WPF Actions and Behaviors: A closer look

There are two assemblies that house the classes necessary for extending interactivity in WPF. They are:

  • System.Windows.Interactivity.dll
  • Microsoft.Expression.Interactions.dll

I am using Windows Server 2008 Enterprise and for my setup, these assemblies are found in:
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend 3\Interactivity\Libraries. In the Libraries folder, you will find two other folders: WPF and Silverlight and each has two assemblies listed above to be used for the particular project type. I mentioned these files now because you need to do an "Add Reference" to them in order to create your own behaviors, actions or triggers.

In the System.Windows.Interactivity.dll, you will find a set of classes which you will inherit from depending on what you are trying to do. Here are some of the classes you can inherit from if you want to create:

  1. Actions + Behavior: (with an associated trigger)
    TriggerAction,
    TriggerAction<T>,
    TargetedTriggerAction,
    TargetedTriggerAction<T>
  2. Behavior: (without an associated trigger)
    Behavior,
    Behavior<T>
  3. Triggers:
    TriggerBase,
    TriggerBase<T>

All of these classes share a common property in that they all inherit from Animatable. As such, they exhibit a similar behavioral pattern as related to each other.

The above list is a bit confusing when you first look at it but basically you can create a Behavior by inheriting from the exact same classes as you would use when creating an Action. The things that really separates them (and sometimes doesn't) boils down to which of the virtual methods defined in the base class you override and implement.

To create just an Action, you derive from all the classes listed in 1 above but you need to only override the Invoke() method. Here is where you write code to do what you want when the Action is invoked.

To create a Behavior that uses Triggers, you can derive from classes both in 1 and 2 but instead you override the OnAttached() and OnDetaching() methods. However, depending on what your behavior entails, you may choose to override Invoke() as well. For a Behavior without any Triggers, derive from classes in 2 and override the methods mentioned above. Of course with this approach, once you attach the behavior, it will do do what the code written tells it to do without need for triggers. Note that you can also use Commands with Behaviors.

Blend 3 and Visual Studio 2008 SP1 comes with templates to get you started in creating actions, behaviors and triggers as in Fig. 1 and 2.

[2009.09.13].01.Blend.new.item
Fig. 1. Blend 3 interactivity templates

[2009.09.13].02.VS.new.item
Fig. 2. Visual Studio interactivity templates

Each time you add one of these items to your project, a skeleton implementation is created. For example, if you are creating a new Behavior, your class will already derive from Behavior<T>, and OnAttached() and OnDetaching() methods will be overridden. In addition, each comes commented to point you in the right direction as shown in Listing 1.

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Text;
  4: using System.Windows;
  5: using System.Windows.Controls;
  6: using System.Windows.Data;
  7: using System.Windows.Documents;
  8: using System.Windows.Input;
  9: using System.Windows.Media;
 10: using System.Windows.Media.Imaging;
 11: using System.Windows.Shapes;
 12: using System.Windows.Interactivity;
 13: //using Microsoft.Expression.Interactivity.Core;
 14: 
 15: namespace ActionBehaviorBlogDemo01
 16: {
 17:   public class Behavior2 : Behavior<DependencyObject>
 18:   {
 19:     public Behavior2()
 20:     {
 21:       // Insert code required on object creation below this point.
 22: 
 23:       //
 24:       // The line of code below sets up the relationship between the command and the function
 25:       // to call. Uncomment the below line and add a reference to Microsoft.Expression.Interactions
 26:       // if you choose to use the commented out version of MyFunction and MyCommand instead of
 27:       // creating your own implementation.
 28:       //
 29:       // The documentation will provide you with an example of a simple command implementation
 30:       // you can use instead of using ActionCommand and referencing the Interactions assembly.
 31:       //
 32:       //this.MyCommand = new ActionCommand(this.MyFunction);
 33:     }
 34: 
 35:     protected override void OnAttached()
 36:     {
 37:       base.OnAttached();
 38: 
 39:       // Insert code that you would want run when the Behavior is attached to an object.
 40:     }
 41: 
 42:     protected override void OnDetaching()
 43:     {
 44:       base.OnDetaching();
 45: 
 46:       // Insert code that you would want run when the Behavior is removed from an object.
 47:     }
 48: 
 49:     /*
 50:     public ICommand MyCommand
 51:     
 52:       get;
 53:       private set;
 54:     }
 55:      
 56:     private void MyFunction()
 57:     {
 58:       // Insert code that defines what the behavior will do when invoked.
 59:     }
 60:     /*
 61:   }
 62: }

Listing 1: Generated template to implement a Behavior

Examples of Actions and Behaviors

In all the samples, I am basically running the same animation, which changes the Opacity of the targeted or associated element. The main areas to look at is the base classes being derived from in each case as well as the comments in each class.

Example 1: Action which derives from TriggerAction

  1: using System;
  2: using System.Windows;
  3: using System.Windows.Interactivity;
  4: using System.Windows.Media.Animation;
  5: 
  6: namespace ActionBehaviorBlogDemo02
  7: {
  8: 
  9:     /// <summary>
 10:     /// Class showing a simple action that can be invoked by a trigger
 11:     /// </summary>
 12:     // Change the type parameter to be a FrameworkElement to access
 13:     //  the AssociatedObject's Opacity property
 14:     public class OpacityAction : TriggerAction<FrameworkElement>
 15:     {
 16:         // variables to hold Storyboard and
 17:         //  DoubleAnimation objects
 18:         Storyboard myStoryboard = new Storyboard();
 19:         DoubleAnimation myDoubleAnimation = new DoubleAnimation();
 20:  
 21:         public OpacityAction(){ }
 22: 
 23:         protected override void Invoke(object o)
 24:         {
 25:             // Insert code that defines what the Action 
 26:             //  will do when triggered/invoked.
 27:             this.Animate();
 28:         }
 29: 
 30:         // method to be called by Invoke()
 31:         public void Animate()
 32:         {
 33:             // set up the animation properties 
 34:             myDoubleAnimation.To = 0.2;
 35:             myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
 36:             myDoubleAnimation.AutoReverse = true;
 37:             myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
 38: 
 39:             // the target of the animation is the AssociatedObject
 40:             //  i.e the object the Action is attached to
 41:             Storyboard.SetTarget(myDoubleAnimation, AssociatedObject);
 42:             // animate the Opacity property
 43:             Storyboard.SetTargetProperty(myDoubleAnimation,
 44:                 new PropertyPath(FrameworkElement.OpacityProperty));
 45:             myStoryboard.Children.Add(myDoubleAnimation);
 46:             myStoryboard.Begin();
 47:         }
 48:     }
 49: }

Listing 2: A simple Action

Example 2: Action which derives from TargetedTriggerAction

  1: using System;
  2: using System.Windows;
  3: using System.Windows.Interactivity;
  4: using System.Windows.Media.Animation;
  5: 
  6: namespace ActionBehaviorBlogDemo02
  7: {
  8: 
  9:     /// <summary>
 10:     /// Class used to set the target of the action other to the element it is attached to
 11:     /// </summary>
 12:     // If you want your Action to target elements other than its parent, extend your class
 13:     // from TargetedTriggerAction instead of from TriggerAction
 14:     public class OpacityTargetedTriggerAction : TargetedTriggerAction<FrameworkElement>
 15:     {
 16:         // variables to hold Storyboard and
 17:         //  DoubleAnimation objects
 18:         Storyboard myStoryboard = new Storyboard();
 19:         DoubleAnimation myDoubleAnimation = new DoubleAnimation();
 20:         public OpacityTargetedTriggerAction()
 21:         {
 22:             // Insert code required on object creation below this point.
 23:         }
 24: 
 25:         protected override void Invoke(object o)
 26:         {
 27:             if (Target == null)
 28:             {
 29:                 return;
 30:             }
 31: 
 32:             // Insert code that defines what the Action 
 33:             //  will do when triggered/invoked.
 34:             this.Animate();
 35:         }
 36: 
 37:         // method to be called by Invoke()
 38:         public void Animate()
 39:         {
 40:             // set up the animation properties 
 41:             myDoubleAnimation.To = 0.2;
 42:             myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
 43:             myDoubleAnimation.AutoReverse = true;
 44:             myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
 45: 
 46:             // The action is meant to be executed on the Target
 47:             //  element, which can be 
 48:             //  or another element. By using the Target property here,
 49:             //  both cases are covered.
 50:             Storyboard.SetTarget(myDoubleAnimation, base.Target);
 51:             // animate the Opacity property
 52:             Storyboard.SetTargetProperty(myDoubleAnimation,
 53:                 new PropertyPath(FrameworkElement.OpacityProperty));
 54:             myStoryboard.Children.Add(myDoubleAnimation);
 55:             myStoryboard.Begin();
 56:         }
 57:     }
 58: }

Listing 3: An Action that can execute on the attached object or on another Target

Example 3: A simple Behavior

  1: using System;
  2: using System.Windows;
  3: using System.Windows.Interactivity;
  4: using System.Windows.Media.Animation;
  5: 
  6: namespace ActionBehaviorBlogDemo02
  7: {
  8:     /// <summary>
  9:     /// Basic independent behavior
 10:     /// </summary>
 11:     public class OpacityTriggerlessBehavior : Behavior<FrameworkElement>
 12:     {
 13:         Storyboard myStoryboard = new Storyboard();
 14:         DoubleAnimation myDoubleAnimation = new DoubleAnimation();
 15:         public OpacityTriggerlessBehavior()
 16:         {
 17:         }
 18: 
 19:         protected override void OnAttached()
 20:         {
 21:             base.OnAttached();
 22: 
 23:             // Since this behavior depicts an animation,
 24:             //  the animation will run as soon as the app
 25:             //  is up and running
 26:             // Here, the behavior is doing something without
 27:             //  being asked/triggered
 28:             this.Animate();
 29:         }
 30: 
 31:         protected override void OnDetaching()
 32:         {
 33:             base.OnDetaching();
 34:         }
 35: 
 36:         public void Animate()
 37:         {
 38:             // set up the animation properties 
 39:             myDoubleAnimation.To = 0.2;
 40:             myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
 41:             myDoubleAnimation.AutoReverse = true;
 42:             myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
 43: 
 44:             // the target of the animation is the AssociatedObject
 45:             //  i.e the object the behavior is attached to
 46:             Storyboard.SetTarget(myDoubleAnimation, AssociatedObject);
 47:             // animate the Opacity property
 48:             Storyboard.SetTargetProperty(myDoubleAnimation,
 49:                 new PropertyPath(FrameworkElement.OpacityProperty));
 50:             myStoryboard.Children.Add(myDoubleAnimation);
 51:             myStoryboard.Begin();
 52:         }
 53:     }
 54: }

Listing 4: A simple Behavior

Example 4: A Behavior that can be triggered

  1: using System;
  2: using System.Windows;
  3: using System.Windows.Input;
  4: using System.Windows.Interactivity;
  5: using System.Windows.Media.Animation;
  6: 
  7: namespace ActionBehaviorBlogDemo02
  8: {
  9:     /// <summary>
 10:     /// Showing how behaviors can be infulenced by a trigger
 11:     /// </summary>
 12:     public class OpacityTriggeredBehavior : Behavior<FrameworkElement>
 13:     {
 14:         Storyboard myStoryboard = new Storyboard();
 15:         DoubleAnimation myDoubleAnimation = new DoubleAnimation();
 16:         public OpacityTriggeredBehavior()
 17:         {
 18: 
 19:             // set up the animation properties 
 20:             myDoubleAnimation.To = 0.2;
 21:             myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1));
 22:             myDoubleAnimation.AutoReverse = true;
 23:             myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
 24: 
 25:             // the target of the animation is the AssociatedObject
 26:             //  i.e the object the behavior is attached to
 27:             Storyboard.SetTargetProperty(myDoubleAnimation,
 28:                 new PropertyPath(FrameworkElement.OpacityProperty));
 29:             myStoryboard.Children.Add(myDoubleAnimation);
 30:         }
 31: 
 32: 
 33:         protected override void OnAttached()
 34:         {
 35:             base.OnAttached();
 36:             // respond to mouse events to control the behavior
 37:             this.AssociatedObject.MouseEnter += new MouseEventHandler(AssociatedObject_MouseEnter);
 38:             this.AssociatedObject.MouseLeave += new MouseEventHandler(AssociatedObject_MouseLeave);
 39:         }
 40:         protected override void OnDetaching()
 41:         {
 42:             base.OnDetaching();
 43:             this.AssociatedObject.MouseEnter -= new MouseEventHandler(AssociatedObject_MouseEnter);
 44:             this.AssociatedObject.MouseLeave -= new MouseEventHandler(AssociatedObject_MouseLeave);
 45:         }
 46: 
 47:         void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
 48:         {
 49:             FrameworkElement fe = sender as FrameworkElement;
 50:             Storyboard.SetTarget(myDoubleAnimation, fe);
 51:             myStoryboard.Begin();
 52:         }
 53:         void AssociatedObject_MouseLeave(object sender, MouseEventArgs e)
 54:         {
 55:             myStoryboard.Stop();
 56:         }
 57:     }
 58: }

Listing 5: Behavior with triggers

[2009.09.13].03.Sample.of.actions.and.behaviors

Fig. 3. Sample of actions and behaviors

Download the Code!




[2009.09.14] Introduction to WPF Actions and Behaviors

I noticed something called Behaviors in Blend 3 under the Asset panel and decided to take a look into it some more. It took quite a bit of reading the Expression Team blog posts to get a sense of what is going on with this new addition to WPF.

Triggers, Actions and Behaviors

Triggers and Actions are words you have probably heard if you are playing around with WPF. Behaviors basically builds on the that infrastructure to extend it to a nice, interesting level. Because the three concepts - triggers, actions and behaviors are closely related, it gets a bit confusing telling what is what. For the most part, triggers and actions are perhaps what you may most familiar with. For instance, when you fire the MouseEnter property on an element, its Background property changes.

You can think of triggers and actions as a stimulus/response or a cause/effect pair. Based on that analogy, let's try to expand that a bit. The trigger/action pairs is related by the statement:
when something happens, do something

A Trigger is the stimulus/cause that motivates something to happen. This is the "when something happens" part. From the example above, the trigger will be when the MouseEnter property changes.

An Action is the response/effect to a trigger. This is the "do something" part. Continuing from the above example, the action would be the changing of the element's Background property.
Note: When I say Action from now on I mean an Action/Trigger pair

A Behavior take this one step further. It has two types of functionality.
   [1] It can do something due to a trigger or
   [2] It can do something on its own

As you can see, a Behavior will let you write code that is both trigger dependent and trigger independent.

When I was first going through the literature of these concepts, I admit I was a bit confused. But here is the bottom line as I understand it:
Both an Action and a Behavior is a piece of reusable, modular piece of interactive code that can be attached to an element. The difference between the two is that an Action is always invoked/called/notified by a Trigger, whereas a Behavior can either be invoked independently of a trigger or it may be called using a trigger.

Therefore, while the action/trigger pair are pretty much inseparable, a Behavior is more loosely coupled. So with behaviors, you get all the pros of using triggers and actions as well as the ability to ditch the triggers completely if you want to.

Target and Source

There are two additional parts that makes these all work like a nice, well-oiled machine. When you drop an action(+ trigger - these naturally go together) or a behavior(+ trigger) onto an element, the element acts both as the Source and the Target of the action or behavior. Depending on what you are creating (a new Trigger, Action, or Behavior), you will have access to properties to change both of these. The SourceName property lets you change the source of the trigger from the element the action is attached to to something else. The TargetName property lets you change the target of the action other than what it is attached to. These will all make a bit more sense later as these two properties are visible as a result of deriving from certain base classes.

Attaching Behaviors and Actions in Blend 3

This could not be any easier. Blend 3 ships with a few stock behaviors and actions. You can get more from the Microsoft Expression Gallery. You can navigate to the Behaviors and Actions that comes with Blend 3 either using the new Assets tab as shown in Fig. 1 or going to the Assets panel as shown in Fig. 2.

[2009.09.12].01.Actions.and.behaviors.in.blend.assets.01
Fig. 1. Accessing Behaviors and Actions using Asset Tab

[2009.09.12].02.Actions.and.behaviors.in.blend.assets.02
Fig. 2. Accessing Behaviors and Actions using Asset Panel

All you have to do is to drag the Action or Behavior you want either onto the element on the artboard or on the Objects and Timeline panel as in Fig. 3. The Action or Behavior then becomes a child of the element it is attached to as in Fig. 4.

[2009.09.12].03.Drag.behavior.to.element
Fig. 3. Dragging a behavior onto an element

[2009.09.12].04.Behavior.child.of.element
Fig. 4. Attached behavior

An action or a behavior may expose properties that you can use to configure each item. These are displayed in the Properties tab as shown in Fig. 5 and 6.

[2009.09.12].05.Behavior.properties
Fig. 5. Properties for the MouseDragElementBehavior

[2009.09.12].06.Action.properties
Fig. 6. Properties for the GoToStateAction

Notice that the properties for the behavior in Fig. 5 does not have a trigger, so this is a type of trigger-independent behavior. Fig. 6 shows an action and the properties indicate several modifiable areas. Note particularly that in this Action you can change both the SourceName and TargetName properties, which essentially changes the Source and Target of the Action from the attached element (the Rectangle) to another element of your choice. Notice also that both of these properties have a little bullseye next to their modifiable textboxes. This is a super handy way of choosing a new Source or Target. Simply click the bullseye and point it to the element you want to set. For instance, in Fig. 7, you can set the Ellipse as the Target as shown.

[2009.09.12].07.Using.artboard.picker
Fig. 7. Setting the TargetName property using the Artboard element picker

Here is a nice little handy trick (thanks!) - if you have overlapping elements, to see the list of all the elements, hold done Ctrl, choose the Artboard picker, then Left Click on the topmost element and a new context menu pops up, allowing you to choose the element to apply the property to. This is in Fig. 8.

[2009.09.12].08.Applying.property.to.overlapping.elements
Fig. 8. Applying properties to overlapping elements

The final thing I would like to point out is that you can change the type of trigger that will be used to fire the action (or behavior if it supports triggers). Clicking the New button next to the TriggerType label will bring up a list of triggers you can set for the action or behavior. This is in Fig. 9 where the current trigger is an EventTrigger. Note that if you create your own triggers in a project, you can set them from this screen.

[2009.09.12].09.Trigger.types
Fig. 9. Changing the type of the trigger

I hope this post has provided an overview of what triggers, actions and behaviors are and how to use them. Next will be about the classes involved and how to write your own actions and behaviors.