FallbackValue, TargetNullValue & StringFormat in Silverlight 4

Silverlight 4 introduces some further databinding functionality including:

FallbackValue

If there is a problem with performing the binding, for example an incorrect path to a property value, the fallback value will be used in it's place. This allows some meaningful display, rather that the default behaviour of showing nothing.

TargetNullValue

Allows a value to be used if the bound property is null.

StringFormat

Allows formatting of the bound value using standard formatting expressions.

Example

The following is the output of the XAML below:

 

 

<Grid x:Name="LayoutRoot" Background="WhiteSmoke" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition Height="auto"></RowDefinition>
        <RowDefinition Height="auto"></RowDefinition>
    </Grid.RowDefinitions>

    <TextBlock TextWrapping="Wrap">Invalid binding path with FallbackValue set</TextBlock>
    <TextBlock Text="{Binding Path=badPath, FallbackValue='this is a fallback value'}" Grid.Column="1"></TextBlock>

    <TextBlock TextWrapping="Wrap" Grid.Row="1">Invalid binding path withOUT FallbackValue set</TextBlock>
    <TextBlock Text="{Binding Path=badPath}" Grid.Row="1" Grid.Column="1"></TextBlock>

    <TextBlock TextWrapping="Wrap" Grid.Row="2">Bound property = null with TargetNullValue set</TextBlock>
    <TextBlock Text="{Binding Path=AnIntProperty, TargetNullValue='The int is null'}" Grid.Column="1" Grid.Row="2"></TextBlock>

    <TextBlock TextWrapping="Wrap" Grid.Row="3">Bound property = null withOUT TargetNullValue set</TextBlock>
    <TextBlock Text="{Binding Path=AnIntProperty}" Grid.Column="1" Grid.Row="3"></TextBlock>

    <TextBlock TextWrapping="Wrap" Grid.Row="4">Bound property with StringFormat</TextBlock>
    <TextBlock Text="{Binding Path=AnotherIntProperty, StringFormat='Age is {0} years old.'}" Grid.Column="1" Grid.Row="4"></TextBlock>

    <TextBlock TextWrapping="Wrap" Grid.Row="5">Bound property withOUT StringFormat</TextBlock>
    <TextBlock Text="{Binding Path=AnotherIntProperty}" Grid.Column="1" Grid.Row="5"></TextBlock>

</Grid>

The DataContext is set to an instance of the following class:

public class TestData : DependencyObject
{
    public int? AnIntProperty
    {
        get { return (int?)GetValue(AnIntPropertyProperty); }
        set { SetValue(AnIntPropertyProperty, value); }
    }

    // Using a DependencyProperty as the backing store for AnIntProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AnIntPropertyProperty =
        DependencyProperty.Register("AnIntProperty", typeof(int?), typeof(TestData),
            new PropertyMetadata(0));


    public int AnotherIntProperty
    {
        get { return (int)GetValue(AnotherIntPropertyProperty); }
        set { SetValue(AnotherIntPropertyProperty, value); }
    }

    // Using a DependencyProperty as the backing store for AnotherIntProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AnotherIntPropertyProperty =
        DependencyProperty.Register("AnotherIntProperty", typeof(int), typeof(TestData), new PropertyMetadata(0));


    public TestData()
    {
        AnIntProperty = null;
        AnotherIntProperty = 44;
    }

}

SHARE:

Printing Support in Silverlight 4

Basic printing can be accomplished through the PrintDocument class. For example, to print the entire contents of the LayoutRoot grid:

private void btnSimplePrint_Click(object sender, RoutedEventArgs e)
{
    string docName = "Test SL4 Print";

    PrintDocument doc = new PrintDocument();

    doc.PrintPage += (s, args) =>
    {
        // print the entire contents of our page (i.e. the
        // outer grid called LayoutRoot)
        args.PageVisual = LayoutRoot;
    };

    doc.Print(docName); // automatically shows a print dialog box
}

Various properties are avaible on the PrintPageEventArgs that are passed to the PrintPage event handle ('args' in the above example); args.HasMorePages allows you to control multi-page printing and args.PrintableArea allows you to get the printable page area you have available to you (which will depend on the settings chosen in the print dialog box that is shown automatically for you.

It is up to the developer to handle more complex scenarios such as overflowing contents, knowing if there are more pages required, etc. In an enterprise situation other PDF-scentric options may be a better choice, especially if there are complex report layouts required, etc. For example, using iText.NET, FOP, or an enterprise solution such as Thunderhead, xPression, etc. 

SHARE:

C# 4.0 Optional Parameters

C# 4.0 introduces the concepts of Optional Parameters and the related Named Parameters language features. Essentially by giving parameters a default value, callers can omit values for those parameters. The example code below produces the following output:

 name: Peter age: 44 height: 200
NAME: PETER AGE: 44 YEARS HEIGHT: 200 CM
NAME: PETER AGE: 44 YEARS HEIGHT: 200 CM
NAME: PETER AGE: 44 YEARS HEIGHT: 200 CM
NAME: PETER AGE: 44 HEIGHT: 200

The code that produces this output:

class Program
{
    static void Main(string[] args)
    {
        // Supply all parameters explicity (passing false)
        Console.WriteLine(CreateString("Peter", 44, 200, false, false));

        // Supply all parameters explicity (passing true)
        Console.WriteLine(CreateString("Peter", 44, 200, true, true));

        // Supply only minimum required parameters,
        // the defaults (true) for useUpperCase & appendUnitText will be used
        Console.WriteLine(CreateString("Peter", 44, 200));

        // Supply the first optional parameter only
        Console.WriteLine(CreateString("Peter", 44, 200, true));

        // If we want to use the default for the first optional parameter (useUpperCase),
        // but we want to supply a value for the second optional parameter we
        // can use Named Parameters using the appendUnitText:false syntax
        Console.WriteLine(CreateString("Peter", 44, 200, appendUnitText:false));

        Console.Read(); // wait for enter key to be pressed
    }

    static string CreateString(string name,
                                int age, int height,
                                bool useUpperCase = true,
                                bool appendUnitText = true)
    {
        StringBuilder sb = new StringBuilder();
           
        sb.AppendFormat("name: {0} ", name);

        sb.AppendFormat("age: {0} ", age);
        if (appendUnitText)
            sb.Append("years ");

        sb.AppendFormat("height: {0} ", height);
        if (appendUnitText)
            sb.Append("cm ");

        if (useUpperCase)
            return sb.ToString().ToUpper();
        else
            return sb.ToString();               
    }
}

SHARE:

Testing Events Using Rhino Mocks

There are possible more 'elegant' methods for the below but these are fairly well understandable by someone new to Rhino Mocks or mocking in general.

Testing Event Subscription

Sometimes we want to ensure that a given event has been subscribed to. The following example is essentially testing that when a new ViewModel is instantiated (the constructor accepts an IWorkPackageCoordinator as a dependency), that the events declared on the IWorkPackageCoordinator instance have been subscribed to (by the ViewModel instance). In other words: does the ViewModel subscribe to the IWorkPackageCoordinatorevents.

To test this we create a ViewModel and pass it a mock object that has been created for us by Rhino Mocks.

 

            MockRepository mocks = new MockRepository();
            IWorkPackageCoordinator mockWPC = (IWorkPackageCoordinator)mocks.StrictMock(typeof(IWorkPackageCoordinator));

            // Tell Rhino Mocks that we expect the following events to be subscriped to
            //  - we don't care about the actual delegate that is attached hence the
            // LastCall.IgnoreArguments();
            mockWPC.Downloading += null;
            LastCall.IgnoreArguments();

            mockWPC.Loading += null;   
            LastCall.IgnoreArguments();

            mockWPC.Processing += null;
            LastCall.IgnoreArguments();

            mockWPC.Saving += null;
            LastCall.IgnoreArguments();

            mocks.ReplayAll();

            new ViewModel(mockWPC);
           
            mocks.VerifyAll();  

 

Testing Event Raising\Handling

Another test that is useful is that the object we are testing performs some action when another object raises an event that it is subscribed to.

In the example below we want to test that when an IWorkPackageCoordinator raises it's Downloading event that the ViewModel in turn raises it's PropertyChanged event. We use a boolean eventRaised, and (using lambda syntax) create an anonymous event handler for the PropertyChanged event which sets eventRaised to true if the event is fired. We then tell out Rhino Mock object to raise the Downloading event (in this example with non specific event arguments 'EventArgs.Empty')

            var mockWPC = MockRepository.GenerateMock<IWorkPackageCoordinator>();
            var SUT = new ViewModel(mockWPC);

            bool eventRaised = false;

            SUT.PropertyChanged += (s, e) => { eventRaised = true; };

            // tell mock to raise event
            mockWPC.Raise(x => x.Downloading += null, this, EventArgs.Empty);

            Assert.IsTrue(eventRaised);

 

SHARE:

Developing a Windows 7 Phone App That Connects To Azure (a quick overview)

Installing

Download and install VS 2010 RC (phone tools below don't currently work with RTM ver of VS 2010):

http://www.microsoft.com/downloads/details.aspx?FamilyID=301c97f3-aecf-42ca-966a-b8d7304f40b0&displaylang=en

Download and install vs 2010 express for windows phone ctp:

http://www.microsoft.com/express/Downloads/#2010-Visual-Phone

 

Developing

Open VS 2010 RC

New --> Project

Double Click Enable Windows Azure Tools and follow instructions to install Azure tools ( once install starts you will  have to quit VS2010)

 

 

Reopen VS2010

Create new proj Cloud --> Windows Azure Cloud Service


Add WCF Service Web Role

R click Service1 Refactor --> Rename to HelloWorldService

R Click definition for Iservice1 Refactor --> Rename to IHelloWorldService

Change interface and service class to:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WCFServiceWebRole1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
    [ServiceContract]
    public interface IHelloWorldService
    {

        [OperationContract]
        string SayHello(string name);     

    }
}





using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace WCFServiceWebRole1
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class HelloWorldService : IHelloWorldService
    {

        public string SayHello(string name)
        {
            return String.Format("Hello {0}.", name);
        }

    }
}




Add a Windows Phone Application project to the solution.



Create a user interface that looks similar to this (notice how the UI elements are pre-styled to the Win 7 phone look and feel codename 'Metro':



Here's where it gets a bit messy. VS2010 RC phone app project doesn't have an Add Service Reference, so: Save All, then r click Service1.svc --> Preview In Browser, then copy the URL - leave IE open

Open VS 2010 Express, open the solution (there might be some errors, but click ok to them), when the solution opens, add service reference to the Windows Mobile application and paste the URL into the add service box and click ok. Save all and close VS 2010 Express.

Go back to VS 2010 RC and click reload solution if you get prompted.

Now we can double click our button to go to the code behind and type:


        private void button1_Click(object sender, RoutedEventArgs e)
        {
            ServiceReference1.HelloWorldServiceClient proxy = new ServiceReference1.HelloWorldServiceClient();

            // declare callback as statement lambda
            proxy.SayHelloCompleted += (s2, e2) =>
            {
                txtGreeting.Text = e2.Result;
            };

            // call 'Azure' service
            proxy.SayHelloAsync(txtName.Text);

        }

Now hit f5 and wait for the Windows Phone Emulator to start (it may take a little time...) then if u click on the button a keyboard will pop up:



Type you name then click the Say Hello button, you should then see the "Hello ...." result displayed that was returned from the Azure service:


It's pretty amazing that a sole developer can now create a worldwide Win 7 phone app which connects to scalable set of services in Azure all from within VS2010.

SHARE:

Modify And Save an EF EntityDataSource Bound Entity From Code Behind

If you're using databound controls (e.g. FormView) and binding them to an EntityDataSource you might want to be able to modify (and save) the underlying entity from code. For example, if you have a Question entity bound to a FormView via an EntityDataSource you might want a button to allow the use to vote up or down the question (like StackOverflow for example). To be able to do this without extra trips to the database, the first thing we need to do is get hold of the EF ObjectContext that the EntityDataSource is using.

        // Context that we can use for code-behind operations
        ObjectContext questionObjectContext = null;


        protected void QuestionEntityDataSource_ContextCreated(object sender, EntityDataSourceContextCreatedEventArgs e)
        {
            questionObjectContext = e.Context;
        }

When the QuestionEntityDataSource creates it's context, we take a reference to it in our private field questionObjectContext.

Now in the button click we can up-vote the question:

 

        protected void btnVoteUp_Click(object sender, EventArgs e)
        {
            // force a databind to ensure we have a DataItem in the FormView        
            FormView1.DataBind();

            // Get the actual entity represented by the FormView
            Question questionToUpdate = FormView1.DataItem.WrappedEntity<Question>();

            // Vote-up
            questionToUpdate.VoteScore++;
           
            // using our 'copy' of the EntityDataSource ObjectContext, save the changes
            questionObjectContext.SaveChanges(true);
           
            // Force rebind of FormView to ensure newest data displayed
            FormView1.DataBind();                     
        }

This method feels like a bit of a hack, but ideally you would provide a client-side AJAX version, only if JavaScript is disabled on the client do we use this server-side up-vote.

SHARE:

Accessing Entity Framework Entities In EntityDataSource Data-Bound Controls

If using ASP.NET EntityDataSource and databound controls you may need to access the actual entity object being represented in the control, e.g. a data row in a table or a single entity in a FormView. The actual entity is not readily available however as it is automatically wrapped in a System.Web.UI.WebControls.EntityDataSourceWrapper which is not accessible. The extension method below allows you to gain access to the strongly typed, underlying entity. It is based on the article by Diego Vega which explains the wrapping behaviour in more detail. 

 /// <summary>
/// Gets the actual EF entity object that is being wrapped and databound.
/// </summary>
/// <example>
/// Advert ad = myFormView.DataItem.WrappedEntity<Advert>();
/// (where myFormView is databound to EntityDataSource returning Advert entity)
/// </example>
static class WrappedEFEntityExtensions
{
    public static TEntity WrappedEntity<TEntity>(this object dataItem) where TEntity : class
    {
        var entity = dataItem as TEntity;

        if (entity != null)
            return entity;

        var typeDescriptor = dataItem as ICustomTypeDescriptor;

        if (typeDescriptor != null)
            return (TEntity)typeDescriptor.GetPropertyOwner(null);

        return null;
    }
}

SHARE:

Blendable Silverlight (and WPF) MVVM Applications With Dependency Injection

Introduction

One of the challenges with the idea of having separate developer and designers is how to allow the developers to write code while at the same time designers are working on the UI.

The goal is to give designers working in Expression Blend some sample data that they can data-bind to, that will match the runtime data items without requiring additional build scripts\etc.

The Model-View-ViewModel (MVVM) design pattern is a popular way to architect a SL\WPF app to provide separation of concerns, testability, etc. This article assumes a basic understanding of the MVVM pattern.

Getting Started - Defining The ViewModel

We create an interface to define out ViewModel (we can do this for every distinct view in the application). Before we do this though, we need something to represent our model data, for example a person:

     public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }

Next we can define our ViewModel interface to allow the user to edit a person's details, the idea is that our view (our XAML user control) will be bound to a class that implements this interface. All data and operations are provided by the ViewModel, i.e. the view has no direct contact with the model.

     public interface IEditPersonDetailsViewModel
    {
        Person PersonToEdit { get; set; }
    }

It is this interface that allows both the designer and developer to work with a single common, well-defined set of data items.

Creating Some Design-Time Data

Now we have defined what data our view will have access to, we can proceed to provide the designer with some sample data to work with.

Remember that one of the goals for us to be able to run the application without having to modify configurations or have extra scripts, i.e. we want our app to provide a 'real' ViewModel at runtime, but a 'dummy' one to the designer in Blend. One way of providing this to to implement a version of the Service Locator design pattern:

    public class ViewModelServiceLocator
    {
        public IEditPersonDetailsViewModel GetEditPersonDetailsViewModel
        {
            get
            {
                return new EditPersonDetailsViewModel_DesignTime();
            }
        }
    }

The GetEditPersonDetailsViewModel property (by using a property we can bind to it in Blend) at the moment always returns an instance of  EditPersonDetailsViewModel_DesignTime, we will modify this shortly.EditPersonDetailsViewModel_DesignTime is defined as:

     public class EditPersonDetailsViewModel_DesignTime : IEditPersonDetailsViewModel
    {
        public EditPersonDetailsViewModel_DesignTime()
        {
            PersonToEdit = new Person()
            {
                Name="Mr Design Time Data",
                Age=44
            };
        }

        #region IEditPersonDetailsViewModel Members

        public Person PersonToEdit { get; set; }

        #endregion
    }

It is an instance of this class will provide the design time data in Blend.

Binding to Design-Time Data in Blend

(You can download a trial copy of blend from Microsoft.)

Open your project in blend and  on the Data tab choose "Define New Object Data Source...".

 

 

Select our ViewModelServiceLocator class and click OK.

 



Now we bind our usercontrol to an instance of ViewModelServiceLocator, you can do this by dragging from the data tab to [UserControl] in the Objects and Timeline pane:

 

If you look at the xaml this creates, it's basically setting the DataContext of the entire user control to the return value of the GetEditPersonDetailsViewModel property.


Now the designer can (for example) bind a textbox to the person name:



So now we have a design time ViewModel bound in Blend. If we run the app now, we would get the design time ViewModel at runtime, so the next step is to provide a 'real' ViewModel at runtime.

Providing a Runtime ViewModel

First we define our ViewModel to be used at runtime (with a hard-coded person for illustration purposes):

    public class EditPersonDetailsViewModel : IEditPersonDetailsViewModel
    {
        public EditPersonDetailsViewModel()
        {
            PersonToEdit = new Person()
            {
                Name="Mr Runtime Data",
                Age=22
            };
        }

        #region IEditPersonDetailsViewModel Members

        public Person PersonToEdit{ get; set;}

        #endregion
    }

We can then modify our ViewModel service locator to provide our runtime version:

    public class ViewModelServiceLocator
    {
        public IEditPersonDetailsViewModel GetEditPersonDetailsViewModel
        {
            get
            {
                if (System.ComponentModel.DesignerProperties.IsInDesignTool)
                    return new EditPersonDetailsViewModel_DesignTime();
                else
                    return new EditPersonDetailsViewModel();
            }
        }
    }

When we run the app we get our runtime version: 



In a real situation you could pass in the Person to be editied to the runtime viewmodel constructor and possibly use Dependency Injection to provide the dependency.

Adding Dependency Injection to the Service Locator

We can add another layer of abstraction by having the service locator delegate to a DI framework. The examples below are from another project which uses Ninject to provide DI.

    public class ViewModelServiceLocator
    {
        public IMainViewModel GetMainViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IMainViewModel>();
            }
        }



        public IAddNewWeightViewModel GetAddNewWeightViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IAddNewWeightViewModel>();
            }
        }



        public IPersonDetailsViewModel GetPersonDetailsViewModel
        {
            get
            {
                return KernelHost.Kernel.Get<IPersonDetailsViewModel>();
            }
        }
    }

 

 

    public static class KernelHost
    {
        static IKernel _kernel;
       

        static KernelHost ()
        {
            _kernel = new StandardKernel(new DI.StandardNInjectModule());
        }


        public static IKernel Kernel
        {
            get
            {             
                return _kernel;
            }
            set
            {
                _kernel = value;
            }
        }
    }

 

    public class StandardNInjectModule : StandardModule
    {
        public override void Load()
        {           
            // For normally injected IModel resolve using the instance provided by factory
            Bind<IModel>().ToFactoryMethod<IModel>(ModelFactory.Get);

            // For when a new IModel is required (and explicitly not required from thefactory)
            Bind<IModel>().To<Model>().Only(When.Context.Variable("createNewNotFromFactory").EqualTo(true));

            Bind<IModelStore>().To<IsolatedStorageModelStore>();
            Bind<IModelLoader>().To<ModelLoader>();


           
            Bind<IPerson>().To<Person>().WithArgument<string>("name", "No Name Specified").WithArgument<double>("heightCm",150);
            Bind<IBMICalculator>().To<BMICalculator>().Using<SingletonBehavior>();
            Bind<IWeightRecord>().To<WeightRecord>();
            Bind<IAggregateData>().To<AggregateData>();



            // Bind view models
            Bind<IMainViewModel>().To<MainViewModel>();
            Bind<IAddNewWeightViewModel>().To<AddNewWeightViewModel>();
            Bind<IPersonDetailsViewModel>().To<PersonDetailsViewModel>();
         

#region "Blend design time view models"
#if DEBUG
            Bind<IMainViewModel>().To<MainViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
            Bind<IAddNewWeightViewModel>().To<AddNewWeightViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
            Bind<IPersonDetailsViewModel>().To<PersonDetailsViewModelDesignTime>().OnlyIf(x => (System.ComponentModel.DesignerProperties.IsInDesignTool));
           
#endif
#endregion
        }
    }

 

SHARE:

Ensure Your Silverlight App Has Focus When The Page Loads

Assuming that your SL app is running in-browser, you may want your SL app to have initial focus, e.g. when it loads a splash screen, the OK button has focus.

You can help achieve this by using System.Windows.Browser.HtmlPage.Plugin.Focus(); in your loaded event handler for your usercontrol\childwindow, e.g.:

 

        private void ChildWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // ensure SL plugin has focus
            System.Windows.Browser.HtmlPage.Plugin.Focus();
        }

SHARE: