开发者

Visual studio - TabControl.TabPages.Insert not working

H开发者_如何转开发ere's my code:

    public MainForm()
    {
        InitializeComponent();

        MyServiceSettings obj = (MyServiceSettings)ConfigurationManager.GetSection("MyServiceSettings");

        foreach (MyServiceConfigElement service in obj.Services)
            CreateServiceControl(service);
    }

    private void CreateServiceControl(MyServiceConfigElement service)
    {
        TabPage tp = new TabPage(service.Name);
        tabControl1.TabPages.Insert(0, tp);
        //tabControl1.TabPages.Add(tp);
        tabControl1.Refresh();    
    }

In a nutshell, it reads a section in a config file and creates a tab for each element in the section.

I already have one static TabPage created at design time. I want the dynamic created tabs to be inserted before this static tab.

Running this code, the tabcontrol shows only the static tabpage.

If I do this change:

        private void CreateServiceControl(SoftInfoServiceConfigElement service)
    {
        TabPage tp = new TabPage(service.Name);
        //tabControl1.TabPages.Insert(1, tp);
        tabControl1.TabPages.Add(tp);
        tabControl1.Refresh();
    }

Using the Add method shows all the pages. But I do not get the order I want.

Is there something I don't understand with the Insert method? Why is it'n working?


There is a comment on social.msdn - although I could not find anything like this in the documentation:

The TabControl's handle must be created for the Insert method to work

Try the mentioned code

IntPtr h = this.tabControl1.Handle;

before you loop over your services


Since "Brad is looking for a canonical answer", I focus on answering the OP's question: "Is there something I don't understand with the Insert method? Why isn't it working?".

It's a bug. The Insert method doesn't work if the TabControl handle is not created; however the Add method always works as expected, no matter the handle is created or not. It could be avoided with a correct implementation.

This is how .NET Tab control works: it has been created based on the native TabControl, which shows a list of tab headers and provide a display area to show some contents inside the control. The .NET Implementation takes care of adding those headers to the native control and also keep a list of containers (TabPages) and position them correctly and show them when user selects a tab.

How the bug occurs for the Insert method but not for the Add method? If the .NET implementation doesn't add the tab page to the native TabControl using native methods, then it doesn't show the headers; And it's what happening here:
In the Insert method, when the handle is not created, the .NET code doesn't call the native methods to add the tab page to the native control. Same for Add method; however the Add method, always works as expected, no matter if the handle is created or not, because in the Add method, the the .NET code checks if the control handle is not created, then it adds the tab page into a list of pages and later when the control handle is created, is calls the native API methods for all the pages in the collection; but for the Insert method, when the handle is not created, they have not added the tab page to the list of tab pages.

If you want to trace the code yourself, look into the source code of Insert and Add, and also consider looking into the custom implementation of the ControlCollection for the TabControl, especially the Add method of it and pay attention to the InsertingItem and IsHandleCreated properties.

And finally, how to avoid this situation? Well, the accepted answer works properly, but if you don't like having a dummy line of code to get the handle of the control, you can do either of the following:

  • You can call the insert in OnShown method or in Shown event handler of the form.
  • You can also call the Show method of the form before inserting tab pages.
  • You can reverse your list of configs and Add them to the control.
  • You can add all the tab pages to an array, reverse the array and use AddRange.


You're passing the same index to the Insert() method. If you wish to simply increment, this should work:

// ...

int i = 0;
foreach (MyServiceConfigElement service in obj.Services)
            CreateServiceControl(service, i++);

// ...

private void CreateServiceControl(MyServiceConfigElement service, int i)
{
        TabPage tp = new TabPage(service.Name);
                tabControl1.TabPages.Insert(i, tp);
// ...

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜