Дизайн пользовательской вкладки в C# WinForms?

У меня есть приложение c# WinForm, которое мне нужно создать вкладки во время выполнения. В идеале я хотел бы создать эти вкладки с помощью VS designer, но кажется, что я не могу напрямую сделать это, поскольку я не могу перетащить его из панели инструментов (есть ли другой способ?).

У меня есть две общие вкладки, которые я буду использовать несколько раз. Один из них содержит простую электронную таблицу и пару текстовых полей, а другой-график и пару текстовых полей. Эти страницы в конечном итоге получат посложнее. Я ищу лучший способ сделать это. В настоящее время я просто создаю пользовательские классы для каждой вкладки и устанавливаю его как базовый класс TabPage. Например:

public partial class SpreadsheetTabPage : TabPage{} 

Я читал, что пользовательские элементы управления предлагают некоторую форму альтернативы, но я действительно не понимаю преимуществ использования его против моего метода.

чтобы быть ясным, я хочу знать, что вы считаете лучшим подходом к разработке этих пользовательских страниц и почему. Пожалуйста, предоставьте базовый пример кода, если это необходимо. Мой метод на самом деле не вызывает слишком много проблем, но я вижу, что добавление вещей на эти страницы позже будет сложно, особенно без использования дизайнера.

Спасибо за вашу помощь заранее!

3 ответов


Если вы создадите пользовательский элемент управления, содержащий ваш tabcontrol, вы можете увидеть дизайнера и спроектировать его, как вам нравится, и вы можете добавить дополнительный код, и все еще можете перетащить его из toolbox, чтобы использовать его.

Примечание: вы не можете видеть, как вы управляете пользователем (ни ваш кодированный вручную класс), пока вы восстановить проект


вы можете создать свой собственный конструктор TabControl и реализовать необходимые функции во время разработки. Вот код самой простой версии такого конструктора:

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);
        }
    }
}

Это кажется довольно сложным способом, но как только вы его узнаете, вы будете впечатлены мощными возможностями, предоставляемыми Visual Studio. Вы можете найти много информации в MSDN. Здесь описаны наиболее распространенные особенности:Расширение Поддержки Времени Разработки


я наткнулся на эту ветку с тем же вопросом в голове. Поразмыслив над проблемой, я понял, что решение стоит передо мной. Это на самом деле довольно простой и элегантный.

то, что я сделал, было создано UserControl под названием TabPageLibrary. Соответственно, я перетащил на него TabControl и добавил страницы на основе настройки, которую я хотел. Затем я установил модификатор TabPage в internal. Когда мне нужна конкретная расширенная страница табуляции - я просто вызову класс TabPageLibrary и возьмите TabPage мне нужно для конкретного приложения. Это дало мне возможность повторно использовать определенную предварительно настроенную страницу табуляции во всем приложении winform

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

это, безусловно, решило мою проблему - возможно, это сработает для вашего приложения.