This is a migrated thread and some comments may be shown as answers.

Custom

2 Answers 96 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Roberto
Top achievements
Rank 1
Roberto asked on 30 Jun 2010, 11:15 AM
Hi,

Instead of the more usual technical question, this post is related to functional requirements, and choosing among different implementations. I hope I can keep it as short as possible, not too philosophical, and of course, raise interest/curiosity among some of you ;-)

We are currently building a Framework in order to ease and speed up the development of certain kind of applications. We have decided to create a custom control library (using telerik as base) that must fulfill the following requirementes:

1.- Provide just the properties/events (Controls) that we consider necessary. --hiding attributes--
2.- Extend the base controls in order to add extra functionallity. --creating new attributes--
3.- Ease the implementation of our interfaces. By dragging a control from the VisualStudio (or Blend) designer toolbox to the window/page/usercontrol/etc, the developer will have most of the necessary attributes (see req. 1) with the proper default values.
4.- The controls must support all the standard (graphic) features of WPF: Styling, Control Templates, Storyboards, etc.
5.- The controls must support standard event handling, although we might use a fancier action/commanding approach (like the ones implemented by Prism, or Caliburn)
6.- DataBindings.

After some research, we came up with three solutions (summarized, as I'm trying to keep this as short as possible):

A) Wrapping the control: using Control as base class, we add the telerik control as the first (and only) visual child. Then we create a DependencyProperty for each DP we want to expose from the telerik control.
public class MyComboBox : MyBaseControl  
{  
    static MyComboBox()  
    {  
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyComboBox), new FrameworkPropertyMetadata(typeof(MyComboBox)));  
  
        RegisterDependencyProperties(typeof(MyComboBox), typeof(RadComboBox));  
    }  
  
    public MyComboBox()  
    {  
        InternalFrameworkElement = new RadButton();  
  
        this.AddVisualChild(InternalFrameworkElement);  
    }  
    protected override int VisualChildrenCount  
    {  
        get  
        {  
            return InternalFrameworkElement == null ? 0 : 1;  
        }  
    }  
    protected override Visual GetVisualChild(int index)  
    {  
        if (InternalFrameworkElement == null)  
        {  
            throw new ArgumentOutOfRangeException();  
        }  
        return InternalFrameworkElement;  
    }  
    private RadComboBox ComboBox  
    {  
        get  
        {  
            return InternalFrameworkElement as RadComboBox;  
        }  
    }  
    public IEnumerable ItemsSource  
    {  
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }  
        set { SetValue(ItemsSourceProperty, value); }  
    }  
  
    public static readonly DependencyProperty ItemsSourceProperty =  
        DependencyProperty.Register(  
            "ItemsSource"typeof(IEnumerable), typeof(MyComboBox),  
            new FrameworkPropertyMetadata  
            {  
                PropertyChangedCallback = (obj, e) =>  
                {  
                    (obj as MyComboBox).UpdateItemsSource((IEnumerable)e.NewValue);  
                }  
            });  
  
    private void UpdateItemsSource(IEnumerable sel)  
    {  
        ComboBox.ItemsSource = sel;  
    }  
}  
 
(its much more elaborated, and I didn't copy all the code, but you get the basic idea)

B) Control templating: using Control as base class, we redefine the default styles of each control. The template (ControlTemplate) property is assigned to the telerik control. Then we create a TemplateBinding (or complete Binding, depends...) for each DP we want to expose. The DP is also created in the Control:
<Setter Property="Template">  
    <Setter.Value>  
        <ControlTemplate TargetType="{x:Type local:MyComboBox}">  
            <ControlsInput:RadComboBox Name="PART_MyComboBox"  
                BorderBrush="{TemplateBinding Property=BorderBrush}"  
                BorderThickness="{TemplateBinding Property=BorderThickness}"  
                Background="{TemplateBinding Property=Background}"  
                Foreground="{TemplateBinding Property=Foreground}"  
                SelectionBoxTemplate="{TemplateBinding Property=SelectionBoxTemplate}"  
                ItemTemplate="{TemplateBinding Property=ItemTemplate}"  
                SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor,   
                AncestorType={x:Type local:MyComboBox}}, Path=SelectedItem}"  
                ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,   
                AncestorType={x:Type local:MyComboBox}}, Path=ItemsSource}">  
            </ControlsInput:RadComboBox>  
        </ControlTemplate>  
    </Setter.Value>  
</Setter>  
(again, its much more elaborated)

C) Directly inheriting the telerik control. (we loose the req. 1, hiding attributes)

public class MyComboBox : RadComboBox  
{  
    static MyComboBox()  
    {  
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyComboBox), new FrameworkPropertyMetadata(typeof(MyComboBox)));  
    }  
}  


In summary:
- Solution A (wrapper) is somehow ugly, and uses a lot of tricks in order to do things such as:
    - Creating data bindings (from XAML)
    - Using CustomTemplates (from the final developer point of view)
    - Create data bindings from code behind.

- Solution B is more elegant (they are pretty much the same thing, as they generate the same logical tree for each control), but I'm not sure how difficult it will be to wrap complex controls, such as the GridView, Ribbon, etc.

- Solution C basically breaks with one of the initial requirements, but its still a valid approach. Besides, you can somehow suggest what properties to use by implementing the Extensibility Model for the WPF Designer.

My questions are:

    * What is the best approach, given the scenario I exposed?
    * Any other ideas/suggestions?


By the way, we need to provide the same control libraries for Silverlight and ASP.net, and it would be nice to use the same approach, at least with WPF and SL.

Thanks,


--
R.

2 Answers, 1 is accepted

Sort by
0
George
Telerik team
answered on 06 Jul 2010, 11:43 AM
Hello Roberto,

Thank you for your interest in our products.

My opinion is that the third approach (extending the controls and placing default styles for the new controls in your assembly) is the best one in your case.
Nevertheless the second one is still good when you need the functionality of more than one control to be combined and used together. Example for such scenario is if you have a DatePicker and TimePicker controls and you need a DateTimePicker control you might prefer creating a new control that aggregates both controls and adds some additional functionality.

Please pay attention that solution C) Directly inheriting the telerik control doesn't allow you to hide properties as you have as an initial requirement, but you can work around it by hiding these properties from the design-time (property grids, intellisense, etc.) As long as I understand correctly, the reason for hiding the properties is to make the controls more comfortable for use for your concrete purposes - this should be good enough for you. This can be achieved by adding design-time assemblies to your control assembly that will be used by Visual Studio and Expression Blend. For more information about design-time assemblies you could refer to the following article:  http://blogs.msdn.com/b/wpfsldesigner/archive/2010/01/13/wpf-silverlight-design-time-code-sharing-part-i.aspx.

Please do not hesitate to contact us if you require any further information.

Kind regards,
George
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Roberto
Top achievements
Rank 1
answered on 09 Jul 2010, 07:59 AM
Hi George,

I agree with you on using Design-time assemblies, although I'm not really familiar implementing them. After following the example you provided, it seems a little cumbersome to me, taking into account that it should also work in Blend: I will need a Design project for each design tool, and a Design base class, and perhaps more. In terms of implementation and maintenance of a decent number of Controls, and knowing pretty much all the details of "wrapping" (or "Control Templating") a control, we think its gonna be more convenient using those approaches rather than inheriting. Please let me know if you think our argument is incorrect (I'm not 100% convinced)

Thanks for your help,


--
R.
Tags
General Discussions
Asked by
Roberto
Top achievements
Rank 1
Answers by
George
Telerik team
Roberto
Top achievements
Rank 1
Share this question
or