I have a Data Grid View like:
if (this.dgv.Rows.Count < 1)
{
this.dgv.DataSource = null;
this.dgv.DataBindings.Clear();
if (this.dgv.Columns.Count == 0) this.dgv.ColumnCount = 15;
this.dgv.ColumnHeadersVisible = true;
this.dgv.Columns[4].Name = "Added By";
this.dgv.Columns[5].Name = "AddedByFullName";
}
as you can see I have column 4 called Added By
this.dgv.Columns[4].Name = "Added By";
and column 5 called AddedByFullName
this.dgv.Columns[5].Name = "AddedByFullName";
I want to know how can I use AddedByFullName column as a tooltip for Added By column then I will just remove AddedByFullName column , is that possible? Regards
You can do this using the CellMouseEnter or CellToolTipTextNeeded event for the DataGridView. Hide the column you want to use as the source, then replace the control name in the sample to match your DataGridView.
private void dgv_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
{
if ((e.ColumnIndex == dgv.Columns["Added By"].Index)
&& (e.RowIndex > -1))
{
dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].ToolTipText = dgv.Rows[e.RowIndex].Cells[dgv.Columns["AddedByFullName"].Index].Value.ToString();
}
}
Using CellMouseEnter event can be a posibility to achieve this but it also can be done with CellFormatting event as Microsoft REFERENCE
private void dgJobNotes_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if ((e.ColumnIndex == this.dgJobNotes.Columns["Added By"].Index)
&& e.Value != null)
{
dgJobNotes.Rows[e.RowIndex].Cells[e.ColumnIndex].ToolTipText = dgJobNotes.Rows[e.RowIndex].Cells[5].Value.ToString();
}
The DataGridViewColumn class has a ToolTipText property. If you set it on the column, you will get a tool tip for the column header. If you want a tool tip to show up on every cell, you can implement a CellFormatting event handler, pull out the right cell (from the column) and set the cell's ToolTipText property. Something like:
private const int InterestingColumnNumber = 5;
private const string InterestingColumnToolTipText = "This Space For Rent";
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var senderGridView = sender as DataGridView;
if (senderGridView != null)
{
if (e.ColumnIndex == InterestingColumnNumber)
{
var cell = senderGridView.Rows[e.RowIndex].Cells[InterestingColumnNumber];
cell.ToolTipText = InterestingColumnToolTipText;
}
}
}
There is a CellToolTipTextNeeded event which is created specifically for setting tooltip text. You don't need to use use CellFormatting or CellMouseEnter. If you are going to show text of column 5 as tooltip of column 4, you can write:
private void g_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
{
if (e.ColumnIndex == 4 && e.RowIndex >= 0)
{
e.ToolTipText = $"{dataGridView1[5, e.RowIndex].Value}";
}
}
Related
I had a GUI that have a datagridview with button column.
I set the button enabled property to false once I click on the button cell.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridView senderGrid = (DataGridView)sender;
if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn && e.RowIndex >= 0)
{
//....
DataGridViewDisableButtonCell btnClick = (DataGridViewDisableButtonCell)dataGridView4.Rows[e.RowIndex].Cells[e.ColumnIndex];
btnClick.Enabled = false;
//execude code
btnClick.Enabled = true;
}
}
My question is how I make the other cell unclickable also to prevent the code run when one of the button cell is clicked?
You need to get the cells of type DataGridViewDisableButtonCell to get or set their properties. To avoid repeating the same code, create a method to toggle the Enabled property.
private void SetEnabled(bool enabled)
{
foreach (var cell in senderGrid.Rows.OfType<DataGridViewRow>()
.SelectMany(x => x.Cells
.OfType<DataGridViewDisableButtonCell>()))
cell.Enabled = enabled;
}
In case you have multiple columns of that type and you want to apply the change on a specific one, then you need to specify the target column:
private void SetEnabled(bool enabled, int columnIndex)
{
foreach (var cell in senderGrid.Rows.OfType<DataGridViewRow>()
.SelectMany(c => c.Cells
.OfType<DataGridViewDisableButtonCell>()
.Where(col => col.OwningColumn.Index == columnIndex)))
cell.Enabled = enabled;
}
Using the method in your code:
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var senderGrid = sender as DataGridView;
if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn && e.RowIndex >= 0)
{
SetEnabled(false);
// Or
// SetEnabled(false, e.ColumnIndex);
//execude code
SetEnabled(true);
// Or
// SetEnabled(true, e.ColumnIndex);
}
}
First I make an unbound column in GridView (using DevExpress):
public void buttonl_Click(object sender, EventArgs e)
{
//GridColumn clmn = gridaaa.Columns["code"];
if (gridaaa.Columns.ColumnByFieldName("idx") != null)
{
gridaaa.Columns.ColumnByFieldName("idx").Dispose();
}
GridColunn unbColumn2 = gridaaa.Columns.AddField("idx");
unbColumn2.VisibleIndex = gridaaa.Columns.Count;
unbColumn2.UnboundType = DevExpress.Data.UnboundColumnType.Integer;
//// Disable editing.
unbColumn2.OptionsColunn.AllowEdit = false;
// gridaaa.Columns.ColumnByFieldName("idx").Dispose();
}
In the gridView1_CustomUnboundColumnData event I am using this code
private void gridView1_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
{
if (e.Column.FieldName == "idx")
{
e.Value = e.ListSourceRowIndex;
}
}
for the output or result was:
The question is how to make the index or idx column value become static when I click sorting in any column header. As you can see when I click genre header the value follow with code or index in database, I want to make it like autonumber from 0 whenever I keep click column header of genre or anything:
You can use ColumnView.GetRowHandle method to get the handle of current row which is always reflects to the position of row in GridView from up to down.
Here is example:
private void gridView1_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
{
if (e.Column.FieldName == "idx")
e.Value = gridView1.GetRowHandle(e.ListSourceRowIndex);
}
I have the following code that highlights a cell when the user makes changes.
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
int selectedRow = e.RowIndex;
int selectedCol = e.ColumnIndex;
if (selectedRow >= 0 && selectedCol >=0 )
{
dataGridView1[selectedCol, selectedRow].Style.BackColor = Color.Yellow;
}
}
The user can sort a column prior to updating the cell. The data looks like this (note the price column is sorted in ascending order ) before updating:
I changed $40.98 to $45. The datagrid automatically sorts itself. The cell that is highlighted is where the updated call was located originally. The new cell that contains $45 is not highlighted.
Datagrid after the update and automatic sorting:
The datagrid's Sorted event is not fired during the automatic sorting process. Could anybody please show me show to fix the problem? Thanks!
The ListChanged (type ItemMoved) event is fired
I have had the same problem and I use this way:
I have declared a private variable in the class of the form:
private string id = string.Empty;
then my CellValueChanged method
private void dgvOggetto_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// other code
ID = dataGridView.Rows[dataGridView.CurrentCell.RowIndex].Cells["ID"].Value.ToString();
}
and I used the SelectionChanged method
private void dgvOggetto_SelectionChanged(object sender, EventArgs e)
{
// avoid fire the event if the Tag contains a keyword
if (dataGridView.Tag.ToString().Contains("updating")) return;
if (!string.IsNullOrEmpty(ID))
{
//find the row
DataGridViewRow row = dataGridView.Rows
.Cast<DataGridViewRow>()
.FirstOrDefault(r => r.Cells["ID"].Value.ToString().Equals(id));
if (row != null)
{
//select the row
dataGridView.Rows[row.Index].Selected = true;
dataGridView.Rows[row.Index].Cells[0].Selected = true;
// place the current row in the middle
dataGridView.FirstDisplayedScrollingRowIndex = (row.Index - (dataGridView.Height - dataGridView.ColumnHeadersHeight) / dataGridView.RowTemplate.Height / 2) > 0 ? row.Index - (dataGridView.Height - dataGridView.ColumnHeadersHeight) / dataGridView.RowTemplate.Height / 2 : 0;
}
// clean ID variable
ID = string.Empty;
}
}
Basically, when I click on the cell, I want to be able to get everything on that row to show up in another form.
I have this code on my Show Form:
public partial class showTask : Form
{
public string TaskID, TaskName, TaskDescription, TaskTimeAndDateCompletion;
public int TaskPriority;
public showTask()
{
InitializeComponent();
}
public void ShowTaskChosen()
{
showTaskIDRtb.Text = TaskID;
showTaskNameRtb.Text = TaskName;
showTaskDescRtb.Text = TaskDescription;
showTaskPriorityRtb.Text = Convert.ToString(TaskPriority);
showTaskTimeAndCompletionDate.Text = TaskTimeAndDateCompletion;
}
}
And on my DataGridView named tasksViewerDGV in my mainPage Form, I have this to try and get the values to show on another form:
private void tasksViewerDGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
int column = e.ColumnIndex;
int row = e.RowIndex;
DataGridView ShowTask = sender as DataGridView;
if (ShowTask == null)
return; //If the cell is null, then just return without sending any information
var cell = ShowTask[column, row];
if (cell != null)
{
DataGridViewRow rows = cell.OwningRow; //Which ever cell is clicked, it gets the row of that cell
showTask displayTask = new showTask();
displayTask.TaskID = rows.Cells["taskID"].Value.ToString();
displayTask.TaskName = rows.Cells["taskName"].Value.ToString();
displayTask.TaskDescription = rows.Cells["taskDescription"].Value.ToString();
displayTask.TaskPriority = Convert.ToInt32(rows.Cells["taskPriority"].Value.ToString());
displayTask.TaskTimeAndDateCompletion = rows.Cells["taskTimeAndDateCompletion"].Value.ToString();
displayTask.ShowDialog();
displayTask.ShowTaskChosen();
}
}
The problems are these: var cell = ShowTask[column, row]; as I get the IndexOutOfRange Exception. Furthermore, when debugging it say's -1 on 'row' variable. Finally, it takes me ages to trigger the event, sometimes I ave to press on the cell title multiple times for it to work. I have no clue what is going on, any light that could come my way would be greatly appreciated.
Kind Regards,
Kieran
Try this..
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex != -1)
{
string value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
}
}
CellContentClick event docs says:
This event occurs when the cell content is clicked
But cell content means just exactly the content of the cell and not some empty space in the cell. In that case you don't get the event fired.
In your context I would use CellMouseClick.
However this event is raised also in case you click the row or column headers of the grid. And for these cases the row or column index is -1.
You should have some kind of protection around these invalid values for row and column before trying to use them to find your grid cell.
private void dgv_CellClickMouse(object sender,
DataGridViewCellMouseEventArgs e)
{
DataGridView dgv = sender as DataGridView;
int column = e.ColumnIndex;
int row = e.RowIndex;
if(column == -1 || row == -1)
{
// for debug purpose...
Console.WriteLine("Not a valid row/column");
return;
}
DataGridViewCell cell = dgv[column, row];
if (cell != null)
{
......
}
}
I have a Datagridview which contains checkboxes in the first column, and text in the second.
When a Checkbox is clicked, the "CellValueChanging"-method is getting the index of the specific row.
How do I get the matching string-text? the Column-index of the text is always the same (1)
You can use GetRow() method to get row:
var row = TaskGridView.GetRow(1) as YourModel;
using ValueChangedEvent:
private void TaskGridView_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
if (e.RowHandle < 0)
return;
var row = TaskGridView.GetRow(e.RowHandle) as YourModel;
}
for speicific column you can do:
private void TaskGridView_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
if (e.RowHandle < 0)
return;
var row = TaskGridView.GetRow(e.RowHandle) as YourModel;
if (e.Column.FieldName.Equals("YourFieldName", StringComparison.InvariantCultureIgnoreCase))
{
// do something here
}
}