Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Resizing DataGrid columns 2

Status
Not open for further replies.

Nelviticus

Programmer
Sep 9, 2003
1,819
GB
I have a DataGrid on my Windows form. I set its DataSource to a DataView of a table that has a variable number of columns.

I want to re-size the DataGrid columns so that they're wide enough to show the names of each column - by default they are a standard width, so any columns with long names will only show part of the name.

Is there a way to do this? I have not even been able to set the widths to arbitrary values, let alone calculated sizes. This is what I tried based on something I read here:

Code:
DataGridTableStyle vStyle = new DataGridTableStyle();
foreach(DataColumn vColumn in dvMyView.Table.Columns)
{
	if (vColumn.DataType.ToString().ToLower()=="system.string")
	{
		DataGridTextBoxColumn vColumnStyle = new DataGridTextBoxColumn();
		vColumnStyle.Width = 15;
		vStyle.GridColumnStyles.Add(vColumnStyle);
	}
	else
	{
		DataGridBoolColumn vColumnStyle = new DataGridBoolColumn();
		vColumnStyle.Width = 25;
		vStyle.GridColumnStyles.Add(vColumnStyle);
	}
}
dgMyGrid.TableStyles.Add(vStyle);

dgMyGrid.DataSource = dvMyView;

My columns are all either strings or boolean. This code did nothing at all - the columns remained at the default widths.

Any idea what I'm doing wrong?

Regards

Nelviticus
 
hey,

If you know what the columns are called, you can reference them based on the name....For example:

Code:
dataGrid1.DataSource = DSMyDataSet;
dataGrid1.DataMember = "Table";

DataGridTableStyle DGTS = new DataGridTableStyle();
DGTS.MappingName = DSMyDataSet.Tables["Table"].TableName;
dataGrid1.TableStyles.Add(DGTS);

foreach(DataGridColumnStyle vColumnStyle in dataGrid1.TableStyles["Table"].GridColumnStyles)
{
   if (vColumnStyle.HeaderText.ToString() == "POS")
   {
	vColumnStyle.Width = 30;
	vColumnStyle.NullText = "";
   }
   if (vColumnStyle.HeaderText.ToString() == "TOS")
   {
	vColumnStyle.Width = 30;
	vColumnStyle.NullText = "";
   }
}

This does require you to know the column names in advance, but it has worked flawlessly for me....however, if you want your way to work, based on datatypes, you may want to try only creating and adding one tablestyle and mapping the name(see lines 4 and 5 of my example) and looping through the gridcolumnstyles (see line 6 of my example). I'm not entirely sure it will work, but I think so.

Good luck,

Kevin

- "The truth hurts, maybe not as much as jumping on a bicycle with no seat, but it hurts.
 
And you can set the PreferedColumnWidth on the tablestyle
 
Your code should work if you set the DataSource as in Kevin's example, e.g. before changing the style.
I think you want to set different columns to different widths.
One way is to create a table that will contain the view attributes such as : display name, width, alignment, color, language etc...
This table has entries for each sql names or aliases that are object to the presentation layer.
An alias, for instance, could be the column name defined in the view objects.

_tColumnFormat table:

dbName/alias viewName Width Alignment
------------ -------- ----- ---------
Prod_Id Product ID 100 left
Prd-id Product ID 100 left
dt_Send Send Date 120 center
dt_Target Target Date 120 center

Next, create a class that will encapsulate a DataTable which holds the contents of the above table and methods to retrive the attributes for a given column.
Example:
Code:
class InventoryView
{
   internal DataTable m_ColumnFormat;
   public:
   InventoryView ()
   {
       // Load data from _tColumnFormat table 
   }
   // Methods to retrive the view attributes for a given column 
   string GetColumnName( string colName)
   {
      // returns the viewName for a given column if found else returns the passed parameter
   }
   string GetColumnWidth( string colName)
   {
     //returns the column width or a default value if not found
   }
   System.Windows.Forms.HorizontalAlignment GetColumnAlignment( string colName)
   {
   }
   
}

Next, have a function to format the grid before displaying it.
This

DataGrid m_DataGrid;
DataSet m_DataSet; // loaded with data to be displayed in DataGrid object
InventoryView m_InventoryView; // loaded with column attributes

private void FormatGrid()
{
try
{
m_DataGrid.TableStyles.Clear();

DataGridTableStyle vStyle = new DataGridTableStyle();
vStyle.AlternatingBackColor = System.Drawing.Color.Bisque;
vStyle.RowHeadersVisible = false;

vStyle.MappingName = m_DataSet.Tables[0].TableName;

// iterate through each column and set the view attribute in the DataGridTableStyle object
foreach(DataColumn vColumn in m_DataSet.Tables[0].Columns)
{
switch (vColumn.GetType().ToString().ToLower())
{
case "system.string" :
case "system.datetime":
case "system.dbnull" :
case "system.int32" :
DataGridTextBoxColumn vColumnStyle= new DataGridTextBoxColumn();
vColumnStyle.TextBox.Enabled = false;
//vColumnStyle.TextBox.CanFocus = false;
vColumnStyle.NullText ="";
vColumnStyle.HeaderText = vColumn.ColumnName;
vColumnStyle.MappingName = vColumn.ColumnName ;
vColumnStyle.ReadOnly =true;
vColumnStyle.Width = m_InventoryView.GetColumnWidth(vColumn.ColumnName);

break;
case "system.boolean" :
DataGridBoolColumn vColumnStyle= new DataGridBoolColumn();
vColumnStyle.AllowNull = false;
vColumnStyle.HeaderText = vColumn.ColumnName;
vColumnStyle.MappingName = vColumn.ColumnName ;
vColumnStyle.Alignment = System.Windows.Forms.HorizontalAlignment.Center ;
vColumnStyle.Width = m_InventoryView.GetColumnWidth(vColumn.ColumnName.ToLower());
switch(m_InventoryView.GetColumnAlignment(vColumn.ColumnName))
{
case "center":
vColumnStyle.Alignment = System.Windows.Forms.HorizontalAlignment.Center ;
break;
case "right":
vColumnStyle.Alignment = System.Windows.Forms.HorizontalAlignment.Right;
break;
default:
vColumnStyle.Alignment = System.Windows.Forms.HorizontalAlignment.Left;
break;
}
vStyle.GridColumnStyles.Add(vColumnStyle);
break;
default:
break;
}
}
m_DataGrid.TableStyles.Add(vStyle);

}
catch(Exception vException)
{
//Process here exceptions
}
}
[/code]

How to use ?
Code:
m_InventoryView= new InventoryView();
m_DataGrid.DataBindings.Clear();   
m_DataSet= ...;
m_DataGrid.TableStyles.Clear();  
// Replace here with your DataView
m_DataGrid.SetDataBinding(m_DataSet,m_DataSet.Tables[0].TableName); 
FormatGrid();
[code]

Or, have a function to render datagrid from a DataSet using the above custom attributes.  

[code]
public bool RenderResults(ref DataSet vDataSet, InventoryView vInventoryView))
{
	try 
	{
		m_InventoryView=vInventoryView;
		m_DataGrid.DataBindings.Clear();   
		m_DataSet= vDataSet;
		m_DataGrid.TableStyles.Clear();  
		// Replace here with your DataView
		m_DataGrid.SetDataBinding(m_DataSet,m_DataSet.Tables[0].TableName); 
		m_DataGrid.AllowNavigation= false;
		m_DataGrid.CaptionText =  " ...." + " (" + m_DataSet.Tables[0].Rows.Count+")";
		FormatGrid();
		return true;
	
	}
	catch(Exception vException)
	{
		MessageBox.Show(vException.Message ,"Unable to load reporting ...",System.Windows.Forms.MessageBoxButtons.OK,System.Windows.Forms.MessageBoxIcon.Stop);       
		return false;
	}
}

-obislavu-
 
Wow, thanks all for replying, particularly kmfna and obislavu for your detailed answers. Have a star each.

The data comes from an XML file that can be edited by users - in fact the app that I'm creating is to enable them to edit the data. The rows of the grid are items and the columns are categories: each item can be in one or more categories. Users can add and remove categories, hence I don't know how many columns there will be or what their names will be until I read the data file.

Because the categories are created by non-technical users I can't ask them to specify a column width, so I can't store it in the data file. I need to calculate it when the data is loaded based on the column's name.

I was planning to calculate the width by having a hidden label on the form, setting its text to the column name and then using '[tt]Label.CreateGraphics().MeasureString(Label.Text, Label.Font)[/tt]' to find out how wide it is. The problem is applying this value to the column.

Unfortunately I've been moved onto another project so I can't test your solutions at the moment but I will have a try at lunchtime.

Regards

Nelviticus
 
Well I ended up trying Kevin's method first because it was the shortest! It worked with some modifications - my data source is a DataView so I can't set the DataMember property. Here's what I ended up with:

Code:
// Set up a new table style and map its name to the source table's name
DataGridTableStyle tsTableStyle = new DataGridTableStyle();
tsTableStyle.MappingName = dvSourceData.Table.TableName;

// Clear any existing styles and add our new one
dgMatrix.TableStyles.Clear();
dgMatrix.TableStyles.Add(tsTableStyle);

// Loop through each column in the style
foreach(DataGridColumnStyle csColStyle in dgMatrix.TableStyles[0].GridColumnStyles)
{
	// Find the display width of the column's title
	string sTitle = csColStyle.MappingName;
	int iWidth = StringWidth(sTitle, dgMatrix) + 2;

	// If it's larger than the default, widen the column
	if (iWidth > dgMatrix.PreferredColumnWidth)
		csColStyle.Width = iWidth;
}

If anyone's interested the string-measuring method is as follows:

Code:
private int StringWidth(string sTest, Control oControl)
{
	// Returns the width in pixels that the string sTest would
	// take up when using oControl's font

	SizeF sfWidthTest = new SizeF();
	sfWidthTest = oControl.CreateGraphics().MeasureString(sTest, oControl.Font);
	int iWidth = Convert.ToInt32(sfWidthTest.Width);
	return iWidth;
}

Thanks to everyone for helping get this working.

Regards

Nelviticus
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top