I want to show the text in the header cells in vertical orientation. How can I do it?
Thanks
You can achieve the result you want using custom cell painting for the header.
In answer to your comment asking for a way to align the text with the bottom of the cell, I've added comments to my code. They are hopefully clear.
You need the following code (say in the Form_Load after initializing components)
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
dataGridView1.ColumnHeadersHeight = 50;
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader;
// Here we attach an event handler to the cell painting event
dataGridView1.CellPainting += new DataGridViewCellPaintingEventHandler(dataGridView1_CellPainting);
Next you need something like the following code:
void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
// check that we are in a header cell!
if (e.RowIndex == -1 && e.ColumnIndex >= 0)
{
e.PaintBackground(e.ClipBounds, true);
Rectangle rect = this.dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
Size titleSize = TextRenderer.MeasureText(e.Value.ToString(), e.CellStyle.Font);
if (this.dataGridView1.ColumnHeadersHeight < titleSize.Width)
{
this.dataGridView1.ColumnHeadersHeight = titleSize.Width;
}
e.Graphics.TranslateTransform(0, titleSize.Width);
e.Graphics.RotateTransform(-90.0F);
// This is the key line for bottom alignment - we adjust the PointF based on the
// ColumnHeadersHeight minus the current text width. ColumnHeadersHeight is the
// maximum of all the columns since we paint cells twice - though this fact
// may not be true in all usages!
e.Graphics.DrawString(e.Value.ToString(), this.Font, Brushes.Black, new PointF(rect.Y - (dataGridView1.ColumnHeadersHeight - titleSize.Width) , rect.X));
// The old line for comparison
//e.Graphics.DrawString(e.Value.ToString(), this.Font, Brushes.Black, new PointF(rect.Y, rect.X));
e.Graphics.RotateTransform(90.0F);
e.Graphics.TranslateTransform(0, -titleSize.Width);
e.Handled = true;
}
}
A simpler and more effective renderer
Attach event either through designer, or with this line of code
dataGridView1.CellPainting += new DataGridView1_CellPainting(dataGridView1_CellPainting);
Event handler to draw rotated text
private void DataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) {
// Vertical text from column 0, or adjust below, if first column(s) to be skipped
if (e.RowIndex == -1 && e.ColumnIndex >= 0) {
e.PaintBackground(e.CellBounds, true);
e.Graphics.TranslateTransform(e.CellBounds.Left , e.CellBounds.Bottom);
e.Graphics.RotateTransform(270);
e.Graphics.DrawString(e.FormattedValue.ToString(),e.CellStyle.Font,Brushes.Black,5,5);
e.Graphics.ResetTransform();
e.Handled = true;
}
}
DataGrid d = new DataGrid();
d.Columns[0].HeaderStyle.VerticalAlign = VerticalAlign.Bottom;
If you are looking for gridview then you case like this :-
GridView gv = new GridView ();
gv.Columns[0].ItemStyle.VerticalAlign = VerticalAlign.Bottom;
If you are looking for datagridview then you case like this :-
Create an object of datagridview.
gv.Columns["ColumnName"].HeaderCell.Style.Alignment = DataGridViewContentAlignment.BottomCenter;
void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == -1 && e.ColumnIndex >= 0)
{
e.PaintBackground(e.ClipBounds, true);
Rectangle rect =
this.dataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, true);
Size titleSize =
TextRenderer.MeasureText(e.Value.ToString(), e.CellStyle.Font);
if (this.dataGridView1.ColumnHeadersHeight <
titleSize.Width)
this.dataGridView1.ColumnHeadersHeight =
titleSize.Width;
e.Graphics.TranslateTransform(0, titleSize.Width);
e.Graphics.RotateTransform(-90.0F);
e.Graphics.DrawString(e.Value.ToString(), this.Font,
Brushes.Orange, new PointF(rect.Y, rect.X));
e.Graphics.RotateTransform(90.0F);
e.Graphics.TranslateTransform(0, -titleSize.Width);
e.Handled = true;
}
}
In addition, you could set the AutoSizeColumnsMode property of the
DataGridView to AllCellsExceptHeader in order to make the DataGridView
compact.
Related
I am new to Winform C#. I have a question: Are there any ways to set color for the first character in a cell of DataGridView?
Thank you!
Handling the CellPainting event is the right way to do it. Here is a code snippet applying your requirement to specific cell excluding the grid column headers.
private void DataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.Value != null && !string.IsNullOrEmpty(e.Value.ToString()) && e.RowIndex != -1)
{
// Current cell pending to be painted.
var currentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
// Cell that needs to be painted. In this case the first cell of the first row.
var cellToBePainted = dataGridView1.Rows[0].Cells[0];
if (currentCell == cellToBePainted)
{
using (Brush customColor = new SolidBrush(Color.Red))
using (Brush cellDefaultBrush = new SolidBrush(e.CellStyle.ForeColor))
{
string fullText = e.Value.ToString();
string firstChar = fullText[0].ToString();
string restOfTheText = fullText.Substring(1);
e.PaintBackground(e.CellBounds, true);
Rectangle cellRect = new Rectangle(e.CellBounds.Location, e.CellBounds.Size);
Size entireTextSize = TextRenderer.MeasureText(fullText, e.CellStyle.Font);
Size firstCharSize = TextRenderer.MeasureText(fullText[0].ToString(), e.CellStyle.Font);
e.Graphics.DrawString(fullText[0].ToString(), e.CellStyle.Font, customColor, cellRect);
if (!string.IsNullOrEmpty(restOfTheText))
{
Size restOfTheTextSize = TextRenderer.MeasureText(restOfTheText, e.CellStyle.Font);
cellRect.X += (entireTextSize.Width - restOfTheTextSize.Width);
cellRect.Width = e.CellBounds.Width;
e.Graphics.DrawString(restOfTheText, e.CellStyle.Font, cellDefaultBrush, cellRect);
}
e.Handled = true;
}
}
}
}
I am trying to write a Windows Forms MusicPlayer application in C#.
The application should show a list and have some play / stop buttons.
I just started half an hour ago, but my design is almost finished. Now I got 3 things to fix. A bug and 2 good looking things:
on the picture you can see the bug I've found. You might say that's nothing, but its a eye catcher. How can I fix this?
how can I align center the headline of a column, without centering the content?
how can I make the last column filling out the rest of the listView?
You can set the TextAlign of all but the 1st Column's Header; it is always left aligned. To change that you need to owner draw it.
There is no automatic filling option so you need to write a setColumnwidth function, that loops over all but the last columns and sums their Widths; then it subtract the sum from the ListView's Clientsize.Width and set the last column's Width.
The display bug in the gridlines is new to me; so far I don't know how to fix it; maybe owner-drawing will help there as well..?
Update:
Here is some code:
void setLastColumnTofill(ListView lv)
{
int sum = 0;
int count = lv.Columns.Count;
for (int i = 0; i < count - 1; i++) sum += lv.Columns[i].Width;
lv.Columns[count - 1].Width = lv.ClientSize.Width - sum;
}
After setting OwnerDraw = true you could code the three (all are needed!) Draw event :
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.Graphics.FillRectangle(SystemBrushes.Menu, e.Bounds);
e.Graphics.DrawRectangle(SystemPens.GradientInactiveCaption,
new Rectangle(e.Bounds.X , 0, e.Bounds.Width , e.Bounds.Height) );
string text = listView1.Columns[e.ColumnIndex].Text;
TextFormatFlags cFlag = TextFormatFlags.HorizontalCenter
| TextFormatFlags.VerticalCenter;
TextRenderer.DrawText(e.Graphics, text, listView1.Font, e.Bounds, Color.Black, cFlag);
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true;
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true;
}
You may want to play a little with the colors or the widths..
If you have an ImageList containing images for displaying the sort order (or other things) you can add this to draw them as well:
ColumnHeader colH = listView1.Columns[e.ColumnIndex];
int ii = colH.ImageIndex;
if (ii >= 0 && ii < imageList1.Images.Count)
e.Graphics.DrawImage(imageList1.Images[ii],
e.Bounds.Width + e.Bounds.X - imageList1.ImageSize.Width, 0);
After setting OwnerDraw to true you can do other stuff like this:
Draw ListView
int sortIndex = 0;
private void listView1_DrawColumnHeader(object sender,
DrawListViewColumnHeaderEventArgs e)
{
var state = e.State == ListViewItemStates.Selected ?
VisualStyleElement.Header.Item.Hot : VisualStyleElement.Header.Item.Normal;
var sortOrder = listView1.Sorting == SortOrder.Ascending ?
VisualStyleElement.Header.SortArrow.SortedUp :
VisualStyleElement.Header.SortArrow.SortedDown;
var itemRenderer = new VisualStyleRenderer(state);
var sortRenderer = new VisualStyleRenderer(sortOrder);
var r = e.Bounds;
r.X += 1;
itemRenderer.DrawBackground(e.Graphics, r);
r.Inflate(-2, 0);
var flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter |
TextFormatFlags.SingleLine;
itemRenderer.DrawText(e.Graphics, r, e.Header.Text, false, flags);
var d = SystemInformation.VerticalScrollBarWidth;
if (e.ColumnIndex == sortIndex) //Sorted Column
sortRenderer.DrawBackground(e.Graphics,
new Rectangle(r.Right - d, r.Top, d, r.Height));
}
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
e.DrawDefault = true; /*Use default rendering*/
}
Fill ListView using Last Column
private void ListViewSample_Load(object sender, EventArgs e)
{
var otherItemWisth= this.listView1.Columns.Cast<ColumnHeader>()
.Where(x => x.Index < this.listView1.Columns.Count - 1)
.Sum(x => x.Width);
this.listView1.Columns[this.listView1.Columns.Count - 1].Width =
this.listView1.ClientSize.Width - otherItemWisth;
}
Result
I have a datagridview which is coding in c#.net
My requirement is, if I select any DataGridView cell the cell content should be visible larger as a popup, or I want to view the datagridview cell larger or fitted one when move my cursor to particular cell.
For text and numerics this may do what you need:
private void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex < 0 | e.ColumnIndex < 0) return;
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected)
{
e.Graphics.FillRectangle(SystemBrushes.Highlight, e.CellBounds);
e.Graphics.DrawString(e.Value.ToString(), new Font(e.CellStyle.Font.FontFamily,
e.CellStyle.Font.Size * 1.5f), SystemBrushes.HighlightText, e.CellBounds.Location);
e.Handled = true;
}
}
You may need to use e.FormattedValue instead of e.Value if you are using formats
You may also need to insert a test of the cell value's type..
This code this will enlarge the font by 50% while not in edit mode.
For images a different solution would be necessary - probably a popup Label or Panel; but that really depends on just what you want and what kind of images they are.. Icons I would leave alone, photos of users would profit from the enlarged display.
Of course, if the enlarged content doesn't actually fit in the Cell the popup solution would also be called for..
Upadate
Here is an extension which tests the Column Value/FormattedValue and for a Bitmap displays the Image in a popup Label:
Label imageLabel;
bool labelHide = false; //*** new
void showImageLabel(DataGridViewCellPaintingEventArgs e)
{
if (labelHide) return; //*** new
if (imageLabel == null) imageLabel = new Label();
imageLabel.Click += (sender, evt) =>
{ ((Label)sender).Hide(); labelHide = true; }; //*** new
imageLabel.Text = "";
imageLabel.Parent = dataGridView1;
imageLabel.Location = e.CellBounds.Location;
if (imageLabel.Image != null) imageLabel.Image.Dispose();
//Size size = ((Bitmap)e.Value).Size; //*** old
Size size = ((Bitmap)e.FormattedValue).Size; //*** new
Size newSize = new Size( (int)(size.Width * 1.5f), (int)(size.Height * 1.5f));
//Bitmap bmp = new Bitmap((Bitmap)e.Value, newSize); //*** old
Bitmap bmp = new Bitmap((Bitmap)e.FormattedValue, newSize); //*** new
imageLabel.Size = newSize;
imageLabel.Image = bmp;
imageLabel.Show();
}
private void dataGridView1_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex < 0 | e.ColumnIndex < 0) return;
if (e.Value == null) { if (imageLabel != null) imageLabel.Hide(); return; }
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected)
{
//if (e.Value.GetType() == typeof(Bitmap)) //*** old
if (e.FormattedValue.GetType() == typeof(Bitmap)) //*** new
{
showImageLabel(e);
e.Handled = true; //*** old
if (labelHide) labelHide = false; else e.Handled = true; //*** new
return;
}
else if (imageLabel != null) imageLabel.Hide();
e.Graphics.FillRectangle(SystemBrushes.Highlight, e.CellBounds);
e.Graphics.DrawString(e.FormattedValue.ToString(),
new Font(e.CellStyle.Font.FontFamily, e.CellStyle.Font.Size * 1.5f),
SystemBrushes.HighlightText, e.CellBounds.Location);
e.Handled = true;
}
}
private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
{
if (imageLabel != null) imageLabel.Hide();
}
You may want to adapt the Location to be e.g. centered..
Update 2
I have now adapted the code to the case of retrieving Images directly as byte[] from a Database. In this case the Type of the Value Property is not Image. Instead one simlpy needs to check the FormattedValue.
If the displayed, resized Image is too large, it may cover the whole Cell and the Cell_Painting event won't get triggered. Therefore I have also added an one-liner for the RowLeave event to prevent that.
I have also added a few lines to allow the image to be clicked away.
Please change the lines I marked with //*** , add the event and check if it now works for you!
Here are two Screenshots:
I have a data grid view and I want to make all of the cell borders thicker. Is there a property you can do this with?
You need to do a little custom painting by adding code to the CellPainting event handler. For setting the cells border to None, use CellBorderStyle:
dataGridView1.CellBorderStyle = DataGridViewCellBorderStyle.None;
// CellPainting event handler for your dataGridView1
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex == -1 && e.ColumnIndex > -1)
{
e.Handled = true;
using (Brush b = new SolidBrush(dataGridView1.DefaultCellStyle.BackColor))
{
e.Graphics.FillRectangle(b, e.CellBounds);
}
using (Pen p = new Pen(Brushes.Black))
{
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
e.Graphics.DrawLine(p, new Point(0, e.CellBounds.Bottom-1), new Point(e.CellBounds.Right, e.CellBounds.Bottom-1));
}
e.PaintContent(e.ClipBounds);
}
}
How can I change the "selection style" on a DataGridView (winforms)?
You can easily change the forecolor and backcolor of selcted cells by assigning values to the SelectedBackColor and SelectedForeColor of the Grid's DefaultCellStyle.
If you need to do any further styling you you need to handle the SelectionChanged event
Edit: (Other code sample had errors, adjusting for multiple selected cells [as in fullrowselect])
using System.Drawing.Font;
private void dataGridView_SelectionChanged(object sender, EventArgs e)
{
foreach(DataGridViewCell cell in ((DataGridView)sender).SelectedCells)
{
cell.Style = new DataGridViewCellStyle()
{
BackColor = Color.White,
Font = new Font("Tahoma", 8F),
ForeColor = SystemColors.WindowText,
SelectionBackColor = Color.Red,
SelectionForeColor = SystemColors.HighlightText
};
}
}
Use the SelectedCells property of the GridView and the Style property of the DataGridViewCell.
Handle the SelectionChanged event on your DataGridView and add code that looks something like this:
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
foreach (DataGridViewRow row in this.dataGridView1.Rows)
{
foreach (DataGridViewCell c in row.Cells)
{
c.Style = this.dataGridView1.DefaultCellStyle;
}
}
DataGridViewCellStyle style = new DataGridViewCellStyle();
style.BackColor = Color.Red;
style.Font = new Font("Courier New", 14.4f, FontStyle.Bold);
foreach (DataGridViewCell cell in this.dataGridView1.SelectedCells)
{
cell.Style = style;
}
}
You can try the solution provided in this topic. I've tested and approved it.
Hope that helped.
With this you can even draw a colored border to the selected cells.
private void dataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
{
if (dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Selected == true)
{
e.Paint(e.CellBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.Border);
using (Pen p = new Pen(Color.Red, 1))
{
Rectangle rect = e.CellBounds;
rect.Width -= 2;
rect.Height -= 2;
e.Graphics.DrawRectangle(p, rect);
}
e.Handled = true;
}
}
}