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:
Related
I have a XtraGridview bound to datasource via Linq, when i check some checkbox i need to set an image into a cell and the value they already have.
right now when i check the checkbox i set the image in the cell just fine but eliminate the cell value (the data).
On CustomDrawCell event i do this
private void gridView_GD_CustomDrawCell(object sender, RowCellCustomDrawEventArgs e)
{
GridView view = sender as GridView;
string evento1 = Convert.ToString(view.GetRowCellValue(e.RowHandle, "Eve1"));
if (CVariables.Ficon_estado == 1)
{
if (evento1 == "06" || evento1 == "15")
{
if (e.Column.FieldName == "G1")
{
e.Handled = true;
Point pos = CalcPosition(e, imageCollection_16.Images[1]);
e.Graphics.DrawImage(imageCollection_16.Images[1], pos);
view.Columns["G1"].AppearanceCell.BackColor = Color.Transparent;
view.Columns["G1"].AppearanceCell.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Far;
}
}
}
else
{
view.Columns["G1"].AppearanceCell.TextOptions.HAlignment = DevExpress.Utils.HorzAlignment.Center;
}
}
private Point CalcPosition(RowCellCustomDrawEventArgs e, Image img)
{
Point p = new Point();
p.X = e.Bounds.Location.X + (e.Bounds.Width - (img.Width * 3)) / 2;
p.Y = e.Bounds.Location.Y + (e.Bounds.Height - img.Height) / 2;
return p;
}
I post an image to illustrate what i want
A cell text disappears since you set the e.Handled property to true. When this option is set, a default painting mechanism is not invoked. You can still draw a cell text manually by using the e.Appearance.DrawString method.
e.Appearance.DrawString(e.Cache, e.DisplayText, e.Bounds);
Another solution is to show an image by using the RepositoryItemTextEdit.ContextImage. That is, you can create two RepositoryItemTextEdits with different context images and assign them to grid cells conditionally in the GridView.CustomRowCellEdit event handler.
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 want to create this view. But I don't know how to make this kind of button, is it feasible with C#? If so, Please help me.
For a ListView you can get something that looks like your image by
splitting the data into the Text and the Tags of each Item/Subitem
owner-drawing the ListView
storing the two images (including headroom) in two Bitmaps.
Coding the MouseDown event to bring the 'buttons' to live
Here is the code for owner-drawing.
private void listView3_DrawItem(object sender, DrawListViewItemEventArgs e)
{
Rectangle textBounds = e.Bounds; textBounds.Height /= 2;
e.Graphics.DrawImage(e.Item.Text == "True" ? bmpOn : bmpOff, e.Bounds.Location);
TextRenderer.DrawText(e.Graphics, e.Item.Tag.ToString(),
Font, textBounds, Color.Black, TFFcenter);
}
private void listView3_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
Rectangle textBounds = e.Bounds; textBounds.Height /= 2;
e.Graphics.DrawImage(e.SubItem.Text == "True" ? bmpOn : bmpOff, e.Bounds.Location);
TextRenderer.DrawText(e.Graphics, e.SubItem.Tag.ToString(),
Font, textBounds, Color.Black, TFFcenter);
}
private void listView3_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.DrawDefault = true;
}
The code to process clicking on a ListView is simple but not obvious:
private void listView3_MouseDown(object sender, MouseEventArgs e)
{
ListViewHitTestInfo HI = listView3.HitTest(e.Location);
if (HI.SubItem != null) HI.SubItem.Text = HI.SubItem.Text == "True" ? "False" : "True";
else if (HI.Item != null) HI.Item.Text = HI.Item.Text == "True" ? "False" : "True";
}
The DrawText call uses TextFormatFlags to center the text in the upper half:
TextFormatFlags TFFcenter =
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter;
The trick is in preparing the whole ListView.
For my test I used this routine:
ImageList il = new ImageList();
il.ImageSize = new Size(1, bmpOff.Height);
listView3.SmallImageList = il;
for (int c = 0; c < listView3.Columns.Count; c++)
listView3.Columns[c].Width = bmpOff.Width;
for (int i = 0; i < listView3.Columns.Count; i++)
{
ListViewItem lvi = new ListViewItem( (i % 2 == 0).ToString() );
for (int c = 0; c < 5; c++)
{
lvi.SubItems.Add( ( (c+i) % 2 == 0).ToString());
lvi.SubItems[c].Tag = "3/7";
}
lvi.Tag = "3/7";
listView3.Items.Add(lvi);
}
listView3.Width = listView3.Columns.Count * bmpOff.Width + 4;
Note how I use a dummy ImageList to enforce the Item heights..but while you're at it, it is probably a better idea to add the ImageList in the Designer and store the Bitmaps in it..
When you want to access/change the text displayed above the buttons you need to use the Tag of each Item/Subitem..!
It is also possible to use a DataGridView and get the same look by cell painting it.
Note that none of the solutions lends itself well to databinding as you have too many data to bind per item/cell!
In Windows Forms. (That it looks like what you are using.) You can drop a DataGridView on a form and change the ColumnType in the GridView designer to DataGridViewCheckBoxColumn. This will give you the Functionality that you are looking for.
In other words, if you dont mind the look, (But need the same functionality) you could use a Checkbox in your grid.
When you have the correct functionality : You can use the above answer from Gnqz, to get the Look of the button.
Background: I am working with winforms in c#. I do not want images to be shown in datagridview cells, i have stored only path in database and showing them in datagridview from database.
Problem: When user enters a cell a tooltip is poped-up. What I need is that when column index of current-cell is 2 then the tool tip should show an image from the path given in the current cell.
I have found This Article very good. But unable to get succeeded. I have following code
void CustomizedToolTip_Popup(object sender, PopupEventArgs e)
{
DataGridView parent = e.AssociatedControl as DataGridView;
if (parent.CurrentCell != null)
{
if (parent.CurrentCell.ColumnIndex == 2)
{
Bitmap bmpIn = new Bitmap(parent.CurrentCell.Value + "");
using (Graphics g = Graphics.FromImage(bmpIn))
{
Rectangle mr = new Rectangle(5, 5, 50, 50);
mr.Location = new Point(5, 5);
g.PageUnit = GraphicsUnit.Pixel;
g.DrawImage(bmpIn, mr);
}
}
}
}
I thought this code should draw image, but it is not drawing, and more than drawing I am uncertain about the location, even If I could draw, how to locate it in tootip. I have not been able to understand it from the article i mentioned. Below is the image of my datagridview.
I did something similar for a project.
Instead, I just used a form which I set to open on CellMouseOver, close on CellMouseLeave
frm_MouseOverPicture HoverZoom = new frm_MouseOverPicture();
private void dgv_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv_sender = sender as DataGridView;
DataGridViewCell dgv_MouseOverCell = dgv_sender.Rows[e.RowIndex].Cells[e.ColumnIndex];
//Get FilePath from dgv_MouseOverCell content
//Get x, y based on position relative to edge of screen
//x, y = top left point of HoverZoom form
HoverZoom.LoadPicture(FilePath);
HoverZoom.Location = new System.Drawing.Point(x, y);
HoverZoom.Show();
}
private void dgv_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
HoverZoom.Hide();
HoverZoom.ClearPicture();
}
Hope that is close enough to what you are looking for. I just made the form with no border and put a picture box over the whole thing.
Just add a picturebox to your form and set size mode to "StretchImage" and visible= false, then add the following events to your datagridview
private void metroGrid1_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv_sender = sender as DataGridView;
DataGridViewCell dgv_MouseOverCell=null;
if (e.RowIndex > 0 && e.ColumnIndex > 0 && e.RowIndex <dgv_sender.RowCount && e.ColumnIndex<dgv_sender.ColumnCount)
{
dgv_MouseOverCell = dgv_sender.Rows[e.RowIndex].Cells[e.ColumnIndex];
}
if(dgv_MouseOverCell !=null)
if (e.ColumnIndex == 4) {
if (dgv_MouseOverCell.Value != null)
{
if (File.Exists(dgv_MouseOverCell.Value.ToString()))
{
Image img = Image.FromFile(dgv_MouseOverCell.Value.ToString());
pictureBox1.ImageLocation = dgv_MouseOverCell.Value.ToString();
pictureBox1.Location = new System.Drawing.Point(Cursor.Position.X - this.Location.X, Cursor.Position.Y - this.Location.Y);
pictureBox1.Visible = true;
}
}
}
}
private void metroGrid1_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
pictureBox1.Visible = false;
}
Click here to view image
void CustomizedToolTip_Popup(object sender, PopupEventArgs e)
{
DataGridView parent = e.AssociatedControl as DataGridView;
if (parent.CurrentCell != null)
{
if (parent.CurrentCell.ColumnIndex == 2)
{
string path = parent.CurrentCell.Value.ToString();
using (System.Drawing.Imaging.Metafile emf = new System.Drawing.Imaging.Metafile(path))
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(emf.Width, emf.Height))
{
bmp.SetResolution(emf.HorizontalResolution, emf.VerticalResolution);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
{
g.DrawImage(emf,
new Rectangle(0, 0, emf.Width, emf.Height),
new Rectangle(0, 0, emf.Width, emf.Height),
GraphicsUnit.Pixel
);
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
}
}
}
}
Source
To use the System.Windows.Interop
"You have to download the .NET 3.0 runtime or later and install it to get
the assembly..."
"After .NET 3.0 is installed, it should appear in the Add References
list with component name as "WindowsBase". If it doesn't you can
always add it from the Browse tab in the Add References dialog.
(C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0 on my
box)"
Source
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.