0

In C# Windows Forms application, I have problem as follows:

  1. I have tab control with 5 tabs
  2. On each tab, I have a DataGridView (control type is not important and you can consider a panel instead)
  3. After loading the form, when I get DataGridView width from inactive tab (#5), it is 500 (wrong value)
  4. When I activate tab #5, then get DataGridView width as 700 (which is the correct value)

Question

As I found, objects in hidden situation cannot return correct value in relation to visual parameters. How can I force application to set its correct state and return correct value in an identical situation as mentioned above?

Why I need control property when it is hidden or out of view?

In each tab, there is a custom DGV (Ces.WinForm.UI) and when user assign DataSource, a Load Screen will appeare in front of DGV to prevent user for any unnecessary click to raise any event related to DGV. So, When selected item in ComboBox changes by user, then all DGVs must be updated with new value selected in ComboBox. In this situation, while no tab is selected, cause to show Load Screen in wrong position & size.

I tried to perform layout then repaint object as follow in Resize event of tab control (but this did not work):

private void tabControl1_Resize(object sender, EventArgs e)
{
    foreach (TabPage t in tabControl1.TabPages)
    {
        t.PerformLayout();
        t.Refresh();
        t.Invalidate();
    }
}
4
  • In design time, form size is small but in run time must be maximize. Because of that I put my solution on resize event of tab control. Commented Aug 7 at 18:39
  • 5
    The Handle of Controls in TabPages other that the one that's first shown is not usually created, because of performance considerations. Since it appears you're targeting .NET, the app is also DPI aware by default, which means that when you show that Control, and the Handle is created if it wasn't already, then it's scaled (or simply adapted, based on the overall layout as it's calculated) -- Not clear why you'd need the bounds of a Control that's not visible, and it's inside a TabPage. You should really clarify that, because you may be focusing on the wrong thing (i.e., solve the wrong issue) Commented Aug 7 at 21:01
  • 1
    Most likely the width of the DGV on all tabs are not the same. You need to have a selected index event and change the width of the DGV based on the index number : learn.microsoft.com/en-us/dotnet/api/… Commented Aug 7 at 21:27
  • Curious, but if you have 5 tabs with 5 data grids, why do you need the size info for the inactive data grid? Can you not just base calculations off the visible data grid dimensions, or the tab control itself? Commented Aug 8 at 5:01

1 Answer 1

1

Thank you @Jimi to mention the root of problem. As you said, Handle of control was not created. DGV has a LoadingScreen when user wants to assign value as DataSource but, this screen is a form and must cover entire area of DGV. Meanwhile, this screen is visible in front of other controls and since the actual size and position of hidden DGV is not accessible, finally LoadingScreen is displayed in wrong size and position.

Solution

Inside code lines where the LoadingScreen must be shown, IsVisible method can return actual situation to decide possibility of showing LoadingSreen. As you can see in the following code, two factor for this purpose is checked: 1) IsHandleCreated (As you mentioned) 2) DGV is visible on screen.

public static Form Create(
    Control control,
    bool coverParentContainer = true,
    bool coverParentForm = false,
    string title = "Loading...",
    double opacity = 0.5)
{

    var frm = new CesLoadScreen();
    frm._title = title;
    frm.Opacity = opacity;

    if (!IsVisible(control))
        return frm;

    SetLoadingScreenSize(frm, coverParentContainer, coverParentForm, control);

    control.Resize += (s, e) 
                => SetLoadingScreenSize(frm, coverParentContainer, coverParentForm, control);

    frm.Show(control.FindForm());
    Application.DoEvents();

    return frm;
}

public static bool IsVisible(Control control)
{
    Rectangle screenBounds = Screen.FromControl(control).Bounds;
    Rectangle controlBounds = control.RectangleToScreen(control.ClientRectangle);

    bool isOnScreen = screenBounds.IntersectsWith(controlBounds);

    if (!control.IsHandleCreated || !isOnScreen)
        return false;

    if (!control.Visible)
        return false;

    return true;
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.