Critical Development

Language design, framework development, UI design, robotics and more.

Compact Framework Controls (Part 1): Creating Custom Controls and Designers

Posted by Dan Vanderboom on March 14, 2008

I’ve been having a lot of fun learning how to create rich design-time experiences for custom controls in Compact Framework for the past few days.  It’s been frustrating, and the documentation is hard to find unless you’re already familiar with the metaphors and know the buzzwords.  While this first article won’t be completely comprehensive, I will continue to write about this topic until I have covered all of the bases necessary for you to create professional, polished controls and design-time experiences suitable for commercial use or sale.

I’m going to assume you have at least some experience in creating custom controls, at least for desktop applications.  Creating custom controls for Compact Framework applications is another story, however.  Not because of any particular constraints of memory of screen real estate, but because the typical method for attaching metadata to specify design-time behavior is different.  There are some other subtleties and oddness as well that are specific to the Compact Framework.

In the full .NET Framework, we have many attributes at our disposal to specify design-time behavior; most of these can be found in System.ComponentModel.  We have access to a lot of these for mobile device applications, but because they’re not included in the Compact Framework, we need another way to associate them with our control classes and their members.  This is done through something called the “design-time attributes file”, which has an extension of .xtma.

There are two ways to add this file.  The method that people typically suggest is to add a class diagram to your project (right-click on your project in Solution Explorer, and select View Class Diagram), select an item in the diagram, edit the Custom Attributes property in the property grid (see screenshot below), click on the ellipsis (…) to open a pop-up window, and then enter an attribute such as DesktopCompatible(true).

Custom Attributes in properties

When you click the OK button, a new file will be added to your project called DesignTimeAttributes.xtma, and this file will open in Visual Studio.

This is quite a round-about way to create the file in my opinion, and it presumes that you know a valid attribute to add right from the beginning.  I personally don’t use the class diagrams, and I think it’s easier just to add the .xtma file directly, by right-clicking on your project in Solution Explorer, Add—New Item, and selecting Design-Time Attribute File.  Editing your attributes directly in this XML file instead of the pop-up window in the class designer has the benefit of providing you with some Intellisense (which it gets from the associated XSD file).

I get a little disappointed when I see people list only the most common attributes that I already know about, and then fail to mention the rest of the attributes that are supported in Compact Framework, and since the list isn’t unmanagable—and easily determined from Intellisense—I will list most of them that are supported .xtma file here, and in a future artile will provide the remaining ones.

Here’s a screenshot showing the full list of tags that you can use at the class level.  Most of them are attributes, while some of them like Event, Method, and Property allow you to specify specific members of the class so that you can apply attributes to just those members.

 Xtma attributes

This is what they mean:

  • ApplyDeviceDefaults – I couldn’t find any mention of this in the normal area of MSDN that enumerates all of the classes, but I did find it explained well in this MSDN article.
  • ComplexBindingProperties – For complex data binding, of course.
  • DefaultBindingProperty – This is for simple data binding.
  • DefaultEvent – The default event for Button is Click.  When you double-click on a control in the designer, Visual Studio switches to the code behind file and will automatically generate this event’s handler for you.  Very handy.
  • DefaultProperty – When you select a control in the designer, this is the property in the properties window that gets focus first.  For the Label control, this is the Caption property.
  • Description – The description text appears in the properties window below the grid of property names and values, and can provide useful information about the meaning of a property or event.
  • Designer – The Designer attribute is one of the primary gateways for providing rich design-time experiences for your controls.  Creating custom designers and associating your controls with them is a tricky business, and one I intend to explore in depth in this and future articles.  Because MSDN documentation in this area is rather sparse, I’ve begun contributing to the community content on the MSDN pages, and you’ll see the help I’ve added at the very bottom of the page if you follow the link for this item.
  • DesignerSerializer – Located in System.ComponentModel.Design.Serialization, a DesignerSerializer is used to provide a custom way of serializing your control to code in the designer partial class file.  I haven’t had a need yet to use this, but if someone can think of a real-world scenario that requires it, I will be happy to explore the subject further and write about it.
  • DesignTimeVisible – Indicates whether a control can be shown on a designer, and is supposedly ignored by “components with a UI presense”, whatever that means.  A little more usefully, MSDN states that it is useful when you have a control that accepts child components, such as the TreeView whose node items “should not appear in the component tray because they are drawn by the TreeView control”.  This will require some more exploration.
  • DesktopCompatible – This is the first design-time attribute I became familiar with in working with Compact Framework controls.  If you have a control that makes P/Invoke calls, Visual Studio is uncertain whether they’re device specific OS calls, and to be safe, it doesn’t execute your control’s code, which means your control can’t render itself even on the designer surface.  You get a message telling you that it’s unsafe.  To get around this, and presuming that it is indeed safe to run your control’s code on the desktop (I’ll explain more about this later, or you can read this article by XinYan), just add a DesktopCompatible attribute to the control class, and you’ll be back in business.  I’m not sure where this attribute is located; it’s not a desktop attribute, so it’s not in the full .NET Framework’s System.dll, and a search through Reflector didn’t locate it, so I’ll have to keep looking.  But it’s there, and it works.
  • Docking – Specifies the default docking behavior for controls.  This is located in System.Windows.Forms.
  • Editor – If you need a more powerful experience for editing complex properties within the properties window itself, this attribute will allow you to hook into one.  I’ll be covering over custom editors in detail.
  • ImmutableObject – Specifies that an object has no subproperties capable of being edited, per MSDN documentation.  Not sure what the benefits of that would be: perhaps to hide all properties for a class without having to hide each one separately?
  • InitializationEvent – This is used to support auto data-binding (by Visual Studio wizards I’m guessing), so it knows which event to hook into when generating the data-binding code.
  • LookupBindingProperties
  • RootDesignerSerializer – I’m not sure what this was for originally, but according to bug report, this attribute is both deprecated and broken.
  • Supported – Explained in this blog as part of Platform Verification Task.  Located in Microsoft.CompactFramework.Build.Tasks.  You can use this attribute to indicate that a class or member is not supported for the specific platform.
  • SuppressFiltering – Located in Microsoft.CompactFramework.Build.Tasks.
  • ToolboxBitmap – This simply specifies the bitmap that will be displayed in the toolbox.  Located in System.Drawing.
  • TypeConverter – Specifies the TypeConverter class used for a property.  TypeConverters are an important aspect of the design-time experience and merit further explanation.
  • Browsable – This determines whether a property or event will be displayed in the properties window, and is typically used to hide properties or events that must be public for some reason but aren’t meant to be manipulated during design time.
  • Category – If you set this to an existing category name, your property or event will appear in there; if you create your own category name, a new category will appear in the properties window.

There are a few more that are specific to properties, events, and methods, but this will give us a good start.  I’ll cover the remainder in future articles.

That seems like a lot at first glance, but chances are that you’ll only need a handful at any given time.  With a little exploration and practice (and guidance from myself and others whose blogs and other resources I’ll share), you could soon be a master of rich, no-compromise custom control development for Compact Framework applications.  I believe this is a worthy cause, for one because there is a scarcity of good third-party controls, especially when compared to the abundance that we have for the desktop world of .NET development; but also because I have personally struggled with Compact Framework development and have always thought it would be nice to have a step-by-step series of tutorial to follow for creating custom controls.  I’ve found many useful and helpful articles, but nothing that really brings it all together in a clear manner.

Here is an example .xtma file for a new user control I created that has Category and Description attributes on a property I created called HighlightForeColor:

XTMA

The magic happens when you build your custom control project.  Visual Studio builds not only your control project in its runtime form, but also generates another assembly with .asmmeta.dll after your own target assembly name.

Build output

If you use Reflector to disassemble it, you will see that this is a design-time component that contains all of your classes and their members with real attributes attached.  Strangely, it does not contain any code, and parameters have no names.  The purpose is simply to be a carrier of attributes.  This is a screen shot from Reflector, showing the attached attributes:

Reflector

I’m puzzled by this implementation detail.  Attributes are so insignificant in size, being just metadata tags.  If Microsoft had just included them in the Compact Framework, it seems they could have avoided the requirement for this second, oddly-empty assembly (and there is a third, for custom designers and editors, as you’ll see later).  Unless there’s something else to it that I’m missing…

[This article is part of a series that continues in this article.]

10 Responses to “Compact Framework Controls (Part 1): Creating Custom Controls and Designers”

  1. Caroline said

    Hello,

    Thanks for the excellent article is seems to be quite difficult to find information about implementing design time functionality for custom controls in the compact framework. I’m currently in the process of trying to create a control that holds a collection of buttons and am having quite a lot of difficulty trying to figure out how to add buttons to my collection at design time.

    I believe that in a windows forms application I would need to create a TypeConverter and CollectionEditor for my collection but when I tried to create a TypeConverter for my buttons I discovered that the methods I need to override are not available in the compact framework. If you know anything about how I could do this I would be most grateful of any help.

    Thanks.

  2. Jan said

    Cool! Many thanks, I was looking for some good explaination and a starting point – both covered by your articles.

  3. LosManos said

    hejdig.

    .xmta, not xtma

    In Vsnet2008 (at least on my machine) the xmta file is not created when adding an attribute through the class diagram designer.

    Make a backup before playing with this because the designer file can be wrecked and it might take some time to repair it again…

    Happy hacking!

    /OF

  4. DesignerSerializer – let’s say your custom control initializes its property by creating a new object by calling its constructor. Now let’s say that the class of that property has several constructors. The default designer serializer will use – well – the default constructor. But if you do not want it to use the default constructor, you have to provide your own designer serializer. Or let’s say you do not want the property to be initialized with an object of the same class as the class of that property, but rather with a derived class – again – use your own designer serializer.

    Great article, by the way. If you plan to write an article about custom designer serializer, I’d be happy to read it, as it seems to be a rather complicated topic for me. The custom designer serializer allows you to specify what pieces of code should be generated by Visual Studio and it’s seems tricky to me.

  5. Ed Eaglehouse said

    Wow, one of the best descriptions to work around .NET CF’s deficiencies I’ve run across. Thank you so much for sharing your insight!

    I found some additional background information about the extra design-time assembly and attributes in a Microsoft article Creating and Migrating Smart Device Custom Controls by Using Visual Studio 2005. I’ve seen no mention of this in the documentation that comes with VS, of course.

  6. Tobias said

    what is really missing here, is the DefaultValue XMTA attribute!

    it took me some time to figure out that I have to use fully qualified
    assembly name…

    finally, this works:

    System.Drawing.Size, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
    100, 20

  7. Tobias said

    In the previous post I used the wrong formatting for the XML sample, sorry for that.
    Here we go:

    <Property Name="Size">
      <DefaultValue>
        <Type<System.Drawing.Size, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a<⁄Type>
        <Value>100, 100<⁄Value>
      <⁄DefaultValue>
    <⁄Property>

  8. Good work buddy, keep writing.

  9. Véro said

    Je n’ai pas réussi à visiter votre blog cette semaine… C’était mon provider, ou bien une panne de votre côté ? En tous cas, article intéressant, comme d’habitude…

  10. stickers said

    stickers…

    […]Compact Framework Controls (Part 1): Creating Custom Controls and Designers « Critical Development[…]…

Leave a comment