Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Named & optional parameters in Silverlight 4

Named & optional parameters are a new C# language feature coming up with .NET FX 4.0 and guess what… it’s in Silverlight 4 as well!

Optional parameters will come very useful when defining complex APIs where you would usually have to provide several overloads for the same method for it to make sense to wide variety of usages. Let’s take a look at this basic example:

public void PositionWindow(bool isTopMost, double left = 0, double top = 0, double width = 800, double height = 600)
{
    Window window = Application.Current.MainWindow;
    window.TopMost = isTopMost;
    window.Left = left;
    window.Top = top;
    window.Width = width;
    window.Height = height;
}

isTopMost is the only parameter that’s required, all other parameter specify their default value, which makes them optional. Needless to say, the default values will be used for those parameters which the calling function doesn’t provide. One thing to know is that optional parameter must always be declared after required parameters.

The following calls are all valid:

PositionWindow(true); // position and size set to defaults
PositionWindow(true, 100); // top position and size set to defaults
PositionWindow(true, 100, 200); // sizes set to defaults
PositionWindow(true, 100, 200, 600, 200); // all parameters provided

But what if you wanted to provide the size only and leave the position to be set to defaults? Enter named parameters. The same method above can be called also with:

PositionWindow(isTopMost:true, width: 600, height: 200); // named parameters
PositionWindow(true, width: 600, height: 200); // naming is optional when positioned right
PositionWindow(true, height: 200, width: 600); // order doesn't matter
PositionWindow(height: 200, width: 600, isTopMost: true); // ... even with the required parameters

Simple, eh? The need for named and optional parameters may have come from the need to simplify COM automation, but they may prove just as useful in many other cases. But before you go start creating methods with tens of optional parameters, note that this is not the ultimate solution, and one thing worth noting is although the calls above look like they are passing the specified parameters only, the compiler in fact generates them with all parameters in place. This is how the Reflector sees that last batch of calls:

bool CS$0$0000 = true;
double CS$0$0001 = 600.0;
double CS$0$0002 = 200.0;
this.PositionWindow(CS$0$0000, 0.0, 0.0, CS$0$0001, CS$0$0002);
CS$0$0001 = 600.0;
CS$0$0002 = 200.0;
this.PositionWindow(true, 0.0, 0.0, CS$0$0001, CS$0$0002);
CS$0$0001 = 200.0;
CS$0$0002 = 600.0;
this.PositionWindow(true, 0.0, 0.0, CS$0$0002, CS$0$0001);
CS$0$0001 = 200.0;
CS$0$0002 = 600.0;
CS$0$0000 = true;
this.PositionWindow(CS$0$0000, 0.0, 0.0, CS$0$0002, CS$0$0001);

Potential architectural issues aside, I’m quite happy to see this feature come to Silverlight as well. How about you?



Add version 4 components to your Silverlight 3 application with MEF

Note: this post and accompanying source code was updated to reflect the latest MEF build on Codeplex. This build is much more aligned with the version of MEF that is available from Silverlight 4 Beta SDK.

The current Silverlight version is v3, with v4 in the making (in Beta 1 at the time of this posting). Silverlight 4 is bringing a lot of new features in the core framework and to use them, you would have to migrate your applications to the latest version, once it gets released. And that would require all the potential users to upgrade their machines to the latest version as well.

But there’s another way. By using MEF (Managed Extensibility Framework), you can extend your existing Silverlight 3 application with optional package, which would contain Silverlight 4 components only.

Here’s an example: user can select an image file from your local disk in Silverlight 3 only through an OpenFileDialog, while with the new drag/drop feature in Silverlight 4, she would be able drag a picture from the file system and drop it onto the application. Why not allow those with Silverlight 4 installed do it the easy way?

To make this work, the main application should be all Silverlight 3. We’d provide additional Silverlight 4 features in a separate XAP package, which would be downloaded later and tested for the right runtime version. In case user had the latest Silverlight runtime installed, we could bring in additional features in the application. For this post, I’m going to implement the abovementioned picture select feature by providing two controls:

  • a select button for choosing the picture through an OpenFileDialog (Silverlight 3 feature)
  • a drop canvas where user can drop the picture from the file system (Silverlight 4 feature)

Silverlight 3 control

Here’s how the BrowseForPictureControl would look like:

imageThis control would be contained in the main application. It exposes the PictureSelected event, with the FileInfo data passed as an event argument. Because the application is going to subscribe to this event for each control that exposes it, we need to make an interface for it and put that into a new project that would be shared among the both packages.

public interface IPictureControl
{
    event EventHandler<PictureSelectedEventArgs> PictureSelected;
}

public class PictureSelectedEventArgs : EventArgs
{
    public FileInfo File { get; set; }

    public PictureSelectedEventArgs(FileInfo file)
    {
        File = file;
    }
}

The control implements the this interface as:

private void OnBrowse(object sender, RoutedEventArgs e)
{
    OpenFileDialog dialog = new OpenFileDialog();
    bool result = dialog.ShowDialog() ?? false;
    if (result)
    {
        OnPictureSelected(dialog.File);
    }
}

Silverlight 4 control

The improved Silverlight 4 control should be created in a new Silverlight 4 application project, that would be disconnected from the main project, but referencing the previously created shared project. The control looks simpler too:

image

And the interface implementation:

private void OnDrop(object sender, DragEventArgs e)
{
    IDataObject dataObject = e.Data as IDataObject;
    if (e.Data == null)
    {
        return;
    }
    FileInfo[] files = dataObject.GetData(DataFormats.FileDrop) as FileInfo[];

    OnPictureSelected(files[0]);
}

OK, controls done. Now, on to MEF.

Bringing in MEF

MEF for Silverlight 3 is available for download from Codeplex. You’ll need the following assemblies added as a reference in your main application:

  • System.ComponentModel.Composition
  • System.ComponentModel.Composition.Initialization.dll

The second assembly is only required to use from the main project, where composition is performed. The project that is shared between the SL3 and SL4 projects can reference just the first assembly from the list. Also, one downside of maintaining the compatibility with Silverlight 3 is that the Silverlight 4 project must reference the same System.ComponentModel.Composition assembly as other projects. No ‘native’ SL4 MEF there…

Attribute for version

Obviously, loading any Silverlight 4 based code into a Silverlight 3 application should be impossible, therefore we need to mark both of controls with information about the Silverlight runtime they require. Something in a way of:

[ExportablePictureSelector(RequiredVersion = "3.0")]
public partial class BrowseForPictureControl : UserControl, IPictureControl
{
    ...
}

for Silverlight 3 control, and:

[ExportablePictureSelector(RequiredVersion = "4.0")]
public partial class DragDropPictureControl : UserControl, IPictureControl
{
    ...
}

for Silverlight 4 control.

The ExportableSelector attribute is derived from MEF’s ExportAttribute and is declared as:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExportablePictureSelectorAttribute : ExportAttribute, IPictureSelectorMetadata
{
    public ExportablePictureSelectorAttribute()
        : base(typeof(IPictureControl))
    {
    }

    public string RequiredVersion { get; set; }
}

Putting it all together

The main application provides a catalog of all the controls that were discovered:

[ImportMany(AllowRecomposition = true)]
public ObservableCollection<Lazy<IPictureControl, IPictureSelectorMetadata>> PictureControls { get; set; }

The PictureControls collection will change whenever a new export is discovered by MEF. When that happens, the newly discovered control will be added to the main form:

private void OnPictureControlsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    foreach (Lazy<IPictureControl, IPictureSelectorMetadata> view in Views)
    {
        Control c = view.Value as Control;
        if (!panel.Children.Contains(c) && Application.Current.Host.IsVersionSupported(view.Metadata.RequiredVersion))
        {
            panel.Children.Add(c);
            view.Value.PictureSelected += OnPictureSelected;
        }
    }
}

The above code shows that the main criteria for adding the control on the form is that it’s RequiredVersion is supported by the runtime – and that is checked with the interop IsVersionSupported method of the plugin host.

When picture is selected, the PictureSelected event is fired by the control and handled to display the picture:

private void OnPictureSelected(object sender, PictureSelectedEventArgs e)
{
    BitmapImage bi = new BitmapImage();
    bi.SetSource(e.File.OpenRead());
    image.Source = bi;
}

Of course, BrowseForPictureControl control being included in the main project, it will immediately be picked by MEF and inserted in the PictureControls collection. For Silverlight 4 based XAP package, however, we need to download it first. Here’s the InitializeContainer method, which initializes a new composition container and triggers the package download:

private void InitializeContainer()
{
    PackageCatalog catalog = new PackageCatalog();
    catalog.AddPackage(Package.Current);
    CompositionContainer container = new CompositionContainer(catalog);
    container.ComposeExportedValue(catalog);

    CompositionHost.InitializeContainer(container);

    Package.DownloadPackageAsync(new Uri("CrossVersioning.Version4Enhancements.xap", UriKind.Relative), (e, p) =>
    {
        if (p != null)
        {
            catalog.AddPackage(p);
        }
    });

    PartInitializer.SatisfyImports(this);
}

The Silverlight 4 package is asynchronously downloaded from the server and added to the package catalog. The last line is there to start the initial composition, causing the v3 control to immediately show up.

Conclusion

There… the application is set up. Users, having the Silverlight 3 runtime installed, will see the it as:image… and Silverlight 4 users will also see that additional feature:

image

This approach will let you gradually update your applications to use Silverlight 4, not forcing the users to update to the latest runtime immediately (although there would probably be no reason not to ;))

You can test the application right here:

Or download the source code from here. Enjoy.



My MEF articles published on SilverlightShow

My two-part article on rebuilding an existing Silverlight application to use MEF (Managed Extensibility Framework) for “selective composition” is now live on SilverlightShow.net (part 1, part 2). I took my Halloween Gallery application and made it pluggable so I can pull in different themes throughout the whole year (current themes include Halloween and Christmas).

Halloween Live Gallery Christmas gallery 

The original features are still there – geotagged photos are retrieved from Flickr API and the location where they were shot is shown on the Bing Map. If you’re interested in MEF, take a look at let me know what you think. The application will be released to Codeplex soon.



Display “My Pictures” in Silverlight application at design time

Following up on The ultimate hack for Silverlight in Blend post from Josh Smith, I tried to make Blend display pictures from the My Pictures folder right in my Silverlight application. Needless to say, it worked as advertised :)

Blend

The ViewModel is set through d:DataContext:

public class MainPageViewModel
{
    public MainPageViewModel()
    {
        SetLocalPictures();
    }

    private void SetLocalPictures()
    {
        string folder = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
        IEnumerable<string> pictures = Directory.EnumerateFiles(folder);
        Pictures = (
            from p in pictures 
            select new Uri(string.Format("file://{0}", p.Replace('\\', '/')), UriKind.Absolute)
            ).ToArray();
    }

    public Uri[] Pictures { get; set; }
}

The thing is that this code wouldn’t work with Silverlight application running in a non-trust mode – it would throw a security exception. However, setting this ViewModel as the run-time DataContext and running with elevated permissions, the pictures would get displayed as well.

And of course this works in Visual Studio 2010 designer too:

VS2010

A nice alternative for Blend’s sample data…



My articles on SilverlightShow

A few of my Silverlight articles were published on the SilverlightShow site this past two months. The first one is an introduction to Silverlight/(WPF)/Blend behaviors, where I create a Silverlight Halloween Sound Player without writing a single line of code – the application is composed entirely in Expression Blend, using various behaviors.

Halloween Sound Player

I also used behaviors for another article, to showcase some of the new Silverlight 4 features: WebCam capture support, printing, drag/drop, clipboard, commanding, some databinding enhancements and implicit styling support. The result is a nice doodling application, which can be used to entertain your kids.Camdoodle

The third article was about creating a Europe Weather Map with Silverlight, showing current weather conditions for some of the larger cities in Europe. It was mostly about using the Bing Maps Silverlight Control SDK, but fun anyway.

Europe Weather map

You can expect more articles appearing on SilverlightShow in the next days/months. Leave a comment if you find them useful.



Silverlight 4 WebCam zoom

Fooling around with Silverlight’s WebCam support. The application below will let you zoom in and out of WebCam capture and pan around. Nothing special, just a quick POC for the project I’m building. Silverlight 4 required.



MVVM with WPF, Silverlight, and… Windows Forms

In my post-NTK09 conference blog post I mentioned one of my MVVM demos was about sharing a ViewModel between WPF, Silverlight and even Windows Forms application. I got a lot of requests for posting sample code online since then, which I intended to do earlier, but because the sample application code was closely related to the conference, I wanted to create a whole new sample application first and share that. Of course time passed and other things kept me busy from actually doing it. With Silverlight 4 Beta coming out recently, things progressed even further in so I decided to keep things as they were, and post the original sample code. I’ll explain it in few lines (and pictures) here, and the source code can be found here.

What’s it all about?

The purpose of the sample (and my NTK09 talk in general) was about the MVVM pattern principle and how it can be used to totally separate the User Interface from the business logic and data. The application I built was a conference session schedule viewer / editor. Technically, there are three application flavors: WPF, Silverlight and WinForms. They share the same data access (WCF service) and ViewModel. The only thing different between the three is their UI implementation.

imageimageimage

Notice the small arrow overlay over the C# icon on Silverlight and WinForms PageViewModel.cs? That’s because both project are linking the original file from the WPF project, which I created first. That means that ViewModel is exactly the same across all three projects when they are compiled. And with all three project, this is the ViewModel that serves up the main page.

The WPF project

I created the WPF project to ‘just work’. I didn’t bother with styling and the looks, I intentionally left it ugly. I used Prism for commanding and WCF based web service for communicating the data.

image

The ‘Dan’ (Day) and ‘Kategorija’ (Category) serve as the filter for the session list on the left. Each combo box change results in a server request which returns new data for filling the session list. Other fields are editable session details fields. Three buttons on the top left correspond to New, Edit and Delete, in that order.

The Silverlight project

The Silverlight project differ from WPF in that that it’s in color :)

Silverlight

Prism is still used for commanding, but the UI is quite different. I even provided the View (above) and Edit (bottom) screens.

Silverlight Edit

As said, the difference between the WPF and Silverlight applications is just and only different XAML. And both have zero code-behind code. Moving on to…

The Windows Forms project

I  didn’t bother much with making Windows Forms project to work. I last coded anything in WinForms 2+ years ago so I suspect I won’t have to go there again… However, this is the UI I put together:

Windows Forms

It’s very similar to WPF, but data bindings perform much slower. Data bindings? There’s data bindings in WinForms too?

LOL. Sometimes I really do get questions like that. Anyway, let’s see the ‘code behind’. [There’s actually quite a few lines of code behind in Windows Forms because it’s used to instantiate and initialize all controls on the screen. That code is stored in the .designer file and I’m ignoring it as the code behind]

private void MainForm_Load(object sender, EventArgs e)
{
    PageViewModel viewModel = new PageViewModel();

    dayBox.DataBindings.Add("DataSource", viewModel, "Days");
    categoryBox.DataBindings.Add("DataSource", viewModel, "Categories");
    categoryBox.DisplayMember = "Name";
    speakerBox.DataBindings.Add("DataSource", viewModel, "Speakers");
    speakerBox.DisplayMember = "FullName";
    speakerBox.ValueMember = "Id";
    startTimeBox.DataBindings.Add("DataSource", viewModel, "TimeValues");
    endTimeBox.DataBindings.Add("DataSource", viewModel, "TimeValues");
    sessionList.DataBindings.Add("DataSource", viewModel, "Sessions");
    sessionList.DisplayMember = "Title";

    dayBox.DataBindings.Add("SelectedValue", 
        viewModel, "SelectedDay", true, DataSourceUpdateMode.OnPropertyChanged);
    categoryBox.DataBindings.Add("SelectedValue", 
        viewModel, "SelectedCategory", true, DataSourceUpdateMode.OnPropertyChanged);
    sessionList.DataBindings.Add("SelectedValue", 
        viewModel, "SelectedSession", true, DataSourceUpdateMode.OnPropertyChanged);
    speakerBox.DataBindings.Add("SelectedValue", 
        viewModel, "SelectedSession.SpeakerId", true, DataSourceUpdateMode.OnPropertyChanged);

    startTimeBox.DataBindings.Add("Text", 
        viewModel, "SelectedSession.StartTime", true, DataSourceUpdateMode.OnValidation);
    endTimeBox.DataBindings.Add("Text", 
        viewModel, "SelectedSession.EndTime", true, DataSourceUpdateMode.OnValidation);
    titleBox.DataBindings.Add("Text", 
        viewModel, "SelectedSession.Title", true, DataSourceUpdateMode.OnValidation);
    descriptionBox.DataBindings.Add("Text", 
        viewModel, "SelectedSession.Description", true, DataSourceUpdateMode.OnValidation);

    newButton.Click += (s, ev) => 
        { viewModel.NewSessionCommand.Execute(null); };
    editButton.Click += (s, ev) => 
        { viewModel.EditSessionCommand.Execute(viewModel.SelectedSession); };
    deleteButton.Click += (s, ev) => 
        { viewModel.DeleteSessionCommand.Execute(viewModel.SelectedSession); };
    saveButton.Click += (s, ev) => 
        { viewModel.EndEditSessionCommand.Execute(viewModel.SelectedSession); };
    cancelButton.Click += (s, ev) => 
        { viewModel.CancelEditSessionCommand.Execute(viewModel.SelectedSession); };
}

This is all the code for the main form. You’ll notice it’s all used for binding controls to various properties on the ViewModel. I could also get rid of some of the lines by setting the properties on the WinForms designer (thus moving them to the .designer file). The last section wires button clicks to execute commands in the ViewModel.

There is absolutely no business logic in this code which makes it very similar to declarative XAML in WPF and Silverlight projects. I was toying with the idea of making an Extender Provider to get rid of the above lines completely and do it all just with the Windows Forms designer – I made a working prototype, but wasn’t generic enough to include it in the sample.

Source code

Bellow is the full source for all three main and related projects. Also included is the Test project with a few Silverlight Unit Test Framework tests. Database is not included so you’ll not be able to actually run any of the applications. Sorry. I’ll post the Silverlight version online when time permits.



Silverlight LOB: Validation (#2 – Annotations and shared classes)

In my previous post, I wrote about “the first line of defense” against inputting invalid data in Silverlight applications (or any kind of application, for that matter) – preventing the user from entering invalid data through some an input form. Input form fields are commonly directly bound to the underlying object’s properties – either directly or through a of value converter – in both cases the entered value gets assigned to the bound object’s property; and this is exactly the place where we would want to put our second line of defense.

Silverlight 3 supports data validation. The majority of controls now feature new visual states for presenting themselves whenever they are associated with invalid data. Putting a control into the invalid state is as easy as throwing an exception in its bound property’s setter code:

public DateTime BirthDate
{
    get { return birthDate; }
    set
    {
        if (birthDate == value)
        {
            return;
        }

        if (birthDate > DateTime.Today)
        {
            throw new ArgumentException("The birth date is invalid.");
        }

        birthDate = value;
        OnPropertyChanged("BirthDate");
    }
}

When the property is set to an invalid date, the exception gets thrown. This exception is then caught by the data binding engine, which in turn triggers the BindingValidationError event, prompting the control to go to invalid state:

 image

This kind of notification can be enabled by setting binding’s ValidatesOnExceptions and NotifyOnValidationError properties to true.

System.ComponentModel.DataAnnotation

There is another way to perform validation over entity’s properties:  by using validators from the System.ComponentModel.DataAnnotation assembly. What you do is put an appropriate attribute above the property definition, describing the kind of validation to performed over property value.

[Required(ErrorMessage = "The date of birth is required.")]
public DateTime BirthDate
{
    get { return birthDate; }
    set
    {
        if (birthDate == value)
        {
            return;
        }

        birthDate = value;
        OnPropertyChanged("BirthDate");
    }
}

You can even write your own validation attributes by deriving from the ValidationAttribute class and overriding the validation method. Here’s an example to match my first method of validation (throwing an exception in property setter):

public class BirthDateValidationAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, 
ValidationContext validationContext) { if (value == null) { return ValidationResult.Success; } DateTime date = (DateTime)value; if (date > DateTime.Today) { return new ValidationResult("The birth date is invalid."); } return ValidationResult.Success; } }

Let’s put this to work. Say we’re using shared entity classes in our project; a kind of a real world scenario. When projects are set up as described in my previous blog entry, we immediately bump into a problem – decorating the Person’s BirthDate property with the new BirthDateValidationAttribute results with the compilation error: it’s just that full .NET framework’s ValidationAttribute implementation differs form how Silverlight’s version is implemented and therefore above BirthDateValidationAttribute can’t be shared between both entity projects:

Client side: protected abstract ValidationResult IsValid(object value, ValidationContext validationContext)
Server side: public abstract bool IsValid(object value)

To work around this, we need to create a dummy validator attribute class in the server side entity project, having the same name as its client counterpart, except always returning true as the validation result:

public class BirthDateValidationAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        return true;
    }
}

Validation

Instead of throwing an exception from the property trigger as in the previous example, we can now simply call the validation method, which would validate against every ValidationAttribute defined for the property.

Modified Property definition (Validate() method is called instead of throwing an exception):

[DataMember]
[BirthDateValidation]
public DateTime BirthDate
{
    get { return birthDate; }
    set
    {
        if (birthDate == value)
        {
            return;
        }

        Validate("BirthDate", value);
        birthDate = value;
        OnPropertyChanged("BirthDate");
    }
}

Because we only want to validate properties on the client, we need to implement the Validate() method just on the client side. But since the Person class is shared, we really have to include this method on both sides, except we would implement it differently.

In the end, Validate() method on the client is defined as:

private void Validate(string propertyName, object value)
{
    Validator.ValidateProperty(value, new ValidationContext(this, null, null)
    {
        MemberName = propertyName,
    });
}

… while the server side method can be left empty:

private void Validate(string propertyName, object value)
{
}

Single base class for entities?

To avoid having duplicate validation methods for all entities, it’s best to put it in a single base page, where you would put all the common entity code (like INotifyPropertyChanged etc.). In this case, partial methods are going to prove themselves very useful:

Main base class part:

partial void ValidateProperty(string propertyName, object value);
protected void Validate(string propertyName, object value)
{
    ValidateProperty(propertyName, value);
}

Client side base class part:

public partial class EntityBase
{
    partial void ValidateProperty(string propertyName, object value)
    {
        Validator.ValidateProperty(value, new ValidationContext(this, null, null)
        {
            MemberName = propertyName,
        });
    }
}

We can just leave the server side base class part out and forget about it. The best thing with with partial methods is that you don’t have to provide any implementation if you don’t want to – in which case the method simply won’t be called.

Source code for this project is available:




Detecting duplicate instances of a running Silverlight application

This is a short tip for constraining your Silverlight applications to a single instance, something that’s quite popular in the desktop applications world. What you want to do is allow only the first instance of your application while rejecting all subsequent instances.

Silverlight 3 introduced a way for applications to communicate between each other, either on the same page or instantiated on a different browser instances (works even with Installed/OOB apps). The communication is performed by sender and receiver classes, which exchange messages through named channels. Each receiver must register a unique name for the channel or an exception will be thrown.

And that’s the trick. Listening on a specific named channel will act like a mutex. By catching the ListenFailed exception you get an option to display appropriate message or launch a different version of the application. All the work is done in App.Xaml.cs file:

private void Application_Startup(object sender, StartupEventArgs e)
{
    try
    {
        receiver = new LocalMessageReceiver("singleinstance");
        receiver.Listen();
        this.RootVisual = new MainPage();
    }
    catch (ListenFailedException)
    {
        this.RootVisual = new DuplicateInstancePage();
    }
}

The test project is available through here.



Halloween Live Gallery

With Halloween around the corner, it’s time for some scary photos… In this post I’ll explain how I built my demo application I showed at my Windows 7 Launch talk.

Expression Blend 3 shipped with a few interesting samples, available for immediate use. One of them is called Wall3D (Silverlight 3) and is a great example of one of the new Silverlight 3D features, called perspective transform.

image

This sample (perhaps a starter kit is a better description for it) features a 3D photo gallery, which sort of puts the viewer in the center of an oval “room”, full of photos, with an option to rotate the view to the left or right (flick / mouse click and pan), zoom in or out (mouse wheel), etc.. The kind of what people used to do in Flash; now it’s possible in Silverlight too. The sample serves also as a demonstration of yet another new Blend 3 feature, called Sample data – the photos on the above image were generated through this feature. Let’s explore the sample and see how we can push it further, shall we?

After opening Blend 3, switch to the Samples page and choose Wall3D (Silverlight 3) and the default project will be generated for you. image

You can test the application by hitting F5. You navigate through the gallery by flicking the view left or right and zoom in or out with your middle mouse button.

Examining the code that’s been created in the project will reveal the following:

  • the photos come from the sample data source (XML + photos, which are also included in the project – look into the SampleData folder)
  • “The wall” is driven by the CircularPanel3D control (a custom panel)

Knowing this, we’re ready to create our own 3D gallery. We’ll only need a single thing from this sample project, and that’s the CircularPanel3D.cs file, found in the root of the project. Copy and save that in some other folder for later reference, then start a new Silverlight 3 Application project in Blend.

I used an ItemsControl instead of ListBox to arrange and display the photos. Of course both will accept CircularPanel3D as their ItemsPanel, I just didn’t need item selection in this case. Here’s how it all looked in Blend designer:

Now what’s wrong with this picture? It’s hard to design something when you’ve got no visual feedback to help you with the layout and arrangements. I have already modified the ItemTemplate, but without the actual photos, it’s hard to do proper design work.  And that’s where the sample data comes in. To create a sample data source, open the Data panel and click on the second icon from the right image (Add sample data source). Choose Define New Sample Data, name the data source and click OK. You can shape the sample data source however you like – flat, hierarchical, with entities having simple or complex type properties, etc. For this gallery, I created the following source:

image

Bind this data source to the ItemsControl as its items source – voila!

Cool, much better. Modifying the ItemTemplate has just become a lot easier. Let’s add another element for displaying a bit more details about the photo (like the title and location where it was taken).

Photo view Details view

So we’ve got two views for the ItemTemplate, each view being represented with a separate element – one’s with the photo and the second one with details. We have to provide a way for user to switch between the two; how would we do this? Write code? Call the developer? Not necessarily. If we’re in luck, the appropriate piece of code may have already been written, waiting to be taken it used in Blend for declaratively specifying whatever we wanted to do to those elements and how. That piece of code is called a behavior. There are several places on the web to look for behaviors (as well as more info on what they are and how to produce them), but my first bets would be the Expression Gallery and Expression Blend Samples library on Codeplex; the letter containing some very handy behaviors.

I added a couple of behaviors to add interaction to gallery elements - FlipAction would switch the photo and details part through flip motion, triggered by DoubleClick trigger; and ScaleBehavior would enlarge the photo on mouse over. A couple of clicks for very cool-looking effect.

Let’s take a look at the data source... I decided to use Flickr to retrieve the photos, because it’s API is easy to use and can (amongst other things) return geo-location of the place where photo was taken (when available). This geo-location is then passed to the Bing Maps geocoding web serviceas an input parameter to retrieve the real-world address; these addresses can be seen on the bottom of the flipped photo.

image

Playing with geo-location was fun so I decided to take it a step further. I put together a special ShowMapAction, which is currently triggered by a mouse wheel over the photo (or details). The action simply shows the location on the interactive Bing Map (I used Bing Maps Silverlight Map Control for this).

image

Just a word of caution: Geo-encoded photos are cool, but be careful what you’re publishing on the net. The information may not always be used for good purposes.

The final result can be seen here (live). Right in time for keeping track with what’s going on on Halloween.

Finally I have to say I’m spending a lot more time in Blend since version 3 got out. It’s evolving into a great tool and behaviors are going to take a significant part in designer’s/integrator’s role in the future.

http://tozon.info/gallery/