Adding Auto Format for ASP.NET Custom Controls Design Time

Back to design time support, but this time with ASP.NET server controls, most complex & simple controls built in the .NET framework are associated with an Auto Format.. link in the smart tag as the one shown in the figure, I showed in a previous post how to add links and properties to the smart tag of a control.

autoLink  [more]

Ok, now when clicking that link a new window is popped out and you get a list of predefined formats on the left and a preview panel in the right like this.

AutoFormatWindow

Of course if you want to implement these features you will not have to design a new windows form and deal with all the head ache for previewing and those. You only will need some basic steps, I will show next, Assuming you already have your own custom control ( I will just use a simple LabelEx control for this sample);

1- Define your designer.

class LabelExDesigner : ControlDesigner
{

}

2- override the AutoFormats property and return some DesignerAutoFormats, to be used.

private DesignerAutoFormatCollection _autoformats = null;
public override DesignerAutoFormatCollection AutoFormats
{
    get
    {
        if (_autoformats == null)
        {
            _autoformats = new DesignerAutoFormatCollection();
            _autoformats.Add(new LabelExAutoFormat("Remove All"));
            _autoformats.Add(new LabelExAutoFormat("Reddish"));
            _autoformats.Add(new LabelExAutoFormat("Blueish"));
        }
        return _autoformats;
    }
}

3- Define a custom DesignerAutoFormat, which comes with an abstract Apply method, which is called when trying to apply a format on the preview control.

class LabelExAutoFormat : DesignerAutoFormat
{
    public LabelExAutoFormat(string name)
        : base(name)
    { }
    public override void Apply(Control control)
    {
        if (control is LabelEx)
        {
            LabelEx ctrl = control as LabelEx;
            switch (this.Name)
            {
                case "Remove All":
                    ctrl.ControlStyle.Reset();
                    break;
                case "Reddish":
                    ctrl.ControlStyle.ForeColor = ColorTranslator.FromHtml("#ff0000");
                    ctrl.ControlStyle.BackColor = ColorTranslator.FromHtml("#ffccff");
                    ctrl.ControlStyle.Font.Bold = true;
                    break;
                case "Blueish":
                    ctrl.ControlStyle.ForeColor = ColorTranslator.FromHtml("#0000ff");
                    ctrl.ControlStyle.BackColor = ColorTranslator.FromHtml("#99ccff");
                    ctrl.ControlStyle.Font.Italic = true;
                    break;
            }
        }
    }
}

4- And don’t forget to decorate the control with the designer attribute

[Designer(typeof(LabelExDesigner))]
public class LabelEx : Label
{ 
}

And now everything is set and you have your own auto formats.

Default format reddish auto format Blueish auto format

Here is the code and Happy Coding…

Extracting Icons from Files

Update: This approach is only to show one of the hidden gems in the .net framework and not to steal copyrighted icons.
Icons of other programs should only be used after owner approval.

Have you ever seen a file with a pretty icon you wanted to use but you couldn't get a similar one in your program?

If yes,  try this method >> Icon.ExtractAssociatedIcon here is the code I wrote that works fine, you will also find the sample attached

[code:c#]

Icon ico;

public Form1()
{
  InitializeComponent();
  ico = this.Icon;
}

private void btnGetIcon_Click(object sender, EventArgs e)
{
  if(dlgOpen.ShowDialog() == DialogResult.OK)
  {
    ico = Icon.ExtractAssociatedIcon(dlgOpen.FileName);
    this.Icon = ico;
    pnlIcon.Invalidate();
  }
}

private void pnlIcon_Paint(object sender, PaintEventArgs e)
{
  e.Graphics.DrawIcon(ico, pnlIcon.ClientRectangle);
}

[/code]

IconExtractor.zip (7.03 kb)

Exploring GDI+ : Using The Brush

Brush HierarchyOne of the core classes in the GDI+ framework built in .Net is the Brush class. There are 5 types of Brushes in .Net that help you to color your objects by lot of variations the five types are as shown in the figure :

 

[more] 

The 5 types as shown are :

SolidBrush Defines a brush of a single color. Brushes are used to fill graphics shapes, such as rectangles, ellipses, pies, polygons, and paths.
HatchBrush Defines a rectangular brush with a hatch style, a foreground color, and a background color.
LinearGradientBrush Encapsulates a Brush with a linear gradient.
PathGradientBrush Encapsulates a Brush object that fills the interior of a GraphicsPath object with a gradient.
TextureBrush Each property of the TextureBrush class is a Brush object that uses an image to fill the interior of a shape.

I have built a simple application that uses and shows the output of each brush, remember that options of each bursh is not limited to my sample, there are much more one can do using these brushes.

solid hatch linearGradient

pathGradient texture

Sample Application Code :

Exploring GDI+ Brushes.zip (13.24 kb)

The ASP.NET Configuration Model

ASP.NET as well as .NET applications have one more excellent feature, ASP.NET uses a flexible configuration management system that keeps the application configuration separate from application code. ASP.NET configuration is stored in XML files with the .config extension, which makes it easy for users to change it before, during and after deployment.

The configuration file we all are aware of is the web.config file found in the application root, which when added has almost very simple configurations. But guess what that is not the only configuration file that your ASP.NET application relies on, there are other config files that your application inherit that configuration by default, next I will show the Configuration Hierarchy in ASP.NET. [more]

Configuration Hierarchy

  1. Server settings – machine.config : This is at the root of the configuration hierarchy. It defines global, default settings for all of the applications on the(a) server. The machine.config is located in the Config folder for the version of the .NET Framework installed on the computer. In default installation will be found in this path C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config *.
  2. Root Web setting – web.config : This defines the default settings for ASP.NET applications on the(a) server, which inherits all the settings from machine.config. Can be located at C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG\web.config*.
  3. Web site settings – web.config : This file is the first optional file in the hierarchy it defines some settings that will be applied on all the ASP.NET applications within a website. For example, to set some default settings for all web applications in the Default Web Site that comes in the IIS, place a web.config file in this path C:\inetpub\wwwroot\web.config *.
  4. ASP.NET application root settings – web.config : This comes to be the web.config we all know that is found in the application root.This file is also optional.
  5. ASP.NET application subfolder settings – web.config : This file is found in subfolders of an application to set some specific settings on the pages contained in this folder. For Example, Admin folder needs an extra <authorization> setting to not allow non admins for accessing the folder.

NOTE : Although some of the settings in the machine.config file can be overridden by settings in the web.config file, other settings that apply to ASP.NET as a whole are protected and cannot be overridden.

Merging configuration at runtime

At runtime, all these settings are merged, all configuration settings are retrieved from the machine.config, then settings from the default web.config are then retrieved, new settings are add to those of the machine.config, changed settings override the orignal ones. And So on, for the rest of the config files.

Editing the web.config

It is highly recommended not to change the default settings in the machine.config and in the default web.config of a server, unless you know exactly what you are doing.
Example for changing, there is a default connectionString in the machine.config named LocalSqlServer, a lot of extensions and providers strongly rely on it, but this default connection string uses sqlexpress which is not preferred by a lot of developers which do not want to override it in every application they use, so you can change that.

Tools for editing Web.Config; Since the web.config is XML based there are many tools that can help reading and writing settings in it, like notepad , also there are tools that are made for the sake of editing the web.config. Example tools:

  1. Web Administration Tool : which enables easy and quick creation and editing web.config files for specific web application and subfolders. The web administration tool comes with Visual Studio 2005, 2008, It is found in the Project/WebSite menu usually the last item named
  2. My friend here found another tool that helps changing web.config file in a nice visual tree.

* These paths are the default when installing the visual studio

Custom Controls Design Time Support Part 15: Debugging Design Time

This is final part of my series/tutorial on design time support, it was really fun writing it and hearing your comments and suggestions, I really learnt alot and hope you too had some experience in writing design time support for the custom controls.

In this part, I will show you how to debug the design time code we are writing (works with vs 2005 and 2008).

[more]

Prerequisites:

  1. Have a solution containing the control.
  2. Configuration set to Debug.

Steps:

  1. Open that solution containing the control.
  2. Right click the project and select Properties.
  3. Select Debug Tab as in Figure.
  4. From Select Action Group select Start external program then browse the devenv.exe usually found in this path C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv.exeDebug Tab
  5. Save Settings.
  6. Place breakpoints where ever design time code should be called.
  7. Now Debug the project a new instance of Visual studio will open.
  8. Start a new project to be a container of the project (new web application to test a web control or a windows application for a windows control).
  9. Choose from the toolbox the control you already built ( Right click toolbox > Choose Items > browse for the dll of the control.)
  10. Now drag your control to the testing container and make any design time action (as using smart tag methods), the first instance will stop in breakpoints. Congratulations you are debugging design time code now.

That's the end of the series, but not the end of design time tips and tricks any one comes in my mind, I will be sure to include it in this blog under the category of Design Time Support.

Hope someone out there will benefit from this tutorial, please let me know if you need any help concerning this issue.

Custom Controls Design Time Support Part 14: Extra Property Tab

The default PropetryWindow in the visual studio shows 2 Tabs one for properties and another for events. If one day you thought that you have set of members might be Properties that you need to put them in an extra property tab then in this post you will learn how to put extra tabs.

When this can be useful?

After the ajax era has arrived and component authors started to build some ajax controls we usually see Properties named " ClientXXX " where xxx is the event name and these properties just appear in the properties tab while it would be more appropriate to show them in an extra tab say a Client side events.  [more]

How Can you do it?

You need to follow some steps.

  1. Create a Custom Tab that extends the System.Windows.Forms.Design.PropertyTab
  2. override the GetProperties method to send back the selected properties
  3. override the TabName property to set the name of the tab.
  4. override the Bitmap property to set the image of the tab button.
  5. Mark the control/component with PropertyTabAttribute and pass the type of the new Custom Tab.

In code:

[code:c#]

public class ExtraSuperTab : System.Windows.Forms.Design.PropertyTab
{
    public override PropertyDescriptorCollection GetProperties(object component, Attribute[] attributes)
    {
        PropertyDescriptor pd = TypeDescriptor.CreateProperty(component.GetType(), "XXX",typeof(int), new CategoryAttribute("Super Properties"));

        return (new PropertyDescriptorCollection(new PropertyDescriptor[]{pd}));
    }

    public override string TabName
    {
        get { return "Super Tab"; }
    }

    public override System.Drawing.Bitmap Bitmap
    {
        get
        {
            return (System.Drawing.Bitmap)System.Drawing.Image.FromFile(@"D:\icon.bmp");
        }
    }
}

[/code]

And in the control don't forget the attribute

[code:c#]

[PropertyTab(typeof(ExtraSuperTab), PropertyTabScope.Component)]
public partial class TestUserControl : UserControl

[/code]

How it looks at the end in visual studio. 

Extra Property Tab 

TestUserControl.cs (1.37 kb)

Custom Controls Design Time Support Part 13: Adding Snaplines

Another new feature added in the Design Time Environment in visual studio 2005 and 2008 for windows forms and windows user controls designers is the Snaplines.

What is a snapline?

A snapline is a dynamically generated UI layout guide line. Snaplines are generated during control move operations in the designer. The location of other controls on the design surface provide the lines.

All controls by default inherit the default the Snaplines which appear while moving that interact with Tops, Lefts, Bottoms and Rights of other controls, with the form border, spacings from other controls and some other. One remarkable snapline is the one that appears while moving a Label control beside TextBox controls the purple snapline that aligns the text position instead of the control position. [more]

Now using thr sample control I used in the previous part , I added two labels and two texboxes to simulate a Login control, like the following:

By default when placing this control on a windows form and start moving it around there are no snaplines to interact with the inner labels and textboxes in this sample I will show how to implement custom Snaplines for this usercontrol.

Steps:

1- Add a designer.

2- override Snaplines property and add your own custom ones.

[code:c#]

public override System.Collections.IList SnapLines
{
    get
    {
        IList snaplines = base.SnapLines; //get old snaplines and then add new ones
        snaplines.Add(new SnapLine(SnapLineType.Baseline, _control.lblUserName.Bottom));
        snaplines.Add(new SnapLine(SnapLineType.Baseline, _control.lblPassword.Bottom));
        return snaplines;
    }
}

[/code]

3- Don't forget to add the Designer attribute to the Control definition

[code:c#]

[Designer(typeof(UserControlDesigner))]
public partial class TestUserControl : UserControl

[/code]

The final looks as this.

Final look

So good luck and happy coding with custom controls design time.

UserControlDesigner.cs (7.70 kb)

Custom Controls Design Time Support Part 12: Adding SmartTag

One more advantage you get from building a custom designer for your custom controls is that you can add smart tag panel to add important most used properties and methods.

What is a Smart Tag?

aa

SmartTag is one of the new enhancement of VisualStudio 2005 design time and VS 2008 as well. Smart tags are menu-like user interface (UI) elements that supply commonly used design-time options. Most of the standard components and controls provided with the .NET Framework contain smart tag and designer verb enhancements. [more]

Some terminology before we start.

DesignerActionItem :  is a base class for all items on the Action List, a designer action item can be on of the following :

DesignerActionTextItem : Just an item with text does nothing used to give information only without any interaction with the user, can have a display name and a category.

DesignerActionHeaderItem : A special case of text item but written in bold , can have a display name and a category.

DesignerActionProeprtyItem : An item that represents a property, the property that is maps can have an Editor attribute to enhance the editing time (I talked about editors here and here), a property item has a Member Name (the property to me mapped), display name, category and a description (to be shown as a tooltip).

DesignerActionMethodItem : An item that represents a method, the method item has a constructor that accepts the DesignerActionList that the method will be added to, member name, display name, category, description and a boolean value to show this method as a designer verb(I talked about designer verbs here).

DesignerActionList: a collection of Items described above.

DesginerActionListCollection : a collection of Lists of items.

DesignerActionUIService: Manages the UI of the smart tag panel. Used to show, hide and refresh the panel when needed.

How to?

The sample I introduce here depends on the control I created the last two parts.

Add a designer.

Build a custom ActionList by extending the DesignerActionList class.

[code:c#]

public class UserControlDesignerActionList : DesignerActionList
{
     public UserControlDesignerActionList(UserControlDesigner designer)
          : base(designer.Component)
     {
          _designerActionUISvc = GetService(typeof(DesignerActionUIService)) as DesignerActionUIService;
          _controlDesigner = designer;
     }
}

[/code]

Put some properties and methods to be mapped by the action items.

[code:c#]

public Color BorderColor
{
    get
    {
        return _controlDesigner.BorderColor;
    }
    set
    {
        _controlDesigner.BorderColor = value;
        RefreshAll();
    }
}

public bool ShowBorder
{
    get { return _controlDesigner.ShowBorder; }
    set
    {
        _controlDesigner.ShowBorder = value;
        _designerActionUISvc.Refresh(this.Component);
    }
}

public Size Size
{
    get { return _controlDesigner.Control.Size; }
    set { _controlDesigner.Control.Size = value; }
}

public AnchorStyles Anchor
{
    get
    {
        return _controlDesigner.Control.Anchor;
    }
    set
    {
        _controlDesigner.Control.Anchor = value;
    }
}

public void MakeItRed()
{
    _controlDesigner.BorderColor = Color.Red;
    RefreshAll();
}

public void MakeItRandom()
{
    Random r = new Random();
    _controlDesigner.BorderColor = Color.FromArgb(r.Next(256), r.Next(256), r.Next(256));
    RefreshAll();
}

private void RefreshAll()
{
    _controlDesigner.Control.Refresh();
    _designerActionUISvc.Refresh(_controlDesigner.Component);
}

[/code]

And now override the GetSortedItems method a return a customized list.

[code:c#]

public override DesignerActionItemCollection GetSortedActionItems()
{
    DesignerActionItemCollection col = new DesignerActionItemCollection();

    DesignerActionHeaderItem hi = new DesignerActionHeaderItem("Border settings", "Border");
    col.Add(hi);

    DesignerActionPropertyItem pi = new DesignerActionPropertyItem("ShowBorder", "Show the border", "Border", "Check to show the border");
    col.Add(pi);

    if (ShowBorder)
    {
        DesignerActionPropertyItem pi2 = new DesignerActionPropertyItem("BorderColor", "Choose Color", "Border", "Choose a color from editor");
        col.Add(pi2);

        DesignerActionMethodItem mi = new DesignerActionMethodItem(this, "MakeItRed", "Make a Red border", "Border", "Click to change the border to Red", true);
        col.Add(mi);

        DesignerActionMethodItem mi2 = new DesignerActionMethodItem(this, "MakeItRandom", "Random Color", "Border", "Click to get a random border color", true);
        col.Add(mi2);
    }

    DesignerActionHeaderItem hi2 = new DesignerActionHeaderItem("Layout settings", "Layout");
    col.Add(hi2);

    DesignerActionPropertyItem pi3 = new DesignerActionPropertyItem("Size", "Size", "Layout", "Set the Size");
    col.Add(pi3);

    DesignerActionPropertyItem pi4 = new DesignerActionPropertyItem("Anchor", "Anchor", "Layout", "Choose anchor style from editor");
    col.Add(pi4);

    return col;
}

[/code]

Finally, get back to the Designer class and override the ActionLists property and an instance of our custom created ActionList.

[code:c#]

public override DesignerActionListCollection ActionLists
{
     get
     {
         DesignerActionListCollection d = new DesignerActionListCollection();
         d.Add(new UserControlDesignerActionList(this));
         return d;
      }
}

[/code]

And thats it. The final result looks like this.

Final result DesignerActionList

More on this : http://msdn2.microsoft.com/en-us/library/ms171829(VS.80).aspx

Download the sample source code UserControlDesigner.cs (7.16 kb)