i have a user form that contain some textbox and a grid view. my grid view contain 5 columns, what i am trying to is to autofit the first 4 columns and make the last one fill the remaining space available. i tried setting my first 4 columns auto Displayed Cells, AllCells.. and the last one to fill it work fine if the containing data in the first 4 columns don't exceed the column width, once they exceed the last column go out of bound.
Result:
Any help will be much appreciated
If you just need to make all the columns visible and you don't care about truncating the string with "...", just add this in the code (for example in the Load event of the form or in the Draw event of the GridView):
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
If, on the other hand, you want to have the cell string in its entirety, you could programmatically decrease the cell font, it is not exactly aesthetic but I leave you a code as an example (obviously it must be used together with the code I wrote above):
private void AdaptCellsToDataGrid()
{
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
foreach (DataGridViewColumn column in dataGridView1.Columns)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
bool ContentTruncated = true;
DataGridViewCell cell = dataGridView1.Rows[row.Index].Cells[column.Index];
cell.Style.Font = dataGridView1.Font;
Font currentCellFont = cell.Style.Font;
float currentFontSize = currentCellFont.Size;
float reduce = 1; //start with only 1 size reduction
while (ContentTruncated == true)
{
Graphics graphics = this.CreateGraphics();
//measuring the string lenght at drawing
SizeF sizeF = graphics.MeasureString(cell.Value.ToString(), dataGridView1.Font);
float textLength = sizeF.Width;
if (textLength > cell.Size.Width)
{
if ((currentFontSize - reduce) > 5) //if value is bigger than 5 reduce else stop reducing
{
cell.Style.Font = new Font(currentCellFont.FontFamily, (currentFontSize - reduce), currentCellFont.Style);
reduce = reduce + 1;
}
else
{
break;
}
}
else if (textLength <= cell.Size.Width)
{
ContentTruncated = false;
break;
}
}
}
}
}
I hope I have helped you in some way. :)
There are 2 lists called listversion & MIN_list. Using values of these list I have created a line chart. Everything is work fine. But I am wondering whether it is possible to add a data table with legend keys in to the chart like MS Excel.
chart.Series.Clear();
chart.ChartAreas[0].AxisX.Title = "Version";
chart.ChartAreas[0].AxisX.TitleFont = new System.Drawing.Font("Arial", 12, FontStyle.Regular);
chart.ChartAreas[0].AxisY.Title = "Time";
chart.ChartAreas[0].AxisY.TitleFont = new System.Drawing.Font("Arial", 12, FontStyle.Regular);
Series MIN = chart.Series.Add("Minimum");
MIN.Points.DataBindXY(listVersion, MIN_list[j]);
MIN.ChartType = SeriesChartType.Line;
MIN.Color = Color.Red;
MIN.BorderWidth = 3;
I am looking forward to something like this
If it is possible How can I do it ?
Thank you.
Yes you can do that:
Here are the steps I took:
First we disable the original Legend as it can't be manipulated the way we need to..:
chart1.Legends[0].Enabled = false;
Now we create a new one and a shortcut reference to it:
chart1.Legends.Add(new Legend("customLegend"));
Legend L = chart1.Legends[1];
Next we do some positioning:
L.DockedToChartArea = chart1.ChartAreas[0].Name; // the ca it refers to
L.Docking = Docking.Bottom;
L.IsDockedInsideChartArea = false;
L.Alignment = StringAlignment.Center;
Now we want to fill in one line for headers and one line per series.
I use a common function for both and pass in a flag to indicate whether the headers (x-values) or the cell data (y-values) should be filled in. Here is how I call the function:
addValuesToLegend(L, chart1.Series[0], false);
foreach (Series s in chart1.Series) addValuesToLegend(L, s, true);
Note that for this to work we need a few preparations in our Series:
We need to set the Series.Colors explicitly or else we can't refer to them.
I have added a format string to the Tag of each series; but maybe you find a better solution that avoids hard-coding the format for the header..
So here is the function that does all the filling and some styling:
void addValuesToLegend(Legend L, Series S, bool addYValues)
{
// create a new row for the legend
LegendItem newItem = new LegendItem();
// if the series has a markerstyle we show it:
newItem.MarkerStyle = S.MarkerStyle ;
newItem.MarkerColor = S.Color;
newItem.MarkerSize *= 2; // bump up the size
if (S.MarkerStyle == MarkerStyle.None)
{
// no markerstyle so we just show a colored rectangle
// you could add code to show a line for other chart types..
newItem.ImageStyle = LegendImageStyle.Rectangle;
newItem.BorderColor = Color.Transparent;
newItem.Color = S.Color;
}
else newItem.ImageStyle = LegendImageStyle.Marker;
// the rowheader shows the marker or the series color
newItem.Cells.Add(LegendCellType.SeriesSymbol, "", ContentAlignment.MiddleCenter);
// add series name
newItem.Cells.Add(LegendCellType.Text, addYValues ? S.Name : "",
ContentAlignment.MiddleLeft);
// combine the 1st two cells:
newItem.Cells[1].CellSpan = 2;
// we hide the first cell of the header row
if (!addYValues)
{
newItem.ImageStyle = LegendImageStyle.Line;
newItem.Color = Color.Transparent;
newItem.Cells[0].Tag = "*"; // we mark the 1st cell for not painting it
}
// now we loop over the points:
foreach (DataPoint dp in S.Points)
{
// we format the y-value
string t = dp.YValues[0].ToString(S.Tag.ToString());
// or maybe the x-value. it is a datatime so we need to convert it!
// note the escaping to work around my european locale!
if (!addYValues) t = DateTime.FromOADate(dp.XValue).ToString("M\\/d\\/yyyy");
newItem.Cells.Add(LegendCellType.Text, t, ContentAlignment.MiddleCenter);
}
// we can create some white space around the data:
foreach (var cell in newItem.Cells) cell.Margins = new Margins(25, 20, 25, 20);
// finally add the row of cells:
L.CustomItems.Add(newItem);
}
To draw the borders around the cells of our legend table we need to code the PrePaint event:
private void chart1_PrePaint(object sender, ChartPaintEventArgs e)
{
LegendCell cell = e.ChartElement as LegendCell;
if (cell != null && cell.Tag == null)
{
RectangleF r = e.ChartGraphics.GetAbsoluteRectangle(e.Position.ToRectangleF());
e.ChartGraphics.Graphics.DrawRectangle(Pens.DimGray,Rectangle.Round(r));
// Let's hide the left border when there is a cell span!
if (cell.CellSpan != 1)
e.ChartGraphics.Graphics.DrawLine(Pens.White,
r.Left, r.Top+1, r.Left, r.Bottom-1);
}
}
You can add more styling although I'm not sure if you can match the example perfectly..
I wrote one project. I used DataGridViewAutoFilter library for filtering. But I have problem.
For filtering Drop-Down Filter List for a DataGridView Column Header Cell size(width) are very small. It come automatic size.
How to resize Drop-Down Filter List for a DataGridView Column Header Cell for filtering?
private void dataGridView1_BindingContextChanged(object sender, EventArgs e)
{
if (dataGridView1.DataSource == null) return;
foreach (DataGridViewColumn col in dataGridView1.Columns)
{
col.HeaderCell = new DataGridViewAutoFilterColumnHeaderCell(col.HeaderCell);
}
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
}
I found the solution : We must change SetDropDownList properties : DataGridViewColumnHeader.cs in DataGridViewAutoFilter.dll.İt is open source.
private void SetDropDownListBoxBounds()
{
Debug.Assert(filters.Count > 0, "filters.Count <= 0");
// Declare variables that will be used in the calculation,
// initializing dropDownListBoxHeight to account for the
// ListBox borders.
Int32 dropDownListBoxHeight = 6; // You must change!!!!!
Int32 currentWidth = 0;
Int32 dropDownListBoxWidth = 0;
Int32 dropDownListBoxLeft = 0;
// For each formatted value in the filters dictionary Keys collection,
// add its height to dropDownListBoxHeight and, if it is wider than
// all previous values, set dropDownListBoxWidth to its width.
using (Graphics graphics = dropDownListBox.CreateGraphics())
{
foreach (String filter in filters.Keys)
{
SizeF stringSizeF = graphics.MeasureString(
filter, dropDownListBox.Font);
dropDownListBoxHeight += (Int32)stringSizeF.Height;
currentWidth = (Int32)stringSizeF.Width;
if (dropDownListBoxWidth < currentWidth)
{
dropDownListBoxWidth = currentWidth;
}
}
}
// Increase the width to allow for horizontal margins and borders.
dropDownListBoxWidth += 40; //You must change !!!
// Constrain the dropDownListBox height to the
// DropDownListBoxMaxHeightInternal value, which is based on
// the DropDownListBoxMaxLines property value but constrained by
// the maximum height available in the DataGridView control.
if (dropDownListBoxHeight > DropDownListBoxMaxHeightInternal)
{
dropDownListBoxHeight = DropDownListBoxMaxHeightInternal;
// If the preferred height is greater than the available height,
// adjust the width to accommodate the vertical scroll bar.
dropDownListBoxWidth += SystemInformation.VerticalScrollBarWidth;
}
// Calculate the ideal location of the left edge of dropDownListBox
// based on the location of the drop-down button and taking the
// RightToLeft property value into consideration.
if (this.DataGridView.RightToLeft == RightToLeft.No)
{
dropDownListBoxLeft = DropDownButtonBounds.Right -
dropDownListBoxWidth + 1;
}
else
{
dropDownListBoxLeft = DropDownButtonBounds.Left - 1;
}
// Determine the left and right edges of the available horizontal
// width of the DataGridView control.
Int32 clientLeft = 1;
Int32 clientRight = this.DataGridView.ClientRectangle.Right;
if (this.DataGridView.DisplayedRowCount(false) <
this.DataGridView.RowCount)
{
if (this.DataGridView.RightToLeft == RightToLeft.Yes)
{
clientLeft += SystemInformation.VerticalScrollBarWidth;
}
else
{
clientRight -= SystemInformation.VerticalScrollBarWidth;
}
}
// Adjust the dropDownListBox location and/or width if it would
// otherwise overlap the left or right edge of the DataGridView.
if (dropDownListBoxLeft < clientLeft)
{
dropDownListBoxLeft = clientLeft;
}
Int32 dropDownListBoxRight =
dropDownListBoxLeft + dropDownListBoxWidth + 1;
if (dropDownListBoxRight > clientRight)
{
if (dropDownListBoxLeft == clientLeft)
{
dropDownListBoxWidth -=
dropDownListBoxRight - clientRight;
}
else
{
dropDownListBoxLeft -=
dropDownListBoxRight - clientRight;
if (dropDownListBoxLeft < clientLeft)
{
dropDownListBoxWidth -= clientLeft - dropDownListBoxLeft;
dropDownListBoxLeft = clientLeft;
}
}
}
// Set the ListBox.Bounds property using the calculated values.
dropDownListBox.Bounds = new Rectangle(dropDownListBoxLeft,
DropDownButtonBounds.Bottom, // top of drop-down list box
dropDownListBoxWidth, dropDownListBoxHeight);
}
/// <summary>
/// Gets the actual maximum height of the drop-down list, in pixels.
/// The maximum height is calculated from the DropDownListBoxMaxLines
/// property value, but is limited to the available height of the
/// DataGridView c`enter code here`ontrol.
I have dataGridView with a particular column. When I write long text in dataGridView it shows me a shortened version, with ellipses, because the column isn't wide enough to display the entire string.
| textdsadasda... |
What do I must to do if I want to dataGridView show this text in next line, or wrap the text?
| textdsadasda |
| dasdasa | (continuation of line above)
How can this be done?
There is no need to reinvent the wheel by repainting the cell.
Instead simply:
Set AutoSizeRowsMode property to AllCells. This allows row height to
grow with any wrapped text.
Set DataGridView.DefaultCellStyle.WrapMode
to DataGridViewTriState.True to wrap text in the cells.
Most importantly set DataGridView.AutoSizeColumnsMode to
DataGridViewAutoSizeColumnsMode.None so that the columns don't resize themselves
(so they remain at the user specified width).
After that the text should wrap to the next line if there is not enough space in the column.
Try setting
.AutoSizeMode to .DisplayedCells.
Set the AutoSizeRowsMode to AllCells.
DataGridView.DefaultCellStyle.WrapMode to DataGridViewTriState.True
You can try setting the DataGridView.DefaultCellStyle.WrapMode to DataGridViewTriState.True
May be handling cell painting event can help you
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.Value == null)
return;
var s = e.Graphics.MeasureString(e.Value.ToString(), dataGridView1.Font);
if (s.Width > dataGridView1.Columns[e.ColumnIndex].Width)
{
using (
Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
e.Graphics.DrawString(e.Value.ToString(), dataGridView1.Font, Brushes.Black, e.CellBounds,StringFormat.GenericDefault);
dataGridView1.Rows[e.RowIndex].Height = (int)(s.Height * Math.Ceiling( s.Width / dataGridView1.Columns[e.ColumnIndex].Width)) ;
e.Handled = true;
}
}
}
I've found #DeveloperX answer really useful, but with a couple of hiccups:
It causes some rows to flicker, if there is more than one cell that needs wrapping
Some cells have the last line missing or truncated (this happens if there are long words which can't be wrapped inside the text)
And it also caused missing cell borders (but this depends on grid/cell border settings).
I did a rework of #DeveloperX code to solve this issues, and came up with the following code:
private int _rowMaxHeight = 0;
private int _rowDefaultHeight = 0;
private void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.Value == null || e.RowIndex < 0)
{
// The WordWrap code is ony executed if requested the cell has a value,
// and if this is not the heading row.
return;
}
if (e.ColumnIndex == 0)
{
// Resetting row max height on each row's first cell
_rowMaxHeight = 0;
if (_rowDefaultHeight == 0)
{
/* The default DataGridView row height is saved when the first cell
* inside the first row is populated the first time. This is later
* used as the minimum row height, to avoid
* smaller-than-default rows. */
_rowDefaultHeight = dataGridView1.Rows[e.RowIndex].Height;
}
}
// Word wrap code
var sOriginal = e.Graphics.MeasureString(e.Value.ToString(),
dataGridView1.Font);
var sWrapped = e.Graphics.MeasureString(e.Value.ToString(),
dataGridView1.Font,
// Is is MeasureString that determines the height given the width, so
// that it properly takes the actual wrapping into account
dataGridView1.Columns[e.ColumnIndex].Width);
if (sOriginal.Width != dataGridView1.Columns[e.ColumnIndex].Width)
{
using (Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor),
fontBrush = new SolidBrush(e.CellStyle.ForeColor))
{
e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
// The DrawLine calls restore the missing borders: which borders
// miss and how to paint them depends on border style settings
e.Graphics.DrawLine(new Pen(gridBrush, 1),
new Point(e.CellBounds.X - 1,
e.CellBounds.Y + e.CellBounds.Height - 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y + e.CellBounds.Height - 1));
e.Graphics.DrawLine(new Pen(gridBrush, 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y - 1),
new Point(e.CellBounds.X + e.CellBounds.Width - 1,
e.CellBounds.Y + e.CellBounds.Height - 1));
//Updating the maximum cell height for wrapped text inside the row:
// it will later be set to the row height to avoid the flickering
// that would occur by setting the height multiple times.
_rowMaxHeight = (Math.Ceiling(sWrapped.Height) > _rowMaxHeight)
? (int)Math.Ceiling(sWrapped.Height) : _rowMaxHeight;
// The text is generated inside the row.
e.Graphics.DrawString(e.Value.ToString(), dataGridView1.Font,
fontBrush, e.CellBounds, StringFormat.GenericDefault);
e.Handled = true;
}
}
if (e.ColumnIndex == dataGridView1.ColumnCount -1
&& _rowMaxHeight > 0
&& _rowMaxHeight != dataGridView1.Rows[e.RowIndex].Height)
{
// Setting the height only in the last cell, when the full row has been
// painted, helps to avoid flickering when more than one row
// needs the wrap.
dataGridView1.Rows[e.RowIndex].Height =
(_rowMaxHeight > _rowDefaultHeight)
? _rowMaxHeight : _rowDefaultHeight;
}
}
Note that there is one problem still unresolved with this code: the text is not vertically centered anymore inside the cells!
Does setting this value help in achieving the display as you want
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
in addition to setting the WrapMode = DataGridViewTriState.True;
I found DeveloperX's answer to be very good. But I found I needed to tweak it a little. Firstly, I needed to ensure that the column in question was not in AutoSizeMode:
if (dgv.Columns[e.ColumnIndex].AutoSizeMode != DataGridViewAutoSizeColumnMode.None)
throw new InvalidOperationException(String.Format("dgv {0} AutoSizeMode <> 'None'", dgv.Columns[e.ColumnIndex].Name));
I also found that using
var s = e.Graphics.MeasureString(e.Value.ToString(), dataGridView1.Font);
returns a string length, which can't be used for comparison to ColumnWidth, which is given in pixels. So, using How can I convert a string length to a pixel unit?, I modified the above line of code to be
var s = e.Graphics.MeasureString(e.Value.ToString(), new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Pixel));
I also found that doing a direct comparison of widths was insufficient to determine when to prevent clipping - there were some edge cases that weren't being caught. So, I replaced
if (s.Width > dataGridView1.Columns[e.ColumnIndex].Width)
with a ratio comparison (cutoff value determined by experiment) :
if (e.Value.ToString().Length / (double)dataGridView1.Columns[e.ColumnIndex].Width >= .189)
Finally, the cell in the selected row was not hightlighted, so I added the following:
SolidBrush backColorBrush;
if (dataGridView1.SelectedRows[0].Index == e.RowIndex)
backColorBrush = new SolidBrush(e.CellStyle.SelectionBackColor);
else
backColorBrush = new SolidBrush(e.CellStyle.BackColor);
Final code:
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.Value == null || e.RowIndex == -1)
return;
if (dataGridView1.Columns[e.ColumnIndex].AutoSizeMode != DataGridViewAutoSizeColumnMode.None)
throw new InvalidOperationException(Format("dataGridView1 {0} AutoSizeMode <> 'None'", dataGridView1.Columns[e.ColumnIndex].Name));
var s = e.Graphics.MeasureString(e.Value.ToString(), new Font("Segoe UI", 11, FontStyle.Regular, GraphicsUnit.Pixel));
if (e.Value.ToString().Length / (double)dataGridView1.Columns[e.ColumnIndex].Width >= .189)
{
SolidBrush backColorBrush;
if (dataGridView1.SelectedRows[0].Index == e.RowIndex)
backColorBrush = new SolidBrush(e.CellStyle.SelectionBackColor);
else
backColorBrush = new SolidBrush(e.CellStyle.BackColor);
using (backColorBrush)
{
e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
e.Graphics.DrawString(e.Value.ToString(), dataGridView1.Font, Brushes.Black, e.CellBounds, StringFormat.GenericDefault);
dataGridView1.Rows[e.RowIndex].Height = System.Convert.ToInt32((s.Height * Math.Ceiling(s.Width / (double)dataGridView1.Columns[e.ColumnIndex].Width)));
e.Handled = true;
}
}
}
To do wrapping add this after binding
DataGrid1.ItemStyle.Wrap = true;
I agree with the answer that discussed simply setting the WordWrap on the cell and would add to it this scenario.
I was needing to change the colors and font styles on the fly based on the data in each cell. Initially I thought that I was stuck figuring out how to make the DrawString work with wrapping inside CellPainting event due to needing different text colors.
However, in the end I just set the Cell.Style properties inside the CellPainting event and then exited the event without setting the e.Handled = true. This way the grid's paint event used the styles I set for each cell and the text wrapped properly.
For example:
datagrid1[e.ColumnIndex, e.RowIndex].Style.BackColor = Color.Green;
I have a datagridview that is docked and anchored with a panel on a Winform. When I resize the form, the datagridview resizes as expected, but the columns do not resize to fit the datagridview. Instead, I am left with the background colour of the Datagridview.
How can I get the columns to grow with the control?
Thanks.
You could always use the AutoSizeColumnsMode property
This property lets you configure the control so that column widths are automatically adjusted either to fill the control or to fit cell contents. Size adjustments occur in fill mode whenever the width of the control changes.
There's a lot more information on the MSDN page for this.
You can set AutoSizeMode property of one of the columns to be Fill. Then this column will always resize itself to fill all the available space not used by other columns.
private void dataGrid_SizeChanged(object sender, EventArgs e)
{
ResizeGridColumns();
}
private void ResizeGridColumns()
{
//get sum of non-resizable columns width
int diffWidth = 0;
foreach (DataGridViewColumn col in this.dataGrid.Columns)
{
if (col.Resizable == DataGridViewTriState.False && col.Visible) diffWidth += col.Width;
}
//calculate available width
int totalResizableWith = this.dataGrid.Width - diffWidth;
//resize column width based on previous proportions
this.dataGrid.ColumnWidthChanged -= new DataGridViewColumnEventHandler(dataGrid_ColumnWidthChanged);
for (int i = 0; i < this.colWidthRaport.Count; i++)
{
try
{
if (this.dataGrid.Columns[i].Resizable != DataGridViewTriState.False && this.dataGrid.Columns[i].Visible)
{
this.dataGrid.Columns[i].Width = (int)Math.Floor((decimal)totalResizableWith / this.colWidthRaport[i]);
}
}
catch { }
}
this.dataGrid.ColumnWidthChanged += new DataGridViewColumnEventHandler(dataGrid_ColumnWidthChanged);
}
private void dataGrid_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
CalculateGridColWidthsRaport();
}
/// <summary>Calculates the proportions between grid width and column width</summary>
private void CalculateGridColWidthsRaport()
{
//get sum of non-resizable columns width
int diffWidth = 0;
int colWidthsSum = 0;
foreach (DataGridViewColumn col in this.dataGrid.Columns)
{
if (col.Visible)
{
colWidthsSum += col.Width;
if (col.Resizable == DataGridViewTriState.False) diffWidth += col.Width;
}
}
colWidthsSum += 24;
//calculate available with
int totalResizableWith = colWidthsSum - diffWidth;// this.dataGrid.Width - diffWidth;
if (this.ParentForm.WindowState == FormWindowState.Maximized)
{
totalResizableWith = this.dataGrid.Width - diffWidth;
}
//calculate proportions of each column relative to the available width
this.colWidthRaport = new List<decimal>();
foreach (DataGridViewColumn col in this.dataGrid.Columns)
{
this.colWidthRaport.Add((decimal)totalResizableWith / (decimal)col.Width);
}
}