Tags

, ,

Exciting Background

Round-robin is a pattern often used in load-balancing scenarios where a scheduler matches/routes a task to an available resource for purpose of efficiency and or continuity. 

if you like me and like to dig under the hood and understand all that is going on in the code, basically the content holders are the available slots/resources that a data item(task) can use to get display time on the UI.  As request arrives for next and previous task, the contentHolders(slots/resources) are freed and made available.

the control could easily serve as the framework for a carousal or slide show type of control with dynamic data that demands continuity.

Enough already

This example is a level 1 introduction at creating custom controls in Silverlight, thus the tutorial will only serve that purpose.  however, if you would like to know the detail of the implementation not shown here, refer to the background section and the comments in the source code.

So, this is the basic schema for the SlidePresenter custom control.  The only required functions are the constructor where I define the DefaultStyleKey for the control as well as overriding the OnApplyTemplate method where much of the initialization debut.

using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace WoRoSoft.Controls
{
    public class SlidePresenter : Control
    {
        private Canvas _whiteBoard;
        private FrameworkElement _whiteBoardMask;


        private readonly Int32 _maxContentHolders;
        private FrameworkElement[] _contentHolders;

        private ObservableCollection<Object> _items;

        public SlidePresenter()
        {
            DefaultStyleKey = typeof(WoRoSoft.Controls.SlidePresenter);
            _maxContentHolders = 5;
            Initialize();
        }

        private void Initialize()
        {
            _contentHolders = new FrameworkElement[_maxContentHolders];

            for (int i = 0; i < _maxContentHolders; i++)
            {
                _contentHolders[i] = new ContentControl();
            }            
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }

        public void BringInNextContent()
        {

        }

        public void BringInPreviousContent()
        {

        }

        public ObservableCollection<Object> Items
        {
            get
            {
                return _items;
            }
            set
            {
                _items = value;
            }
        }
    }
}

Next I added a xaml Resource file to serve as my default controlTemplate provider and sgenericet its build Action to Resource.  By default it is good to name the file generic.xamlsetthemetoresourcesetthemetoresource2

 

 

 

 

and this is the content of the generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:class="clr-namespace:WoRoSoft.Controls">
    
    <Style TargetType="class:SlidePresenter">
        <Setter Property="Template" >
            <Setter.Value>
                <ControlTemplate>
                    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderThickness="2">
                            <Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch" x:Name="PART_whiteBoard" Background="Wheat">
                                <Canvas.Clip>
                                    <RectangleGeometry x:Name="part_whiteBoardMask" />
                                </Canvas.Clip>
                            </Canvas>
                        </Border>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
            

</ResourceDictionary>

Inside my controlTemplate, I defined a control having the name “PART_whiteboard” and another one having the name  “part_whiteBoardMask” because the SlidePresenter Custom Control requires those parts as mentioned by its Class level TemplatePart Attribute. See second code container below.

public override void OnApplyTemplate()
        {            
            _whiteBoard = GetTemplateChild("part_whiteBoard") as Canvas;
            _whiteBoardMask = GetTemplateChild("part_whiteBoardMask") as FrameworkElement;

            if (_contentHolders == null && _whiteBoardMask != null && _whiteBoard != null)
                Initialize();
        }

From inside the OnApplyTemplate the required UI elements are retrieved using the GetTemplateChild method passing in the part name and stored locally by a canvas variable and FrameworkElement variable.

    [TemplatePart(Name="part_whiteBoard", Type=typeof(Canvas))]
    [TemplatePart(Name="part_whiteBoardMask", Type=typeof(FrameworkElement))]
    public class SlidePresenter : Control

TemplatePart attribute is stamped on the SlidePresenter Custom Control demanding a part having the declared Name and being of a type matching the declared Type.

Additionally, since Silverlight does not provide a ClearBinding method out of box I wrote the following in effort to ease unbinding a control from its current data item:

private void UnbindAllContentHolders()
        {
            for (int i = 0; i < _maxContentHolders; i++)
            {
                _contentHolders[i].ClearValue(ContentControl.DataContextProperty);
            }
        }

finally, I’ve also included a nice goody to help me detect when the control is being displayed from inside an editor such as Visual Studio or Expression blend.  For the most part it is always good to test the control also from within Visual Studio.

protected Boolean IsDesignMode
       {
           get
           {
               return System.ComponentModel.DesignerProperties.GetIsInDesignMode(Application.Current.RootVisual);
               
           }
       }

If you take the time to look at the code of this simple sample, you will notice that I make extensive use of the stack for easy performance gain, but keep in mind that the winding of calls are kept at a maximum of 5 and that long lived variables are heap based so as to minimize unexpected overflow issues.

Conclusion

you can also use the control as an L shape item list presenter by synching two SlidePresenter with different alignment (Vertical and Horizontal).

In the next tutorial I will demonstrate how to implement a DataTemplate DependencyProperty that will allow you to define the default template for the dynamically created ContentControl bound to your data

Here is the source Code.

Download Link

Advertisements