Search code examples
c#.netwinformsdatagridviewdpi-aware

Winforms application throws Win32Exception if marked as DPI aware and used with multiple monitors


I have a Windows Forms application (.NET Framework 4.8) which has a TabControl tabControl as the main object. I use it to switch to different screens, and I have a next and previous button which select the next or previous tab with this code:

private void ButtonNextTab(object sender, EventArgs e)
{
    int index = tabControl.SelectedIndex;
    tabControl.SelectTab(index + 1); // index - 1 for ButtonPreviousTab
}

I set my application as DPI aware by including the following in app.config:

<System.Windows.Forms.ApplicationConfigurationSection>
   <add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>

On the last tab, I have a DataGridView. If I go to this last tab exactly twice using the buttons, no matter how fast I click the buttons, I get the following exception: System.ComponentModel.Win32Exception: 'Error creating window handle.', and it appears to be thrown in the SelectTab method. It also happens if I replace SelectTab with tabControl.SelectedIndex = index + 1.

However, it does not happen if I remove the tag in app.config or navigate to the tab any number of times using the TabControl's tabs. I create and run the application on a second monitor with 100% scaling, but if I run it on my main laptop screen with 125% scaling the problem does not occur (although interestingly the application always starts at 100% until a DPI change event seems to be triggered by moving the application from one screen to the other). I have only been able to recreate this problem on my 100% screen and never on my 125% screen. If I set scaling on my primary screen to 100% the problem vanishes, and if both screens are set to 125% I can't reproduce it either.

I could not find any information about this problem. Is there a way to prevent it?

Image of the exception information, barely contains any useful information


Update: I tried setting DataGridView.DisableHighDpiImprovements to "false", that didn't fix it


Update 2: the complete stack trace (the image only shows the first bit):

at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
at System.Windows.Forms.Control.CreateHandle()
at System.Windows.Forms.ComboBox.CreateHandle()
at System.Windows.Forms.Control.RecreateHandleCore()
at System.Windows.Forms.ComboBox.RecreateHandleCore()
at System.Windows.Forms.ComboBox.OnFontChanged(EventArgs e)
at System.Windows.Forms.Control.set_Font(Font value)
at System.Windows.Forms.Control.WmDpiChangedBeforeParent(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ComboBox.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

For reference, this is what the datagridview looks like (with text in the header removed), the buttons on the right aren't part of the datagridview but are used to control the currently selected row.

enter image description here


Update 3: I can't reproduce it myself when creating a new project. Restarting at different DPI values (100% and 125%) didn't help. I found that the dropdown background is black the first time it is clicked. If an option is moused over it appears as a normal highlighted option (blue background and white text) until I leave it again. This happens on both screens.

black dropdown menu

I also found that if I place my cursor in both of the text fields in the placeholder DataDridViewRow, no exception occurs. After placing the cursor in one of those text fields the text field itself appears black like the dropdown does, but only once (unlike the dropdown) and afterwards the dropdown and other textbox are no longer black. This would suggest to me that there's something wrong with the placeholder row, but I can't find out what and I don't know how it relates to different DPI issues. One of the columns also had a really long tooltip I thought might cause issues, but removing it did nothing.


Update 4: If the DataGridView's Visible property is set to false in the form designer, no error occurs. That seems to restrict the problem to something related to both the DataGridView and the different scaling on multiple screens. I also tried programmatically setting text in the two text fields of the placeholder row, which didn't work.


Solution

  • I found a workaround, by manually selecting the first text field in the datagridview if no cell is selected the problem no longer occurs:

    private void ButtonNextTab(object sender, EventArgs e)
    {
        int index = tabControl.SelectedIndex;
        if (index == 1 && dataGridView.CurrentCell is null)
        {
            dataGridView.Rows[0].Cells[1].Selected = true;
        }
        tabControl.SelectTab(index + 1);
    }
    

    I still have no idea what the actual problem is or how this workaround prevents that from occurring, but at least it works. I will probably switch to WPF if I ever find the time to rewrite everything. If someone comes across this and figures out what caused the problem, please add it as answer.