I need to handle some behaviour requiring to identify the grid's row and column index for a given point on the screen (like mouse coordinates).
Given a System.Drawing.Point corresponding to mouse coordinates, how can I retrieve the grid's row and column index?
Just use the built-in methods, each taking a coordinate.
Example, get the clicked cell in an overridden MouseDown event:
protected override void OnMouseDown(MouseEventArgs e)
{
Int32 row = RowContaining(e.Y);
Int32 col = ColContaining(e.X);
}
Or, if you have a reference to the grid, the same thought applies:
Int32 row = Grid.RowContaining(yCoord);
Int32 col = Grid.ColContaining(xCoord);
You can also use the Point with ComponentOne's PointAt method to identify the clicked region:
C1.Win.C1TrueDBGrid.PointAtEnum ptEnum - Grid.PointAt(e.X, e.Y);
Related
Is there any way to set the style of a row based on some value from a column that is not visible to the user? The grid contains a couple of rows and I want some rows to be colored in red if they were deleted. I have a hidden column that stores true if the columns were deleted, false otherwise. I've tried CellFormatting but since my column is not visible, e.ColumnIndex never has the correct value for my hidden column.
Any help will be greatly appreciated.
Edit:
Below is an image of what I am trying to accomplish. You can see that the second row has the text red which is due to the values in a column that the user cannot see in the datagrid. This grid should be colored like this when the user see the form for the first time too (on load).
Instead of CellFormatting, try CellValueChanged for unbound data or DataBindingComplete for a bound data set. For example, let's say that you are "deleting/undeleting" a row using the following Button.Click event:
private void Button1_Click(object sender, EventArgs e)
{
bool value = (bool)dataGridView1.CurrentRow.Cells["Deleted"].Value;
dataGridView1.CurrentRow.Cells["Deleted"].Value = !value;
// For bound data (like a DataTable) add the following line:
// ((DataTable)dataGridView1.DataSource).AcceptChanges();
}
Unbound Data
Changing the rows "deleted" column value in this way will trigger the following event handler. Therefore, you can color your row based on that column's value of True or False:
private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == dataGridView1.Columns["Deleted"].Index)
{
dataGridView1.Rows[e.RowIndex].DefaultCellStyle.ForeColor = (bool)dataGridView1[e.ColumnIndex, e.RowIndex].Value ? Color.Red : Color.Black;
}
}
Bound Data
For bound data, such as from a DataTable, handling the DataBindingComplete event will be enough. This event will trigger when the binding is first set as well as after changes - such as the changes from the Button1.Click event. Here, you'll loop through the rows and set the desired style according to the hidden column's value. (Note the additional change to the Button1_Click event handler for a grid with a DataTable source. This is needed to give an immediate style change - otherwise it won't happen until you navigate to a different row.)
private void DataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
row.DefaultSCellStyle.ForeColor = (bool)row.Cells["Deleted"].Value ? Color.Red : Color.Black;
}
}
Based on my understanding, you want to get a column's value when the column is a invisible column in DataGridView.
Is it right? Please correct me if I'm wrong.
private void button1_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = CreateDataTable();
dataGridView1.Columns["ID"].Visible = false; // Set the ID column invisible.
MessageBox.Show(dataGridView1.Rows[2].Cells["ID"].Value.ToString()); // Get the ID column value.
}
I have a grid which contains 2 rows and 2 columns. Each cell hosting a windows forms host control. I want to capture the selected cell when the user clicks on any of the cell. I have searched and found that there is no 'Click' event but I can make use of 'MouseDown' event with similar results. But now I am stuck because you would think there must be an easier way like 'GetCurentRow' and 'GetCurrentColumn' to capture the selected cell but there isn't.
What I want further to do is to get the child element in that particular cell of the grid.
I tried the following code but no matter which cell I click, I always get 0 for the row and column:
void InnerGridToContainWindowsFormsHost_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var element = (UIElement)e.Source;
int c = Grid.GetColumn(element);
int r = Grid.GetRow(element);
}
Is there any way to get the selected/clicked cell details or the children inside the cell?
I think that you may be going down the wrong route here... if you just want to know what control was clicked on, try using the VisualTreeHelper.HitTest method. You can find information on the VisualTreeHelper.HitTest Method page on MSDN. Basically, you would do something like:
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Get the position of the mouse pointer relative to the grid
Point clickPoint = e.GetPosition(grid);
HitTestResult result = VisualTreeHelper.HitTest(grid, clickPoint);
if (result != null)
{
// Do something here
}
}
You may also need some kind of basic recursive function to drill down through the Visual objects until you get to the one you want.
I'm binding a datagrid to a DataView. I would like to hide the ID column when the data is displayed. The ID column needs to exist in the data as it is used in another part of my code.
The ID column is always the first (index 0) column.
Am I right in thinking that the DataContextChanged event doesn't guarantee that all columns have been refreshed?
How can I ensure that binding has finished before hiding the column? Ideally, I would like to hide it by its column name.
EDIT: Forgot to say that I can't specify the columns in XAML, as they are generated from dynamic SQL.
I figured it out.
In the AutoGeneratingColumn event, I'm checking the DataGridAutoGeneratingColumnEventArgs header value and canceling the operation if it matches the column header.
Private void dataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
if (e.Column.Header.ToString() == "ID")
{
e.Cancel = true;
}
}
There is a datagrid with n number of rows, the first column in the Grid is a CheckBox column, now i want to enable/Disable some of the Rows(so that user cannot check the checkbox) of datagrid depending on some values.o How is it possible using MVVM pattern.
You are probably binding a list (IEnumerable) of data objects to your grid. To keep it nice and clean, what you need to do is wrap each of those data objects with another object, let's call it the RowViewModel. This RowViewModel can then hold extra properties, like a boolean which you can bind your checkbox's IsEnabled property to, that boolean can be calculated from the state of the data object, or even from the state of the parent view model should you pass a reference of it to the RowViewModel.
You can also extend this a little further and have row specific context menu items controlled by each RowViewModel, etc. Using the RowViewModel in this way ensures that you keep your data object nice and pure, you don't pollute it with stuff it doesn't need.
Using the LoadingRow event for each row you can update the controls in any cell you desire. For instance,
private void MyDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
MyDataObjectClass dataContext = (e.Row.DataContext as MyDataObjectClass);
foreach (DataGridColumn col in from cols in MyDataGrid.Columns orderby cols.DisplayIndex select cols)
{
FrameworkElement fe = col.GetCellContent(e.Row);
DataGridCell result = fe.Parent as DataGridCell;
// as an example, find a template column w/o a sort member path
if (col is DataGridTemplateColumn && col.SortMemberPath == null)
{
CheckBox button = VisualTreeExtensions.GetChildrenByType<CheckBox>(fe)[0];
button.IsEnabled = true; // insert your data condition...
}
}
}
In project there is a DataGridView.
I have a little bit of code that I which displays information based on
the cell that was clicked.
My problem is how to detect if the user clicked on a column or row
header (anything other than a cell).
All this is tied to the 'dataGridView1_CellMouseDown' method, and I'm using
the HitTest to attempt to detect what the user clicked, but all I'm
getting is 'TopLeftHeader' when the user clicks a cell and 'None'
everywhere else and the Row index always comes as -1
Using the CellMouseDown event gives you coordinates relative to the cell that was clicked.
Use the control's MouseDown event instead, which will give you control-based coordinates.
See the example on MSDN.
You can still use the CellMouseDown event handler. In fact i find it a bit cleaner because with MouseDown event, you have to create a HitTest to get the selected row.
The following code is equivalent:
private void dgv_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
{
// If right-click
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
// Get selected row
var selectedRow = dgvBatches.Rows[e.RowIndex];
}
}
private void dgv_MouseDown(object sender, MouseEventArgs e)
{
// If right-click
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
// Get the selected row/column
DataGridView.HitTestInfo info = dgvBatches.HitTest(e.X, e.Y);
// Get selected row
var selectedRow = dgvBatches.Rows[info.RowIndex];
}
}