Telerik blogs

With our still hot Q3 2009 release we introduced a brand new RadCoverFlow control, that was rewritten from scratch in order to be able to exploit some new features in Silverlight 3 that improved both its performance and appearance. We are now using matrix projections to transform the items’ content and pixel shader effects to render the reflection. This allows us to show and properly transform any element in RadCoverFlow, including UI Elements, controls and video, as well as instantly synchronize the reflection.

This major change in the control caused major changes in its API and usage patterns. We provide some nice examples that demonstrate the most common scenarios, including how to data-bind RadCoverFlow to an RSS feed, but now I will try to explain some aspects in the data-binding that are not so obvious. I will also demonstrate our brand new RadButton control and our commanding framework, that is present in RadControls for Silverlight since Q1 2009.

Now, let’s get straight to the sample application – it consists of a ViewModel (FlickrRssViewModel class) and a View (MainPage.xaml). The ViewModel downloads a Flickr RSS feed and creates simple objects, that represent an image. The RSS download is straightforward and I am not going to explain it here. The important thing is that the downloaded XML is converted to an ObservableCollection<ImageItem>, that is used to data-bind RadCoverFlow:

<Grid DataContext="{StaticResource FlickrRssViewModel}"> <telerikNavigation:RadCoverFlow x:Name="CoverFlow" ItemsSource="{Binding Items}"> <telerikNavigation:RadCoverFlow.ItemContainerStyle> <Style TargetType="telerikNavigation:RadCoverFlowItem"> <Setter Property="Width" Value="200" /> <Setter Property="Height" Value="200" /> </Style> </telerikNavigation:RadCoverFlow.ItemContainerStyle> <telerikNavigation:RadCoverFlow.ItemTemplate> <DataTemplate> <Border BorderBrush="Black" BorderThickness="1"> <Image Source="{Binding ImageSource}" Stretch="UniformToFill" telerikNavigation:RadCoverFlow.EnableLoadNotification="True" /> </Border> </DataTemplate> </telerikNavigation:RadCoverFlow.ItemTemplate> </telerikNavigation:RadCoverFlow> </Grid>

 

The data-binding is virtually the same as any other ItemsControl – set the ItemsSource property and provide an ItemTemplate. In the ItemTemplate I put an Image, which Source property is bound to the ImageSource property of the ImageItem class:

public class ImageItem
{
    public ImageItem(string imageSource)
    {
        this.ImageSource = imageSource;
    }
    public string ImageSource { get; private set; }
}

 

In Silverlight we cannot create a custom DisplayMemberPathTemplate, hence if you use DisplayMemberPath, RadCoverFlow will display only the text representation of the value of the provided property.

I could set Width/Height on the Image element, but I chose to demonstrate that you could use the ItemContainerStyle property for that purpose. Using this Style you could set various properties on each RadCoverFlowItem, including Width, Height, Foreground, Background, etc.

Note that the Image element has an attached property set - RadCoverFlow.EnableLoadNotification. It is a behavior, that automatically turns the parent RadCoverFlowItem into Loading or Error visual states, depending on the current download state of the Image or the MediaElement. Without this property the RadCoverFlowItem will display its ItemTemplate as it is provided. When you set the property, the RadCoverFlowItem will display a rotating arrow while the Image is loading. If the image cannot be loaded, or its format is not supported by Silverlight, the RadCoverFlowItem will display an error image. The loading animation and the error image can be customized by editing the RadCoverFlow control template, which is really simple, by the way.

You could play with RadCoverFlow in its Configurator online example to get better idea what the other properties do. The most important properties you need to know about are CameraViewpoint, RotationY, CameraRotation and OffsetX/OffsetY.

Let’s move to the RadButton control. In short, it is a standard Silverlight Button control that can use Telerik Application Themes and has Command, CommandParameter and CommandTarget properties. The properties above, however, are enough for any MVVM enthusiast to like the control :) Like the standard WPF Button, when you click the RadButton, it will execute the provided command. Here is how to declare a Command (the syntax is virtually the same as the WPF commands):

public class FlickrRssViewModel
{
    static FlickrRssViewModel()
    {
        AddImages = new RoutedCommand("AddImages", typeof(FlickrRssViewModel));
    }

    public static ICommand AddImages
    {
        get;
        private set;
    }

...
}

 

The RoutedCommand class provides the Telerik implementation of the ICommand interface. When creating a new instance you need to specify a Name and owner Type – the Name is the name that will be used in XAML to reference the command. The owner Type is the type of the class, declaring the command. Here is how to wire the command in XAML:

<telerik:RadButton Content="Add more images" Command="local:FlickrRssViewModel.AddImages" />

 

The XAML namespace is irrelevant, I would advice to use it just for the sake of WPF compatibility. There is one caveat, though - the static constructor of the class, declaring the commands should be called before the XAML parser parses the Command property of the Button. In my application I create a FlickrRssViewModel instance in the beginning of the XAML file. If you cannot do this, you could “touch” a static property of the class before the InitializeComponent() method in the UserControl constructor.

The last thing about the commands that left unexplained is how to handle the command’s Executed and CanExecute events. This is usually done like this:

CommandManager.SetCommandBindings(this, new CommandBindingCollection()
{
    new CommandBinding (FlickrRssViewModel.AddImages, OnAddImagesExecuted, OnAddImagesCanExecute)
});

 

Where “this” is usually the root element of the UserControl, or the UserControl itself. The routed commands use RoutedEvents to propagate up in the visual tree, hence we need to specify the element that will “catch” the events. The syntax is borrowed from WPF, with one small difference – in WPF the CommandBindings property is a regular dependency property, while in Silverlight it is an attached property. In my application I wanted to encapsulate all of the command functionality in my ViewModel, that’s why I put the OnAddImagesExecuted and OnAddImagesCanExecute methods in the FlickrRssViewModel class and provided a public method GetCommandBindings() that returns the CommandBindingCollection, filled with the needed bindings.

In the CanExecute handler we specify whether the command can be executed, or not. This will automatically enable/disable the element that executes the command:

private void OnAddImagesCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = !this.IsCurrentlyDownloading;
}

To refresh the CanExecute on all commands on the page you need to call the CommandManager.InvalidateRequerySuggested(), for example:

private void DownloadImages()
{
    this.WebClient.DownloadStringAsync(RssUri);

    this.IsCurrentlyDownloading = true;
    CommandManager.InvalidateRequerySuggested();
}

 

Please, check the attached application and share your opinion here. I will be glad to answer your questions and get your feedback about RadCoverFlow and our commanding framework.


Comments

Comments are disabled in preview mode.