LIST SCALING

Giorgio Sfiligoi 286 Reputation points
Oct 10, 2024, 2:05 PM

I have developed a pretty large application for desktop using VS Community, based on .NET Framework 4.7.2. The app includes several instances of ListView (in detail mode) and DataGridView.

When I run my application with the default display scaling 100% it's all OK.

In a previous query I raised the issue of Font scaling and I got the solution: it consists in adding the following in the app.manifest:

<application xmlns="urn:schemas-microsoft-com:asm.v3">

<windowsSettings>

<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>

</windowsSettings>

</application>

Now, if I change the scaling e.g. to 125%, all the windows and fonts scale as expected, except the column widths and row heights in the ListView and DataGridView: they do not scale and as a consequence the layout of certain forms is messed up and some texts do not fit into the cells.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,030 questions
0 comments No comments
{count} votes

Accepted answer
  1. Jiale Xue - MSFT 48,521 Reputation points Microsoft Vendor
    Oct 11, 2024, 2:58 AM

    Hi @Giorgio Sfiligoi , Welcome to Microsoft Q&A,

    This is a common DPI scaling behavior, especially in Windows desktop applications. Although you can solve some of the problems by enabling DPI awareness in app.manifest, you still need to manually adjust the column width and row height of the control to respond to the change in DPI scaling.

    You can capture the DpiChanged event and adjust the layout of the control when the DPI changes. For Windows 10 and above, the DpiChanged event is available for the form.

    protected override void OnDpiChanged(DpiChangedEventArgs e)
    {
    base.OnDpiChanged(e);
    
    // Get the new DPI and adjust column width and row height
    float scaleFactor = e.DeviceDpiNew / 96f;
    
    foreach (ColumnHeader column in listView1.Columns)
    {
    column.Width = (int)(column.Width * scaleFactor);
    }
    
    foreach (DataGridViewColumn column in dataGridView1.Columns)
    {
    column.Width = (int)(column.Width * scaleFactor);
    }
    dataGridView1.RowTemplate.Height = (int)(dataGridView1.RowTemplate.Height * scaleFactor);
    }
    

    You can also use the Windows API functions Graphics.DpiX and Graphics.DpiY to get the current system DPI Scale and dynamically adjust the column width and row height of the control.

    
    private void Form1_Load(object sender, EventArgs e)
    {
    // Get the current system DPI scaling ratio
    using (Graphics g = this.CreateGraphics())
    {
    float dpiX = g.DpiX;
    float dpiY = g.DpiY;
    
    // Assuming the default DPI is 96 (100% scaling), calculate the scaling ratio
    float scaleFactor = dpiX / 96f;
    
    // Adjust ListView column width
    foreach (ColumnHeader column in listView1.Columns)
    {
    column.Width = (int)(column.Width * scaleFactor);
    }
    
    // Adjust DataGridView column width and row height
    foreach (DataGridViewColumn column in dataGridView1.Columns)
    {
    column.Width = (int)(column.Width * scaleFactor);
    }
    dataGridView1.RowTemplate.Height = (int)(dataGridView1.RowTemplate.Height * scaleFactor); } }
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Mike Meinz 1 Reputation point
    Dec 8, 2024, 11:22 PM

    For DPI Awareness, here is how I scale ListView columns at initialization of my program and whenever the window is moved to a different DPI screen.

    Additionally, I found that setting MinimumSize, MaximumSize and all four Anchor point properties for every control on the form helps a lot. All my forms are fixed format - no grow or shrink. I set MinimumSize and MaximumSize to the same height and width as specified in the Size property.

    This must be in the project file:

    <ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
    

    which will cause the Designer files of the project to contain this:

      Me.AutoScaleDimensions = New SizeF(96.0F, 96.0F)
    
        Private Sub ScheduleVideos_Shown(sender As Object, e As EventArgs) Handles Me.Shown
            AdjustListViewControls(96, Me.DeviceDpi) ' Scale ListView columns at initialization
        End Sub
    
        Private Sub Main_DpiChanged(sender As Object, e As DpiChangedEventArgs) Handles Me.DpiChanged
            AdjustListViewControls(e.DeviceDpiOld, e.DeviceDpiNew) ' When form is moved to another screen
        End Sub
    
    Sub AdjustListViewControls(ByVal OldDPI As Integer, ByVal newDPI As Integer)
        Dim scaleFactor As Double = newDPI / OldDPI
        For Each column As ColumnHeader In LstSchedule.Columns ' Scale columns in ListView
            column.Width = CInt(column.Width * scaleFactor)
        Next
        For Each column As ColumnHeader In LstVideos.Columns ' Scale columns in ListView
            column.Width = CInt(column.Width * scaleFactor)
        Next
    End Sub
    

    .NET 9.0 Windows Forms
    Visual Studio 17.12.1

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.