(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Custom Controls: Weather control: Part 2 – The Slider

(1 votes)
Denislav Savkov
>
Denislav Savkov
Joined Feb 11, 2008
Articles:   14
Comments:   6
More Articles
3 comments   /   posted on Aug 12, 2008
Categories:   General , Controls

This article is compatible with the latest version of Silverlight.

See also part 1, part 3 and the update.

Download full source code

What is the slider

Main part of the weather control we introduced is the slider. Actually, we planned the whole weather control as a demo for it. The slider is a separate control that has functionality similar to the ListBox control.

It has support of

  • Items
  • Defining items in XAML
  • Binding items to data objects
  • Template the items
  • Template the containers for the items
  • Selection
  • Scrolling
  • Mouse dragging

Almost all of the above are available in ListBox but there are differences with our slider. The main differences are that it uses animations for scrolling instead of instant transition and it provides better customization for the container. We called it AnimatedSlider and like the ListBox it inherits from ItemsControl.

Why inherit from ItemsControl

ItemsControl is the most convenient class to inherit from. To display the items we need a parent element that is visualized and ItemsControl provides a Panel. It has support for DataTemplate items and binding so this will shorten our work. When inheriting from ItemsControl we should override

There are some functions that handle the items and their containers that you need to override if you want to extend the functionality of the ItemsControl. For more information on the functions see the descriptions in the tables in our article on how to do that.

How does ItemsControl support binding

To support binding ItemsControl needs a source collection that implements INotifyCollectionChanged wed. This allows tracking changes in the data and updating the control. ItemsControl hooks on the event NotifyCollectionChangedEventHandler and handles the changes in the collection accordingly. You can see that in the private functions of the class ItemsSourceChanged and OnCollectionChanged in .Net Reflector. When you inherit from ItemsControl you can override OnItemsChanged to process the changed items.

Do you speak XAML

What do we mean by support of items in XAML?

We mean possibility to use syntax like this:

<MyControl>
    <SomeControl/>
    ...
    <AntherControl/>
</MyControl>

Probably the first thing you need to know is the XAML syntax and how the XAML declarations bond with your class. For our case we will explain in short but for more detailed information you should read the MSDN page on XAML syntax. XAML like this

<MyControl TextProperty="TextValue"/>

called Attribute syntax and XAML like this

<MyControl>
    <MyControl.ColorProperty>ColorValue</MyControl.Property>
</MyControl>

called Property Element syntax are often used and seem obvious. It turns out our in case we need the Content Element syntax that is usually used to define the Parent-Child relationship.

<Parent>
    <Child/>
</Parent> 

This syntax is somewhat more special. It is used to assign value to a certain property and that is the property indicated by the ContentPropertyAttribute of the class. Here is an example of how it works.

Definition in code

[ContentProperty("SpecificProperty")]
public class MyControl
{
    public string SpecificProperty
    {
        get { return _specificProperty; }
        set { _specificProperty = value; }
    }
  
    private string _specificProperty;
}
Use in XAML
<MyControl SpecificProperty="Value"/>

which is equivalent to

<MyControl>Value</MyControl>

Value could be anything from string to collection. In the case of collection the opening and closing tag for the collection can be omitted. In the ItemsControl ContentPropertyAttribute is the Items property, which is of type ItemCollection.

Implementing selection

To add selection functionality to an ItemsControl we use the helper class SelectionManager from our previous article to create the class ItemsSelector.

protected ObservableCollection<ISelectable> _selectableItems;
private SelectionManager _selectionManager;
public event EventHandler<SelectionChangedEventArgs> SelectionChange;

PrepareContainerForItem is called when an item is updated or added. We only add the container of the item in our list of items that are selectable.

protected override void PrepareContainerForItemOverride( DependencyObject element, object item )
{
    base.PrepareContainerForItemOverride( element, item );
    ISelectable item2 = element as ISelectable;
    if ( item2 != null )
    {
        this._selectableItems.Add( item2 );
    }
}

And tell the SeletionManager to manage our collection…

_selectionManager.SetCollectionToManage ( _selectableItems );

…then we get notified for change of the selection…

_selectionManager.SelectionChange += new EventHandler<SelectionChangedEventArgs>( _selectManager_SelectionChange );

…and pass the event outside

void _selectManager_SelectionChange( object sender, SelectionChangedEventArgs e )
{
    if( this.SelectionChange != null )
        this.SelectionChange( this, e );
}

ItemsControl with templatable containers

We already showed you how to inherit from ItemsControl and implement containers but here we have some more thoughts on how we do it here. ItemsControl is designed to be extendable with containers for its items. That’s why you override GetContainerForItemOvveride() – you should return the type of your container. This is used in the private methods of ItemsControl. Container for the items can be any ContentControl. We chose to create the class ItemContainer that extends the ContentControl and has additional three properties. Two of them ContentWidth and ContentHeight allow you to choose the size of the items. Normally, they would have the size of the container. The other property (ContentStyle) sets the Style of the item. Normally, you would set only the DataTemplate of an item like in the ListBox. This allows you to set template for the container and for the item, and have DataTemplate for the item. The idea is to allow the user to template the items if they are defined in XAML without setting template for the containers.

The ItemContainersControl class is the class that implements containers. It inherits the ItemsSelector and defines four new properties. Three of them correspond to the three properties we talked about lastly. The other exposes the template of the container.

AnimatedSlider

The final step to finish our slider is to make the items scrollable. We do that by simply animating the Canvas.Left property of the ItemsPresenter. ItemsPresenter is the Panel containing the items. The control has two buttons to control the movement. The space between the buttons is the visible area. We use clip to hide the items that are outside of it.

void AnimatedSlider_LayoutUpdated( object sender, EventArgs e )
{
    this.LayoutUpdated -= new EventHandler( AnimatedSlider_LayoutUpdated );
    _areaWidth = this.ActualWidth - PreviousButton.ActualWidth - NextButton.ActualWidth;
    RectangleGeometry visibleArea = new RectangleGeometry();
    Rect clip = new Rect( 0, 0, _areaWidth, this.ActualHeight );
    visibleArea.Rect = clip;
    View.Clip = visibleArea;
}

The other way of scrolling is using mouse dragging. Both for the movement animation and the mouse dragging we’ve added limitations so that the view doesn’t go out of boundary.

void RightButton_Click( object sender, RoutedEventArgs e )
{
    double dist = ( double )ItemsPresenter.GetValue( Canvas.LeftProperty ) - _areaWidth - NextButton.ActualWidth;
    if ( dist + 20 <= -( ItemsPresenter.ActualWidth ) )
    {
        ItemsPresenter.SetValue( Canvas.LeftProperty, _areaWidth - ( ItemsPresenter.ActualWidth ) );
    }
    else if( ToNextStoryboard != null)
        ToNextStoryboard.Begin();
}
 
private void Canvas_MouseMove( object sender, MouseEventArgs e )
{
    if ( _IsMouseDrag )
    {
        Point toViewCoordinates = e.GetPosition( View );
        double delta = toViewCoordinates.X - _lastMousePos.X;
        double newLeft = ( double )ItemsPresenter.GetValue( Canvas.LeftProperty ) + delta;
        if ( newLeft <= 0 && newLeft >= -( ItemsPresenter.ActualWidth - _areaWidth ) )
            ItemsPresenter.SetValue( Canvas.LeftProperty, newLeft );
        _lastMousePos = toViewCoordinates;
    }
}

In Part 3 we template the slider and connect it to the weather forecast web service.


Subscribe

Comments

  • -_-

    RE: Custom Controls: Weather control: Part 2 – The Slider


    posted by Gus on Aug 14, 2008 12:56

    Very nice, I wanted to implement this control in my project to display bound textBoxes from a XML file with Parts information. I got it to work but I wanted to show one part at a time, how do I make it slide using the buttons to the next part. I am trying to use it like an Image slider, where only display one picture at a time.

    Thank you,

  • dejo

    RE: Custom Controls: Weather control: Part 2 – The Slider


    posted by dejo on Aug 15, 2008 06:57

    Hi Gus,

    please see the update we posted

    http://www.silverlightshow.net/items/Weather-control-update.aspx

    and the comment I left you in the first article

    http://www.silverlightshow.net/items/Custom-controls-Weather-forecast-control-Part-1-Introduction.aspx

    Denislav Savkov

  • lnikolov

    RE: Custom Controls: Weather control: Part 2 – The Slider


    posted by lnikolov on Jan 13, 2011 18:01
    The article has been updated to the latest version of Silverlight and Visual Studio.

Add Comment

Login to comment:
  *      *