3

Edit: This is not a duplicate of Icons in TabControl C# - How?. The question there is about adding icons to tab pages. Here it is about how the change the error provider error icon position to be inside the header instead of to the right of the tab page itself. Also, the error provider error icon has the functionality that when you hover the mouse on it, you see the error text, which you do not see if you simply add an icon to the header.


I have a form with a TabControl. The form has also an ErrorProvider. When I try to use the following code:

errorProvider1.SetError(tabPage1, "error");

The error icon is shown to the right of the tab page, and it is cut-off by the tab control itself: 1]

I would like the icon to be shown next to the tab page header. Something like this (made with Photoshop):

2]

I do not know where to start, or how to approach this.

Edit: I have a class responsible for adding errors to a control, and showing them using an error provider. This class is used for TextBoxes, NumericUpDowns etc. I would like to use it also for TabPages. The problem is that when I use it for tab pages I get the result shown above. The trick of adding an error icon to the header using an ImageList and then add a tooltip is not good, because it is specific to tab pages, and I cannot implement it in my class which is general to all controls. So I really need to change the settings of the tab page so when I use errorProvider.SetError(...) it is shown in the header.

Michael Haddad
  • 4,085
  • 7
  • 42
  • 82
  • Possible duplicate of [Icons in TabControl C# - How?](https://stackoverflow.com/questions/3663603/icons-in-tabcontrol-c-sharp-how) – Renatas M. Jan 15 '19 at 08:59
  • @Reniuz - Please see my edit. – Michael Haddad Jan 15 '19 at 09:10
  • You can do the same as in linked answer and also add tooltip for tab page - it will be displayed when you hover mouse on tab page header. – Renatas M. Jan 15 '19 at 09:22
  • @Reniuz - Thanks. Even so, this is not a duplicate. Also, please see my new edit. – Michael Haddad Jan 15 '19 at 09:35
  • ErrorProvider does not help you to get this right, it does take setting the ImageIndex property of the tab. If you want to do both (use ErrorProvider to mark the bad control *and* show an icon in the tab) then you have to write the code to count errors. [Like this](https://stackoverflow.com/a/2682478/17034). – Hans Passant Jan 15 '19 at 10:32
  • @HansPassant - Thanks! According to my business logic, It is not a control inside the tab page that is bad, but the tab page itself that is bad. For example, let's say I have ten `TextBox`es inside the tab page, and I want the user to fill at least one of them. If he doesn't, an error should be shown. The problem is not with a specific control but with the page itself. Using `errorProvider.SetError(tabPage, "error")` works just fine, it's just that it draws the icon in the wrong place. All I want is to draw the icon in the right place, maybe with `SetIconPadding`, but I am not sure how. – Michael Haddad Jan 15 '19 at 10:40
  • @HansPassant - I hope I am clear enough. My English is not so good as you can see... – Michael Haddad Jan 15 '19 at 10:42
  • 1
    `ErrorProvider` is not such flexible for changing the location of the icon and even if you change the location of the error icon, for tab page, it will show the icon in client area of the tab page. Or if you choose to set the error icon for the tab control, at any point of time, you can show error icon only for one tab page while there may be invalid controls on all tab pages. In general if I want to show error Icon for tab pages, I'll use icon of tab page. And I would say it's custom or general as much as you consider `SetIconPadding` custom or general. – Reza Aghaei Jan 15 '19 at 18:48

2 Answers2

9

ErrorProvider shows error icon of the TabPage in tab page's client area. By playing with IconAlignment or IconPadding, you can show error icon of TabControl on one of the tab pages' headers, but it's error icon for the whole TabControl.

In a real application each of the tab pages can contain controls which are not valid and you may want to show the validation icon on tab pages not for the tab control.

My suggestion is using tab page icon by setting ImageList containing the error icon as image list of the TabControl and by setting ImageIndex of the TabPage, show or hide the image icon. This way you can show the error icon for every tab page which needs it:

enter image description here

Example

To setup the example, follow these steps:

  1. Create a Form.
  2. Drop a TabControl, an ErrorProvider and an ImageList on the Form.
  3. Set ImageList property of tabControl1 to imageList1.
  4. Drop two TextBox on tabPage1.
  5. I assume, just for example, you are going to validate these two text box controls using Validating event. The key point is here. When you validate any control, check if it's hosted in a TabPage, check validity of all children of TabPage and set the error icon based on that:

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        this.AutoValidate = AutoValidate.EnableAllowFocusChange;
        imageList1.ColorDepth = ColorDepth.Depth32Bit;
        imageList1.Images.Add(errorProvider1.Icon);
        tabControl1.ImageList = imageList1;
        textBox1.Validating += textBox_Validating;
        textBox2.Validating += textBox_Validating;
    }
    private void textBox_Validating(object sender, CancelEventArgs e)
    {
        var textBox = (TextBox)sender;
        if (string.IsNullOrEmpty(textBox.Text))
        {
            this.errorProvider1.SetError(textBox, "Value is required.");
            e.Cancel = true;
        }
        else
            this.errorProvider1.SetError(textBox, null);
        var tabPage = textBox.Parent as TabPage;
        if (tabPage != null)
            ValidateTabPage(tabPage);
    }
    void ValidateTabPage(TabPage tabPage)
    {
        var tabIsValid = tabPage.Controls.Cast<Control>()
            .All(x => string.IsNullOrEmpty(errorProvider1.GetError(x)));
        if (tabIsValid)
            tabPage.ImageIndex = -1;
        else
            tabPage.ImageIndex = 0;
    }
    
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Using `Validating` event is just for example (while it's always good idea). In general you need to call `ValidateTabPage` at the same time that you do the validation. – Reza Aghaei Jan 15 '19 at 18:50
2

You can do the following.

Rectangle rc = tabControl1.GetTabRect(0); // Replace with the index of Tab required
errorProvider1.SetIconPadding(tabControl1, -rc.Left-20);;
errorProvider1.SetError(tabControl1, "Error String");

You also need to set

errorProvider1.SetIconAlignment(tabControl1, ErrorIconAlignment.TopLeft);

Sample (With Second Tab Selected - based on comments),

You would need to prepend whitespace to your TabPage Text to ensure there is sufficient space for showing the icon

enter image description here

With Icon on Second Tab

enter image description here

Anu Viswan
  • 17,797
  • 2
  • 22
  • 51
  • Thanks! When the selected tab is the first, this is the result I get: https://i.imgur.com/WHsu5NH.png. When the selected tab is the second, however, the icon disappears. – Michael Haddad Jan 15 '19 at 11:30
  • 1
    @Sipo Have added a screenshot with mentioned scenario. Did you mean the same ? – Anu Viswan Jan 15 '19 at 12:23
  • I mean that if I use `tabControl1.GetTabRect(1)`, then this is the result: https://i.imgur.com/ONh0cmd.png – Michael Haddad Jan 15 '19 at 12:25
  • 1
    @Sipo I have updated the answer. It should work now, you need to use "-rc.Left" when setting the IconPadding. Kindly check and let me know – Anu Viswan Jan 15 '19 at 14:02
  • Thanks! much better! Now, how can I make the icon not overlap the text? – Michael Haddad Jan 15 '19 at 14:05
  • 1
    You need to playaround with that number 20 (offset) a bit., I would suggest leave some space before your TabPage Text, so that you can accomodate the icon – Anu Viswan Jan 15 '19 at 14:07
  • One of the reasons that I preferred to not post such answer is because, it's setting error icon for `TabControl`, it's not setting the icon for `TabPage`. If you want to show error icon for multiple tab pages this will not work. – Reza Aghaei Jan 15 '19 at 16:24
  • @RezaAghaei I agree. This is not the most ideal way if we consider more than one tab pages are required. But at the moment, it would be a wild guess to think the OP might require it in tab pages or not. But yes, definetely not the best way to indicate error on tab pages, if multiple scenario might occur – Anu Viswan Jan 15 '19 at 16:31