Desired DataGrid ColumnWidth functionality: Star with Auto MinWidth

Dec 5, 2008 at 2:01 PM
The current DataGrid ColumnWidth (DataGridLength) options do not cover my most commonly required scenario, where columns have an automatically calculated minimum width so that column content will not be truncated, and where the column width will also grow to fill available space.

So, it would be just like the current Star option, but with the MinWidth of each column set to the ActualWidth of the column if it were sized using Auto.

I am currently achieving this using custom code (on DataGrid v1), but I would have thought this would be a common enough requirement to warrant a simpler approach, like a value that could be set on the ColumnWidth property of the DataGrid.

This sizing technique is particularly useful for scenarios where columns are auto-generated.
Coordinator
Dec 5, 2008 at 5:37 PM
Thanks for the suggestion, chrisduff.  We will take this into consideration when choosing features for V2.
Jan 6, 2009 at 4:26 AM
chrisduff,

could you give a clue as to how you are providing this behavior with custom code?

I can't seem to find any way of finding out from a column what it's fitted width should be... short of declaring it's width as Auto and peeking at the ActualWidth property.

Like yourself, I would like all auto-generated columns to have a minimum width set to the "Auto" value, and the width set to "*".

Thanks for any help.

KB
Jan 12, 2009 at 7:20 AM
Hi KB,

You're on the right track re: declaring columns as Auto and peeking at their ActualWidth property.

My approach has been to create my own derived DataGrid class to work around various issues such as this. I've quickly edited my code to leave the parts relevant to this thread and pasted below (not compiled/tested).

Some points to note:

> It's obviously a hack approach, but does the job for me and seems to be the easiest way to achieve the functionality.
> Note that I only use this data grid for read-only purposes. It works for both pre-defined and auto-generated column scenarios.
> I've noticed UI responsiveness issues during resizing when used with large data sets.

I hope you find it useful.

Cheers,
Chris
===========================
using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Windows.Controls;

namespace MyNamespace
{
    public class MyDataGrid : DataGrid
    {
        private bool newCols = false;
        private bool rowsLoaded = false;
        private IList itemsSourceList = null;

        public MyDataGrid()
        {
            this.LoadingRow += new EventHandler<DataGridRowEventArgs>(MyDataGrid_LoadingRow);
            this.LayoutUpdated += new EventHandler(MyDataGrid_LayoutUpdated);
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            if (this.ColumnWidth.IsStar)
            {
                if (this.Columns.Count > 0)
                {
                    newCols = true;
                    foreach (DataGridColumn col in this.Columns)
                    {
                        col.Width = DataGridLength.Auto;
                    }
                }
            }
        }
       
        protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e)
        {
            base.OnAutoGeneratingColumn(e);

            if (this.ColumnWidth.IsStar)
            {
                e.Column.Width = DataGridLength.Auto;
            }
        }

        protected override void OnAutoGeneratedColumns(EventArgs e)
        {
            base.OnAutoGeneratedColumns(e);

            if (this.ColumnWidth.IsStar)
            {
                newCols = true;
                rowsLoaded = false;
                itemsSourceList = null;
            }
        }

        private void MyDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            if (this.ColumnWidth.IsStar)
            {
                if (!rowsLoaded)
                {
                    if (itemsSourceList == null)
                    {
                        itemsSourceList = this.ItemsSource as IList;
                    }

                    if (itemsSourceList == null)
                    {
                        rowsLoaded = true;
                    }
                    else
                    {
                        if (itemsSourceList.IndexOf(e.Row.Item) == (itemsSourceList.Count - 1))
                        {
                            rowsLoaded = true;
                        }
                    }
                }
            }
        }

        private void MyDataGrid_LayoutUpdated(object sender, EventArgs e)
        {
            if (rowsLoaded)
            {
                if (this.ColumnWidth.IsStar)
                {
                    if (newCols)
                    {
                        double totalMinWidth = 0D;
                        foreach (DataGridColumn col in this.Columns)
                        {
                            col.MinWidth = col.ActualWidth;
                            totalMinWidth += col.MinWidth;
                        }
                        this.MinWidth = totalMinWidth;

                        newCols = false;
                    }

                    ResizeColumns();
                }
            }
        }

        private void ResizeColumns()
        {
            double leftover = (this.ActualWidth - this.MinWidth);
            double leftoverPerCol = (leftover / this.Columns.Count);

            foreach (DataGridColumn col in this.Columns)
            {
                double desiredWidth = (col.MinWidth + leftoverPerCol);

                if (col.ActualWidth != desiredWidth)
                {
                    col.Width = new DataGridLength(desiredWidth);
                }
            }
        }
    }
}
===========================