in Silverlight

Silverlight 2 (beta1): User Control Inheritance

We have been discussing about how to inherit a Silverlight page or Silverlight control from the base class lately in Silverlight Forum. (You can read our discussions here, here, here and here.) As the most of .NET developers have the ASP.NET background, we all want to have the base class/master page that can be inherited from other controls. Unlike ASP.NET Master Page, it’s a lit bit tricky to do inheritance in Silverlight. In this post, I’m gonna give you the step-by-step guide for that.

User Control Inheritance in Silverlight

Note: As you know, you can change the name as you like but I will use the following names in my sample.

1. Create new silverlight project called “SL2Controls”

2. Add a class called BaseControl

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SL2Controls {
public class BaseControl : UserControl {

}
}

3. Add Silverlight User control called “InheritedControl”

XAML


<BaseControl x:Class="SL2Controls.InheritedControl"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="Red">

</Grid>
</BaseControl>

C#


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SL2Controls {
public partial class InheritedControl : BaseControl {
public InheritedControl() {
InitializeComponent();
}
}
}

4. Add mapping in AssemblyInfo.cs under Properties of SL2Controls


using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Markup;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SL2Controls")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SL2Controls")]
[assembly: AssemblyCopyright("Copyright ©  2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/client/2007", "SL2Controls")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("27885afb-0308-473e-9773-73350bc1555f")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

5. Add this Inherited control to Page.xaml.


<UserControl x:Class="SL2Controls.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myctl="clr-namespace:SL2Controls"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<myctl:InheritedControl/>
</Grid>
</UserControl>

then, run the application. (You don’t need to update *.g.cs file.)

Download Source: http://michaelsync.net/demo/SL2Controls.zip

There is one weakness in this trick. You will lost the designer in InheritedControl.xaml but you won’t get any error. If you want to know how to do for Silverlight page, you can read the second post in this link.

Yes. As we all are new to Silverlight 2 beta1, we probably need to explore more thing about it. Feel free to discuss with me if you have any comment or suggestion.

Update: If you don’t add namespace mapping in assembly, I think it will be working fine. but this is a known issue that will fix in next release. Yi-Lun from Microsoft said as below ~

Hello, there’re some issues related to UserControl inheriting that we’re investigating… I’m surprised to see this works:

<MyUserControlBase x:Class=”SL2Test.Page”
xmlns=”http://schemas.microsoft.com/client/2007″
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400″ Height=”300″>
<Canvas Width=”400″ Height=”300″ Background=”Red”>
</Canvas>
</MyUserControlBase>

Actually it shouldn’t work. MyUserControlBase is not in the namespace http://schemas.microsoft.com/client/2007. This xml namespaces maps to a series of clr namespaces such as System.Windows.Controls. But there’s no way it can map to your own namespace. Also this behavior is inconsistent with WPF.

This is likely to be a bug. I’ll redirect this to our product team. Thanks for letting us know.

You’re right. This can be a work round.

In the class library project’s AssemblyInfo.cs file, add this:

[assembly: XmlnsDefinition(“http://schemas.microsoft.com/client/2007″, “YourNamespace”)]

Now after you add reference to this assembly in your main project, you can use any classes in this namespace in your XAML files.

But without the namespace mapping, your original code should not work. So this still seems to be an issue…

Leave a Reply

20 Comments

  1. Hi Michael,

    In my project I have a main UserControl (as a MasterPage which contains other XAML pages), this main UserControl inherits a custom class (which inherits UserControl) which will contain my common methods, like your topic. From what I read on silverlight.net forums (and here) a modification of AssemblyInfo is required but I didn’t and it’s work fine. The line
    [assembly: XmlnsDefinition(“http://schemas.microsoft.com/client/2007″, “MyNamesapce”)] is only necessary if the BaseControl is located in an other Assembly no ?

    NOTE:
    I guess you copy/paste what you wrote in silverlight.net forums, and you have a mistake on this article :

    you have any tags in the article, that can be confuse for beginners.

    I didn’t know the assembly stuff

  2. >>you have any tags in the article, that can be confuse for beginners.

    oops.. thanks.. :)I have fixed it.

    >>AssemblyInfo is required but I didn’t and it’s work fine.

    Yes. because it’s known issue. If you read the links from my post, I did it without namespace mapping in assembly. It’s working fine. but Yi-lun from MS said that i should not do that way and I should add namespace mapping in assembly.

  3. Your project is working fine, but when I’m using the same code in my project I receive
    Error 1 ‘SilverlightApplication.PageIn2′ does not contain a definition for ‘FindName’ and no extension method ‘FindName’ accepting a first argument of type ‘SilverlightApplication.PageIn2′ could be found (are you missing a using directive or an assembly reference?) SilverlightApplication\obj\Release\PageIn2.g.cs 50
    Code in PageIn2.g.cs is”
    namespace SilverlightApplication {

    public partial class PageIn2 : BaseClass {

    internal System.Windows.Controls.Grid LayoutRoot;

    private bool _contentLoaded;

    ///
    /// InitializeComponent
    ///
    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
    public void InitializeComponent() {
    if (_contentLoaded) {
    return;
    }
    _contentLoaded = true;
    System.Windows.Application.LoadComponent(this, new System.Uri(“/SilverlightApplication;component/PageIn2.xaml”, System.UriKind.Relative));
    this.LayoutRoot = ((System.Windows.Controls.Grid)(this.FindName(“LayoutRoot”)));
    }
    }
    }
    and in PageIn2.xaml.cs
    namespace SilverlightApplication
    {
    public partial class PageIn2 : BaseClass
    {
    public PageIn2()
    {
    InitializeComponent();
    }
    }
    }
    and in AssemblyInfo.cs is:
    [assembly: AssemblyTrademark(“”)]
    [assembly: AssemblyCulture(“”)]
    [assembly: XmlnsDefinition(“http://schemas.microsoft.com/client/2007″, “SilverlightApplication”)]

  4. Hello Elena,

    Normally, we don’t use FindName in Silverlight 2. Visual Studio will generate those codes automatically. For example: If we add the textbox in Page.xaml, we can just call the name of this textbox in Page.xaml.cs right away. no need to use “FindName”.

    Could you please follow the steps that I mentioned? Please let me know which step you got the error…

  5. The code in “PageIn2.g.cs” with “FindName” is autogeneratad, as you mensioned. I only changed partial class definition from “public partial class PageIn2 : System.Windows.Controls.UserContro” to “public partial class PageIn2 : BaseClass”. Any way after every rebuild file “PageIn2.g.cs ” is rebuild again in old way. It looks as line “[assembly: XmlnsDefinition(“http://schemas.microsoft.com/client/2007″, “SilverlightApplication”)]” doesn’t work from some reason.

  6. Hello,

    So, you are using PageIn2 instead of “InheritedControl”?

    Example:

    public partial class PageIn2 : BaseControl ??

    Have you changed “UserControl” to BaseControl in PageIn2.xaml?

    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">

  7. Excellent post, very helpful.

    However I have one more question, how can I add the controls dynamically in the base class (BaseControl)?

    There isn’t a this.Children.Add() as it’s a UserControl and I get a null value when I call Application.Current.RootVisual

    What am I missing?

    Thanks

  8. Why do you want to add the controls dynamically to the base class? As you know, there is no XAML in base class.. so, your control won’t be shown anyways..

  9. I knew that you couldn’t have a XAML file attached to the base class but I did think I read something somewhere in the Silverlight forms that you could add Controls dynamically to the base class (but there was no example).

    The reason why is because I want to extend the functionality of my UserControl. I’ve created a Silverlight application that has a UserControl that has a bunch of child custom UserControls and it does a bunch of things. I now want to create administration functionality for my application and take that base UserControl and add more functionality and child UserControls to it.
    I can’t just re-write the UserControl, because the child UserControls depend on the parent being of a specific type with some menthods. So if I re-write one I have to re-write them all and then I have a lot of duplicated code.

  10. hi,i have same question,

    I have create BaseControl in a silverlight class library,then create a User Control Inheritance from BaseControl ,but the user control is in other project(a silverlight application) who reference to this class library,then we i build the project,VS modify the usercontrol.g.cs change the baseControl back to UserControl…

  11. did think I read something somewhere in the Silverlight forms that you could add Controls dynamically to the base class (but there was no example).

    Can you please give me the link? Normally, I used to read the most of messages in Silverlight forum..

    The reason why is because I want to extend the functionality of my UserControl.

    As you already know, we can’t add XAML in base control. This is the main thing.

    Example #1:

    Let’s say you have created one base class that has a function called validatedUser(string,string). Then, you create another class that inherits from base class and you can comsume that functionality. then, it’s possible to do in Silverlight..

    Example #2:

    Let’s say you have created one base class that has a button. (You can’t have XAML so that it won’t show on Designer anyway.) then, you create another class that inherit from that base class.. but the button that you created in Base control won’t be shown. that’s why I’m wondering why you need to do that..

    I have create BaseControl in a silverlight class library,then create a User Control Inheritance from BaseControl ,but the user control is in other project(a silverlight application) who reference to this class library,then we i build the project,VS modify the usercontrol.g.cs change the baseControl back to UserControl…

    Please check two things

    1)
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">


    You should use BaseControl instead of User Control.

    2) public partial class InheritedControl : BaseControl {

    Your class should be inherited from BaseControl.

  12. I downloaded your project, ran it straight from the box, and received this error: Unknown element: BaseControl.

    In the InheritedControl designer, the BaseControl tag is not recognized.

  13. I have this same thing happening, in Silverlight RC1.
    Is there a new fix??

  14. I just tested with latest version of Silverlight. it wasn’t working. Here are the steps to do with SL2 release version.

    1. Create BaseControl

    2. InheritedControl

    3. (No need to update XmlnsDefinition in AssemblyInfo.cs)

    4. Add this line xmlns:local=”clr-namespace:SL2Controls” in InheritedControl.xaml

    5. Use local:BaseControl instead of UserControl in InheritedControl.xaml

    6. You can write Button Content=”Click Me Quick” Click=”Button_Click” in XAML. It will work.

  15. Excellent Michael,

    your last comment (Feb 27 2009) worked perfectly with Silverlight 2.

    Thank you for sharing this.

  16. Is it also possible to set a theme in the base class en let all the inherited sites use that theme? i searched but could not find anything.
    I also noticed that the themes are not yet working in Blend but they are working in visual studio. does anyone have a solution for this?