Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design Custom TabPage in C# WinForms?

I have a c# WinForm application that I need to generate TabPages at runtime. Ideally, I would like to design these tabpages using VS designer, but it seems that I can't directly do that as I can't drag and drop it from the toolbox (is there another way?).

I have two generic tabpages that I will be using multiple times. One that contains a simple spreadsheet and a couple textboxes and another with a graph and a couple textboxes. These pages will eventually get more complicated. I'm looking for the best method of doing this. I am presently just creating custom classes for each tab page and setting it as a TabPage base class. For example:

public partial class SpreadsheetTabPage : TabPage{} 

I read that user controls offer some form of an alternative, but I don't really understand the advantages of using it vs. my method.

So to be clear, I want to know what you think is the best approach to developing these custom tabpages and why. Please provide a basic code example if relevant. My method is not really causing too much problems, but I see adding things to these pages later on will be difficult, particularly without use of the designer.

Thanks for your help in advance!

like image 773
ImGreg Avatar asked Mar 02 '12 14:03

ImGreg


3 Answers

You can create your own TabControl designer, and implement the functionality you need at design time. Here is the code of the simplest version of such designer:

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.ComponentModel.Design;
using CustomTabControlExample.TabControl;

namespace CustomTabControlExample.Design {
    public class CustomTabControlDesigner :ParentControlDesigner {
        DesignerVerbCollection fVerbs;
        public override DesignerVerbCollection Verbs {
            get {
                if (fVerbs == null)
                    fVerbs = new DesignerVerbCollection(new DesignerVerb[] {
                        new DesignerVerb("Add Tab", OnAdd)
                        });
                return fVerbs;
            }
        }

        void OnAdd(object sender, EventArgs e) {
            TabPage newPage = (TabPage)((IDesignerHost)GetService(typeof(IDesignerHost))).CreateComponent(
                typeof(CustomTabPage));
            newPage.Text = newPage.Name;
            ((System.Windows.Forms.TabControl)Component).TabPages.Add(newPage);
        }

        public override void InitializeNewComponent(IDictionary defaultValues) {
            base.InitializeNewComponent(defaultValues);
            for (int i = 0; i < 2; i++)
                OnAdd(this, EventArgs.Empty);
        }

        protected override void WndProc(ref Message m) {
            base.WndProc(ref m);
            // Selection of tabs via mouse
            if (m.Msg == 0x201/*WM_LBUTTONDOWN*/) {
                System.Windows.Forms.TabControl control = (System.Windows.Forms.TabControl)Component;
                int lParam = m.LParam.ToInt32();
                Point hitPoint = new Point(lParam & 0xffff, lParam >> 0x10);
                if (Control.FromHandle(m.HWnd) == null) // Navigation
                    if (hitPoint.X < 18 && control.SelectedIndex > 0) // Left
                        control.SelectedIndex--;
                    else control.SelectedIndex++; // Right
                else // Header click
                    for (int i = 0; i < control.TabCount; i++)
                        if (control.GetTabRect(i).Contains(hitPoint)) {
                            control.SelectedIndex = i;
                            return;
                        }
            }
        }

        protected override void OnDragDrop(DragEventArgs de) {
            ((IDropTarget)((System.Windows.Forms.TabControl)Component).SelectedTab).OnDragDrop(de);
        }

        protected override void OnDragEnter(DragEventArgs de) {
            ((IDropTarget)((System.Windows.Forms.TabControl)Component).SelectedTab).OnDragEnter(de);
        }

        protected override void OnDragLeave(EventArgs e) {
            ((IDropTarget)((System.Windows.Forms.TabControl)Component).SelectedTab).OnDragLeave(e);
        }

        protected override void OnDragOver(DragEventArgs de) {
            ((IDropTarget)((System.Windows.Forms.TabControl)Component).SelectedTab).OnDragOver(de);
        }
    }
}

This seems like a quite a complex way, but once you learn it, you will be impressed by powerful capabilites provided by Visual Studio. You can find a lot information in the MSDN. Here are described most common features: Enhancing Design-Time Support

like image 100
Uranus Avatar answered Nov 01 '22 02:11

Uranus


I came across this thread with the same question in mind. After thinking about the problem I realized the solution was staring me in the face. It is actually pretty basic and elegant.

What I did was created a UserControl called TabPageLibrary. Accordingly I dragged a TabControl on it and Added Pages based on the set up I wanted. I then set the TabPage modifier to internal. When I needed a specific extended TabPage - I would simply call the TabPageLibrary class and grab the TabPage I need for a specific application. This gave me the ability to reuse a specific pre-configured TabPage throughout the winform application

private void PropertiesButton_Click(object sender, EventArgs e)
{
TabPageLibrary library = new TabPageLibrary();
TabPage propertyPage = library.PropertyPage;
this.tabControl.TabPages.Add(propertyPage);
}

This certainly solved my problem -- perhaps it will work for your application.

like image 32
Sean Mc Avatar answered Nov 01 '22 01:11

Sean Mc


If you make a user control that contains your tabcontrol you can see the designer and design it as you like, and you can add some additional code, and still can drag & drop it from toolbox to use it.

Note: you can't see you user control (neither your manually coded class) untill you Rebuild your project

like image 3
Amen Ayach Avatar answered Nov 01 '22 01:11

Amen Ayach