Silverlight usercontrol inheritance

Demo and source code included below.
inheritance-monkies

At some point you think wouldn’t it be better to move all this functionality to  a super class ?
And right you are.
Since we all live in objectville it’s not so uncommon.

In my case I tried  to move some of the boring position functionality to a base control.
We all know that creating a basecontrol is peanuts.
But when we do this in a Silverlight control we run in some trouble.
Since our control lives in two files defined by two partial classes.
Partners in crime are the XAML file and the .cs (aka codebehind) file.

So when our .cs file inherits from basecontrol our XAML has to follow.
You probably think  so be it, no problem.
The problem occurs when you re-open that control in Expression Blend.
For no reason whatsoever Expression Blend kicks out the basecontrol.
If you don’t mind changing the XAML file every time you opened it in blend skip the rest of this post.

Method 1 : Inject your XAML friend into a new control

Create a basecontrol.
This sample basecontrol contains some methods and properties to move the control around in a easy way.
At line 19 we set the control which is the most important part in this code.

using System.Windows.Controls;

namespace InheritenceSample
{
    public class BaseControl
    {
        private UserControl userControl;

        public UserControl UserControl
        {
            get
            {
                return userControl;
            }
        }

        public BaseControl(UserControl userControl)
        {
            this.userControl = userControl;
        }

        public double Left
        {
            get
            {
                return (double) userControl.GetValue(Canvas.LeftProperty);
            }
            set
            {
                userControl.SetValue(Canvas.LeftProperty, value);
            }
        }

        public double Top
        {
            get
            {
                return (double)userControl.GetValue(Canvas.TopProperty);
            }
            set
            {
                userControl.SetValue(Canvas.TopProperty, value);
            }
        }

        public void MoveTo(double left, double top)
        {
            Left = left;
            Top = top;
        }
    }
}

Create a wrapper control which will contain the XAML control.
At line 7 we pass a new instance of our control containing the XAML into the constructor.

namespace InheritenceSample
{
    public class Monkey : BaseControl
    {

        // Set XAML file through the constuctor of the base file.
        public Monkey()
            : base(new MonkeyDesign())
        {
        }

    }
}

That’s it.

Advantage:

  • This method is very good when creating an application or game which makes heavy use of multiple XAML files which or focused on design.
  • You can change between multiple designs (XAML files) by just changing the usercontrol property.

Disadvantage:

  • You need to create a extra file foreach control.
  • The usercontrol is only accessible throught the UserControl property

Method 2 : Strategy pattern

Our second method makes use of the well known strategy pattern and design pattern rule “Composition over Inheritance”.
Create an interface which defines the helper class.

using System;
namespace InheritenceSample.Interfaces
{
    public interface IPosition
    {
        double Left { get; set; }
        void MoveTo(double left, double top);
        double Top { get; set; }
    }
}

Create the helper class

using System.Windows.Controls;
using InheritenceSample.Interfaces;

namespace InheritenceSample.CompositionSample
{
    public class PositionHelper : IPosition
    {
        private UserControl userControl;

        public PositionHelper(UserControl userControl)
        {
            this.userControl = userControl;
        }

        public double Left
        {
            get
            {
                return (double) userControl.GetValue(Canvas.LeftProperty);
            }
            set
            {
                userControl.SetValue(Canvas.LeftProperty, value);
            }
        }

        public double Top
        {
            get
            {
                return (double)userControl.GetValue(Canvas.TopProperty);
            }
            set
            {
                userControl.SetValue(Canvas.TopProperty, value);

            }
        }

        public void MoveTo(double left, double top)
        {
            Left = left;
            Top = top;
        }

    }
}

Hang on we are almost there.
To use this helper we need to add it to our control.

using System.Windows.Controls;
using InheritenceSample.Interfaces;
using InheritenceSample.CompositionSample;

namespace InheritenceSample
{
	public partial class MonkeyDesign2 : UserControl, IPosition
	{
        public IPosition position;

		public MonkeyDesign2()
		{
			// Required to initialize variables
			InitializeComponent();
            position = new PositionHelper(this);
            txtBaloon1.Text = "Arrived here through the stragey pattern";
		}

        public double Left
        {
            get
            {
                return position.Left;
            }
            set
            {
                position.Left = value;
            }
        }

        public void MoveTo(double left, double top)
        {
            position.MoveTo(left, top);
        }

        public double Top
        {
            get
            {
                return position.Top;
            }
            set
            {
                position.Top = value;
            }
        }
    }
}

Advantage:

  • When using composition its easy to change the position behavior at runtime.
  • Using composition over inheritance decouples your classes

demodownload

6 Responses to “Silverlight usercontrol inheritance”

  1. Raghuraman says:

    Don’t know why nobody has yet commented here.

    Thanks for a Nice Write UP !!!

  2. Jason says:

    Very nice, indeed, thanks.

  3. Bastien BESSON says:

    I think there is a better option now :

    This solution take in account that your base class is in another project ( let say your Framework ), but of course work also if in the same project, with the same processus ( it’s just to show that it is possible too ).

    Home.Xaml :

    For adding the possibility of using the base class, add a “xmlns” to the property of your UserControl, Intellisense will give you automatically all the namespace you have in your project and dll, just choose the one where your HomeBase is, and you’ll have something like :

    xmlns=”clr-namespace:Framework;assembly=Framework”

    Then add it a name to use it in the Xaml File :

    xmlns:Base=”clr-namespace:Framework;assembly=Framework”

    Finally change your to something like where HomeBase is your base class and Base the name you gave to your xmlns reference.

    Here is what you should have =>

    Home.Xaml.cs :

    namespace SilverlightApplication
    {
    public partial class Home : HomeBase
    {

    }

    }

    And it’s done ;)

    Rmk : If you use Expression Blend 3, be aware that using abstract class as Base will make Blend unable to display your Xaml file ( even if all works fine .. ), and you need to create a default Constructor without parameter too or again, Blend won’t display your xaml file.

  4. Kris Meeusen says:

    Hey Bastien,

    Thx for the solution.
    It’s an older blog post so I didn’t check if the problems still exists in Blend 3

  5. SLMaster says:

    Yes, Blend 3 also cannot display abstract classes.
    But don’t bother with it, just remove the abstract keyword:)

  6. [...] cannot be written directly in xaml? There is a workaround: 1. Use a wrapper, described here 2. Create a new non-generic class, like in this sample: xaml <v:MyViewBase [...]

Leave a Reply


lab101 is proudly powered by WordPress
Content and design by Kris Meeusen
Entries (RSS) and Comments (RSS).