How to adjust the width of GridViewComboBoxColumn based on the contents of the dropdown.

4 posts, 0 answers
  1. Dave Galligher
    Dave Galligher avatar
    37 posts
    Member since:
    May 2010

    Posted 03 Jan 2012 Link to this post

    What I thought was going to be a simple issue, hasn't turned into one. Basically I need to autosize a column based on the contents in the dropdown.

    The grid is bound to a BindingList<T> as well as the combobox column. The values that appear in the combobox (DisplayMember) are based on resources, so it's possible the width of the required column could changed based on the resource id and the string returned. I need to automatically adjust the width of the GridViewComboBoxColumn based on the contents in the combo box. Currently I'm using the <column>.BestFit() method, but this only works based on the displayed data, I've tried using the AutoSizeMode property after the call of BestFit() call as explained in help but there is nothing there that says to use width of the values in the drop down (by the way there is an error in the names of the enumerators for this setting BestFitColumnMode.SymmaryRowCells - it should be BestFitColumnMode.SummaryRowCells, but I digress)

    An example, based on resourceID

    en-US                     fr-FR                es-MX
    XXX                         XXXXXXXX        XXXXXXXXXXXXXXXXXXXX
    YYYYYY                  YYYY              YYYYYY

    I need the width of the column to adjust based on the max length of whatever could be displayed to the user, in the example above, if the resource id is set to es-MX, the width of the column should be larger (wider) than it is if the resourceID is en-US, and the same for fr-FR.

    Hopefully I haven't over-complicated the explanation of the problem. Thank you in advance,
    Dave Galligher
  2. Jack
    Admin
    Jack avatar
    2335 posts

    Posted 06 Jan 2012 Link to this post

    Hi Dave,

    Thank you for questioning.

    If I understand correctly, you want to calculate the best width of a grid column based on a list with known values. If this is the case you can use the following method to do the job:
    private int MeasureCell(RadGridView grid, GridViewColumn column, string text)
    {
        if (grid.Rows.Count == 0)
        {
            return 50;
        }
     
        GridViewRowInfo row = grid.Rows[0];
        RowElementProvider rowElementProvider = (RowElementProvider)grid.TableElement.RowElementProvider;
        CellElementProvider cellElementProvider = (CellElementProvider)grid.TableElement.CellElementProvider;
        GridRowElement visualRow = rowElementProvider.GetElement(row, null) as GridRowElement;
        visualRow.InitializeRowView(grid.TableElement);
        visualRow.Initialize(row);
        grid.TableElement.Children.Add(visualRow);
     
        GridCellElement cell = cellElementProvider.GetElement(column, visualRow) as GridCellElement;
     
        cell.Initialize(column, visualRow);
        cell.Text = text;
        cell.UpdateInfo();
     
        visualRow.Children.Add(cell);
     
        cell.ResetLayout(true);
        cell.Measure(new SizeF(float.PositiveInfinity, float.PositiveInfinity));
        int width = (int)cell.DesiredSize.Width;
     
        visualRow.Children.Remove(cell);
        grid.TableElement.Children.Remove(visualRow);
     
        GridVirtualizedCellElement virtualizedCell = cell as GridVirtualizedCellElement;
        if (virtualizedCell != null)
        {
            cellElementProvider.CacheElement(virtualizedCell);
            virtualizedCell.Detach();
        }
        else
        {
            cell.Dispose();
        }
     
        GridVirtualizedRowElement virtualizedRow = visualRow as GridVirtualizedRowElement;
        if (virtualizedRow != null)
        {
            rowElementProvider.CacheElement(virtualizedRow);
            virtualizedRow.Detach();
        }
        else
        {
            row.Dispose();
        }
     
        return width;
    }

    Use this method by passing a text value for the cell. For example:
    this.radGridView1.Rows[18].Cells["Name"].Value = "I am a long text!";
    this.radGridView1.Columns["Name"].Width = MeasureCell(this.radGridView1, this.radGridView1.Columns["Name"], "I am a long text!");

    Measuring cell content is a slow process and that is why RadGridView measures only the cells that are currently visible.

    If you have further questions, please do not hesitate to contact us.
     
    Kind regards,
    Jack
    the Telerik team

    SP1
    of Q3’11 of RadControls for WinForms is available for download (see what's new).
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Dave Galligher
    Dave Galligher avatar
    37 posts
    Member since:
    May 2010

    Posted 06 Jan 2012 Link to this post

    There are two problems with this approach:

    1. You must know the the longest value in advance as to what the longest text will be in the combo box, I could have 5 values, I could have 60, are you telling me the only way to do is to cycle through all the values in the BindingList<T> collection and pass that to the function before I run the measure text function? If so, seems like a lengthy process, is there a way to just look at the comboboxitem collection and read the width from there based on the longest string?

    2. It only will measure the values if there is a row in the grid. Unfortunately, this is not practical in my situation. The user determines if they wish to add a row from the add row on the grid at run time. Yes, eventually the information will get saved in a database and rebuilt as a BindingList<T> collection for the datasource for the grid when the form loads, but in the beginning there are zero rows for a new value in our system, yet the comboboxes are initialized with data.

    Thank you for your assistance.
  5. Jack
    Admin
    Jack avatar
    2335 posts

    Posted 11 Jan 2012 Link to this post

    Hi Dave,

    Thank you for writing us back. Directly to your questions:

    1. Yes, it is possible to iterate through combobox items. However, a combo box editor is created only when editing a cell. You can iterate through data source items if you know what the data source is. Consider the sample below:
    GridViewComboBoxColumn c = new GridViewComboBoxColumn("A");
    c.DataSource = table;
    c.ValueMember = "ID";
    c.DisplayMember = "Name";
    this.radGridView1.Columns.Add(c);
     
    int maxLen = 0;
    DataRow longestRow = null;
    DataTable t = c.DataSource as DataTable;
    for (int i = 0; i < t.Rows.Count; i++)
    {
        DataRow row = t.Rows[i];
        int len = row[c.DisplayMember].ToString().Length;
        if (len > maxLen)
        {
            longestRow = row;
            maxLen = len;
        }
    }
     
    if (longestRow != null)
    {
        MeasureCell(this.radGridView1, c, longestRow[c.DisplayMember].ToString());
    }

    2. Currently, it is possible to measure a cell only when there is a row. So, you have to create a fake row to measure, or you have to measure after adding a row. We know about this limitation and we will consider removing it in a future version.

    Should you have other questions, I will be glad to help.

    Kind regards,
    Jack
    the Telerik team

    SP1
    of Q3’11 of RadControls for WinForms is available for download (see what's new).
Back to Top