SharePoint 2010: Reasons to use the new UI

December 16, 2011 16:00

There are a lot of reasons to upgrade from SharePoint 2007 to SharePoint 2010. There are also a lot of reasons to upgrade to the new 2010 look and feel. But it’s not a requirement, and, in fact, can potentially add a lot of work to your migration effort.

In order to justify this extra work to a client, I’ve compiled a list of advantages the new 2010 UI gives one over sticking with the old SP2007 look and feel. Most items come from posts listed in my SharePoint 2007 to SharePoint 2010 Upgrade Resources post.

Here’s the list:

  • explicit use of strict DOCTYPE provides better standards compliance, more consistent look and feel across SharePoint pages, and better consistency and support from a cross-browser perspective
  • access to the new ribbon UI
  • better general ease of use through the ribbon, menus, dialogs
  • aligns better with current Office look and feel
  • better use of modern CSS/HTML tags (uses div tag for layout vs. tables, for ex.) resulting in faster rendering and more maintainable pages/sites
  • if not using the new 2010 interface, users will not have access to the ribbon, in-place editing of Wiki pages, interactive calendars, cannot define list relationships
  • new sites created after the 2007->2010 upgrade automatically default to the new 2010 interface (requiring manual change to the old look and feel each time)
  • fully XHTML compliant WCAG 2.0 AA level accessibility (for the impaired)
  • AJAX/Web 2.0 enhancements greatly reduce page refreshes
  • in-place page editing

I don’t doubt there are many more reasons, so consider this list preliminary or something to build on.


SharePoint 2007 to SharePoint 2010 Upgrade Resources

December 14, 2011 13:51

I’m currently involved in a project whose purpose is to upgrade an existing SharePoint 2007 server farm to SharePoint 2010. In order to help facilitate my part of the project, I’m going to use this post to document the relevant resources. While I’m interested in the process from start to finish, I’m only tasked with performing the Visual Upgrade and porting some Silverlight applications and relevant other pieces to the new environment. That isn’t going to stop me from learning about the other steps, though. I’ll update as I find new things.

Here’s the links.

General

Visual Upgrade

Master Pages

Themes

CSS 

Browser Compatibility

(Believe it or not, but DOCTYPE/IE8 compatibility comes into play b/c the client has a HUGE installed base of IE6 that is just now being upgraded to IE8 (no, not 9). Compatibility with IE8 is one of the requirements of the project.)


Silverlight class library not included in .XAP

July 10, 2011 15:51

This is something I'm sure I ran into before, but it still bit me the other day. Hopefully by writing this down here it won't get me again.

The problem is this: A Silverlight class library whose name ends with ".Resources" is not included in the Silverlight .XAP file.

".Resources" is a reserved naming convention (I guess) that shouldn't be used. The solution to including such DLL's in the .XAP file is to rename it so it ends with something like ".SharedResources.dll".

Short post. Odd problem. Easy solution.

[ Follow me on Twitter ]


A basic Silverlight project using the MVVM design pattern

May 20, 2011 08:07

I've been immersing myself in the Model-View-ViewModel (MVVM) design pattern of late. The pattern derives from Model-View-Presenter (MVP), which in turn has its roots in the Model-View-Controller (MVC) pattern. MVVM takes MVP one step further by gearing itself specifically towards WPF/Silverlight style development. While both WPF and Silverlight have built-in support for implementing MVVM (commanding, bindings, behaviors via the Expression Blend SDK), they do so with varying depth, and, even still, both fall short in terms of providing comprehensive support. Fortunately, a wide array of MVVM frameworks have cropped up to fill in these holes.

In this post I wanted to go through the motions of setting up a skeleton Silverlight project that utilizes MVVM. The application doesn't do much (it displays a random number in response to user input), but it does demonstrate some of the basic facilities we can use to implement the MVVM pattern, namely commanding and binding. One of the primary goals of MVVM is to remove the (often tight) coupling between the presentation layer (XAML) and the business logic (code-behind). Some argue that the pattern is overrated; we're simply removing logic from the code-behind and putting it into the ViewModel. This is true to some extent. But if you create a true separation between your UI and logic, and you take full advantage of the platform's support for MVVM, ultimately you'll find yourself writing less code. That's a good thing.

Much of what I show below is encapsulated in the various MVVM frameworks. I'm ignoring those for now because I want to establish a deeper understanding of the implementation mechanics. Moving forward, I will most certainly be adopting one of the frameworks.

Now, on to the code…

The Silverlight MVVM Project

1. Create a new Silverlight project

Standard stuff. Create a new Silverlight project, giving it a host web site. I called mine "MVVMBase".

2. Add three new folders to the Silverlight project

imageThe three folders are:

  1. MVVMFramework
  2. ViewModels
  3. Views

3. In the MVVMFramework folder, add support classes

These are the classes that any of the MVVM frameworks will supply for you. Even if you choose to not use one of the frameworks and roll your own, you'll likely want to place these objects in their own reusable class library since any MVVM project will make use of them. As noted above, I'm rolling my own here simply as a learning exercise.

Here are the classes. There are three of them.

a. Observable

When we define our own ViewModel classes, it is necessary that those objects derive from INotifyPropertyChanged because we'll be using the class in binding operations. Normally, you might create a ViewModelBase class, derive it from INotifyPropertyChanged, and you're done.  It's been suggested by some, however, to separate out INotifyPropertyChanged functionality from the base ViewModel class since there are instances other than when defining a ViewModel where you might want to derive from INotifyPropertyChanged. That's what I've done here. Observable is defined as:

   1: namespace MVVMBase.MVVMFramework
   2: {
   3:     using System.ComponentModel;
   4:     using System.Windows;
   5:  
   6:     public class Observable : INotifyPropertyChanged
   7:     {
   8:         public event PropertyChangedEventHandler PropertyChanged;
   9:  
  10:         protected void NotifyPropertyChanged (string propertyName)
  11:         {
  12:             if (PropertyChanged != null)
  13:             {
  14:                 PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
  15:             }
  16:         }
  17:     }
  18: }

b. ViewModelBase

It's convenient to have a ViewModel base class from which your own ViewModel classes can derive. For purposes of this post, mine doesn't do much except derive from Observable:

   1: namespace MVVMBase.MVVMFramework
   2: {
   3:     public class ViewModelBase : Observable
   4:     {
   5:     }
   6: }

c. RelayCommand

WPF introduced something called Commanding, which allows you to bind a user event (like a button click) to execution logic where the binding is done in XAML. User-defined commands are derived from ICommand; you need to have one defined per command event. Of course, if you define a new ICommand for each and every command, you'll quickly have a lot of repetitive code. Fortunately, there's a better way.

RelayCommand (alternatively named DelegateCommand or ViewModelCommand by others) is a generic class that derives from ICommand. It takes as parameters an Action and a Predicate, which define ICommand's Execute and CanExecute methods which RelayCommand must implement.

Here's the code:

   1: namespace MVVMBase.MVVMFramework
   2: {
   3:     using System;
   4:     using System.Windows.Input;
   5:  
   6:     public class RelayCommand : ICommand
   7:     {
   8:         private readonly Action<object> _executeAction;
   9:  
  10:         private readonly Predicate<object> _canExecute;
  11:  
  12:         public RelayCommand (Action<object> executeAction, Predicate<object> canExecute)
  13:         {
  14:             if (executeAction == null)
  15:             {
  16:                 throw new ArgumentNullException ("executeAction");
  17:             }
  18:  
  19:             _executeAction = executeAction;
  20:             _canExecute = canExecute;
  21:         }
  22:  
  23:         public event EventHandler CanExecuteChanged;
  24:  
  25:         public void OnCanExecuteChanged ()
  26:         {
  27:             if (CanExecuteChanged != null)
  28:             {
  29:                 CanExecuteChanged (this, EventArgs.Empty);
  30:             }
  31:         }
  32:  
  33:         /// <summary>
  34:         /// Defines the method that determines whether the command can execute in its current state.
  35:         /// </summary>
  36:         /// <returns>True if this command can be executed; otherwise, false.</returns>
  37:         /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
  38:         public bool CanExecute (object parameter)
  39:         {
  40:             return _canExecute == null || _canExecute (parameter);
  41:         }
  42:  
  43:         /// <summary>
  44:         /// Defines the method to be called when the command is invoked.
  45:         /// </summary>
  46:         /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
  47:         public void Execute (object parameter)
  48:         {
  49:             _executeAction (parameter);
  50:         }
  51:     }
  52: }

4. In the ViewModels folder, add a new class called "MainPageViewModel"

This is our ViewModel, derived from ViewModelBase, which contains the business logic for updating our View. Note that the ViewModel doesn't update the View directly. Instead, it updates properties that have been bound to the View in the View's XAML.

   1: namespace MVVMBase.ViewModels
   2: {
   3:     using MVVMBase.MVVMFramework;
   4:  
   5:     using RandomNumber;
   6:  
   7:     public class MainPageViewModel : ViewModelBase
   8:     {
   9:         private IGenerateNumber _generateNumber;
  10:  
  11:         private string _number;
  12:  
  13:         public MainPageViewModel (IGenerateNumber generateNumber)
  14:         {
  15:             _generateNumber = generateNumber;
  16:  
  17:             GetNumberCommand = new RelayCommand (GetNumber, CanGetNumber);
  18:         }
  19:  
  20:         public RelayCommand GetNumberCommand { get; private set; }
  21:  
  22:         public string Number
  23:         {
  24:             get
  25:             {
  26:                 return _number;
  27:             }
  28:  
  29:             private set
  30:             {
  31:                 if (value == _number)
  32:                     return;
  33:  
  34:                 _number = value;
  35:  
  36:                 NotifyPropertyChanged ("Number");
  37:             }
  38:         }
  39:  
  40:         private void GetNumber (object parameter)
  41:         {
  42:             Number = _generateNumber.GetRandomNumber ().ToString ();
  43:         }
  44:  
  45:         private bool CanGetNumber (object parameter)
  46:         {
  47:             return true;
  48:         }
  49:     }
  50: }

The constructor takes an interface to GenerateNumber, which is just a class library whose code is included in the download (see below). This service class generates a random number and returns it to the caller via the GetRandomNumber method.

GetNumber and CanGetNumber correspond to the RelayCommand's Action and Predicate delegates. ICommand gives us the ability to turn off a feature via a CanExecute method and to execute some logic in response to a command via a Execute method. That's the role these two delegates play. In CanGetNumber I simply return 'true'; in a real application you might have logic here that actually checks conditions and then possibly returns false if you do not want the command to execute. GetNumber runs if and when CanExecute evaluates to 'true'. Here it initializes the POCO property Number with a new random number. See the discussion beneath the View code for what's going on behind the scenes.

5. In the Views folder, copy over and rename MainPage.xaml/.cs

MainPage.xaml/.cs was created when you created the Silverlight project. Rename it to MainPageView.xaml/.cs and copy it into the Views folder (you don't have to rename it, but I do just for naming consistency; remember to rename the class, too).

First, let's look at the codebehind:

   1: namespace MVVMBase.Views
   2: {
   3:     using System.Windows.Controls;
   4:  
   5:     public partial class MainPageView : UserControl
   6:     {
   7:         public MainPageView ()
   8:         {
   9:             InitializeComponent ();
  10:         }
  11:     }
  12: }

As we intended, it pretty much contains nothing. This is as it should be when implementing the MVVM pattern, though note that achieving this ideal while easy in a small project like this one, can be very difficult and almost counter-productive in a real-world, complex application.

Next, take a look at the MainPageView.xaml file:

   1: <UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="MVVMBase.Views.MainPageView"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:     mc:Ignorable="d"
   7:     d:DesignHeight="200" d:DesignWidth="150">
   8:  
   9:     <StackPanel x:Name="LayoutRoot" Orientation="Vertical" Background="White" VerticalAlignment="Center">
  10:         <sdk:Label Content="{Binding Number}" Height="30" Width="100" Background="AliceBlue" Margin="10" />
  11:         <Button Content="Get Number" Height="30" Width="100" Margin="10" Command="{Binding GetNumberCommand}" />
  12:     </StackPanel>
  13: </UserControl>

The important stuff is on lines 10-11.

On Line 10, we define a Label whose Content is bound to a property called "Number". If you go back and look at the ViewModel, you'll see I defined a POCO property there that corresponds to this binding. The magic is the call to NotifyPropertyChanged, which notifies the binding framework that this property's value has changed. This in turn triggers an update to our UI because of the Binding we set up.

On Line 11, we declare a Button whose Command property is bound to something called "GetNumberCommand". Again, looking back at MainPageViewModel, you'll see a RelayCommand that corresponds to this binding.

6. Connect the View to the ViewModel

At this point we have all the infrastructure in place for a basic Silverlight MVVM application. But we still need to connect the View to the ViewModel. There are several philosophies out there on how best to do this. The basic options are these (Pete Brown touches on these approaches in his book, Silverlight 4 in Action):

1.) The code owns the ViewModel

In this approach you instantiate the ViewModel in the View's code-behind and assign it to the View's DataContext. While straightforward, this is not a recommended approach mostly because you've created a situation where the View cannot be used without also pulling the ViewModel along with it.

2.) The markup owns the ViewModel

This is essentially the same thing as the previous approach except in this case you declare the ViewModel in the View's XAML. Again, while relatively straightforward, you're creating a tightly bound relationship between the View and the ViewModel. This isn't necessarily a bad thing; in MVVM, a View is going to have a ViewModel, right? The truth of the matter is that either this approach or the previous one works perfectly fine. But option #3 has the added benefit of additional flexibility.

3.) The ViewModel is provided externally

In this approach the ViewModel is instantiated externally from the View and the two are bound together outside of either the View or the ViewModel. The benefit of this is a more loosely coupled arrangement, enhanced testability, and the ability to inject a different ViewModel for a given View rather than just the default. This is the approach I took.

In App.xaml.cs, I added the following code to the Application_Startup event:

   1: var mainPageViewModel = new MainPageViewModel (new GenerateNumber ());
   2: RootVisual = new MainPageView { DataContext = mainPageViewModel };

First, instantiate the ViewModel, passing in a GenerateNumber object via constructor injection (GenerateNumber is a service class that generates a random number; download the sample code to see it in all it's glory). Then, new up the View, setting it's DataContext to the ViewModel while also assigning the View itself to the application's RootVisual property.

It's setting the View's DataContext to the ViewModel class which essentially "glues" the ViewModel to the View. Also, if we wanted to use a different ViewModel with this View (or have several Views of this type each with a different ViewModel type), it's as simple as assigning each ViewModel type to the View's DataContext. You'd have some difficulty doing that with either of the other ownership approaches above.

Conclusion

This is more or less the bare minimum you must implement in order to adhere to the tenets of the MVVM pattern. I know I left some things out—MVVM frameworks and IoC Containers, for starters. These are platforms that make your life easier, but are not necessarily requirements of implementing the pattern. I know my next step, however, is to start evaluating the options available for each. Future posts should start to steer down those roads.

For more information on the MVVM pattern, take a look at my MVVM Reference post.

Download: MVVMBase.zip