I have a DataGridView in a Winform desktop project in net 6.0
This DataGridView's generic row is composed by a DataGridViewCheckBoxCell in the first column, and another 6 DataGridViewTextBoxCells in the subsequent columns : the first one of the DataGridViewTextBOxCell (column 1) is permanently ReadOnly.
What I want to do is make the Cells from the second TextBox to the last one (that is columns 2 to 6) ReadOnly when the CheckBox is unchecked, and restore them to ReadWrite when the checkbox is checked.
What I do is override the dataGridViev.CellClick event, and when the sender is the element in column 0 (the checkbox) I get the row index and I iterate on the cells of the row from index 2 to 6 and set the ReadOnly property to true or false depending on the state of the checkobx itself.
The mechanism basically works fine, I read the event on the exact column/row, I correctly get the state of the checkobox (maybe in a not-so-smart way...) : but when it comes to setting the ReadOnly property I can see that ,in spite of iterating on the 2 to 6 column, it skips the cell in column 2 and sets the one in column 1 instead: all the settings on the other columns work correctly. I thought it was a matter of configuring the columns in the designer but all the columns from 2 to 6 are set identically.
My event handler is the following :
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 0) // if checkbox
{
int row = e.RowIndex;
bool setState = true;
DataGridViewCheckBoxCell check = (DataGridViewCheckBoxCell)(dataGridView1.Rows[row].Cells[0]);
if (check.Value != null && check.Value == "true")
{
setState = true;
check.Value = "false";// CheckState.Unchecked;
}
else
{
setState = false;
check.Value = "true";// CheckState.Checked;
}
for (int i = 2; i < dataGridView1.Rows[row].Cells.Count; i++)
{
DataGridViewTextBoxCell txt = (DataGridViewTextBoxCell)(dataGridView1.Rows[row].Cells[i]);
txt.ReadOnly = setState;
if (setState) txt.Style.BackColor = Color.Gray;
else txt.Style.BackColor = Color.White;
}
}
}
Related
The following code returns -1 for each displayed column.
Anyone knows the answer? I tried to use ColumnDisplayIndexChanged event. But it did not show anything.
i.konuk
private void dg_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
string headername = e.Column.Header.ToString();
//Cancel the column you don't want to generate
if (headername == "Occupation")
{
e.Cancel = true;
}
//update column details when generating
if (headername == "FirstName")
{
e.Column.Header = "First Name";
}
//update column details when generating
if (headername == "LastName")
{
e.Column.Header = "Last Name";
}
int myin = e.Column.DisplayIndex;
System.Text.StringBuilder messageBoxCS = new System.Text.StringBuilder();
messageBoxCS.AppendFormat("{0} = {1}", "Column", myin);
messageBoxCS.AppendLine();
MessageBox.Show(messageBoxCS.ToString(), "DataGridAutoGeneratingColumnEvent");
}
AutoGeneratingColumn event occurs when an individual column is auto-generated in other words the event is called when columns are forming in the dataGrid. This means no columns are displayed yet.
DataGridColumn.DisplayIndex property displays the position of the column in the DataGrid. We have not yet displayed the columns in AutoGeneratingColumn event. The DisplayIndex property has a default value of -1 before it is added to the DataGrid.Columns collection.
Thats why you are getting the default value of -1.
ColumnDisplayIndexChanged Event is called when you have selected a particular column and changed the dispayed order in the DataGrid.
Hope I have answered your Question!
I have a combobox that is created with data from a dataset
foreach(var item in ds.MiDESValues)
{
string comboboxtext = ds.MiDESValues.Rows[k][1].ToString();
sFactorCB.Items.Add(comboboxtext);
k++;
}
On a selectionchanged event it will populate a listbox with that selection
private void sFactors_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string add = sFactorCB.SelectedValue.ToString();
var svalue = ds.MiDESValues.Rows[0][2].ToString();
int Svalue = int.Parse(svalue);
SValue.Add(svalue);
SelectionListBox.Items.Add(add);
SelectionBox.Add(add);
// when a new item is added to Selection list box, select it and show it
// this will keep the last item highlighted and as the list grows beyond
// the view of the list box, the last item will always be shown
SelectionListBox.SelectedIndex = SelectionListBox.Items.Count - 1;
SelectionListBox.ScrollIntoView(SelectionListBox.SelectedItem);
}
That list box then used to populate a listbox used on the next page. If I navigate to the next page and then navigate back, the combobox is still showing the last selection I made therefor the listbox is being populated with that value.
I have tried setting the selectedindex of the combobox to sFactorCB.SelectedIndex = -1;, at the end of the sFactors_SelectionChanged event but i get System.NullReferenceException. How can I get the combobox to reset back to a non-selected item state? Thanks
Actually, you are doing it correctly. To clear the selection either set the SelectedIndex to -1 or the SelectedItem to null.
The problem is that once you do that your sFactors_SelectionChanged gets called again and since there is no current selection, the SelectedValue property is null thus causing the following to fail:
string add = sFactorCB.SelectedValue.ToString();
How to solve this sort of depends on your intended results when nothing is selected. The simplest thing to do would be to just check for nothing selected at the start of the handler and simply return.
private void sFactors_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sFactorCB.SelectedIndex == -1 || sFactorCB.SelectedValue == null)
return;
string add = sFactorCB.SelectedValue.ToString();
...
I bound a DataTable to a datagrid in wpf. The first column has unique values. Now I would like to autoselect a cell in the second column whose first column cell has the given value. How should I achieve that? For example,here is my datagrid:
Name | Age
cat | 2
dog | 3
When user input 'dog', I will need the '3' to be selected.
I tried the method show here:
How to select a row or a cell in WPF DataGrid programmatically?
However, I cannot figure out the displaying row number. Even though I know the row number of the dataTable, the display number can be different since I allow users to sort the table.Thanks a lot.
Set your grid's SelectionUnit property to "Cell", and assuming you feed the DataGrid with the table's DefaultView:
private void button1_Click(object sender, RoutedEventArgs e)
{
// Search for the source-row.
var Element = MyDataTable.AsEnumerable()
.FirstOrDefault(x => x.Field<string>("Name") == "horse");
if (Element == null) return;
// Found the row number in the DataGrid
var RowOnGrid = MyGrid.Items.OfType<DataRowView>()
.Select((a, Index) => new { data=a.Row, index = Index })
.Where(x=> x.data == Element)
.Select(x => x.index)
.FirstOrDefault();
// Assuming the desired column is the second one.
MyGrid.SelectedCells.Clear();
MyGrid.SelectedCells.Add(new DataGridCellInfo(MyGrid.Items[RowOnGrid], MyGrid.Columns[1]));
}
It should work even if you re-sort the rows.
I have several radio buttons that are dynamically populated on a form and I have set a click event on the dynamically created radio buttons. On click i get a returned value as follows through debugging (eg) "sender { Text = "this is answer one" + Checked = "True"} using code as follows:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
string radioButtonValue = rb.Text;
if (radioButtonValue != String.Empty)
{
}
}
The debug values are returned via "RadioButton rb = sender as RadioButton;" - the diffrent radio buttons text is set via a dataset that I call in a local dataset that loops through the dataset and and sets the radio button text accordingly (eg):
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Text = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i]["tbl_QuestionnaireAnswer_Description"].ToString();
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
So: wat id like to know is on the radio button click (Form1_Click) event is it possible to return the primary key of the of the selected radio button that I choose and not just the sender { Text = "this is answer one" + Checked = "True"} as I would like to use the primarykey in that dataset to write back to my Database.
Thanks in advance.
Kind regards
geo
Most winforms controls contain the Tag property that is used to contain custom user data in the control. You can read more at: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.tag.aspx
So, your solution should be simpler and more concise like this:
for (int i = 0; i < _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows.Count; i++)
{
radioButtons[i] = new RadioButton();
radioButtons[i].AutoCheck = true;
radioButtons[i].Location = new System.Drawing.Point(60, 20 + i * 20);
radioButtons[i].Tag = _dataSetRadioButtons.Tables["tbl_QuestionnaireAnswer"].Rows[i];
radioButtons[i].Click += new EventHandler(Form1_Click);
panel.Controls.Add(radioButtons[i]);
}
This includes a relevant datarow in the radiobutton. The next thing is to get any data from it you need:
//Radio button click:
void Form1_Click(object sender, EventArgs e)
{
RadioButton radioButton = sender as RadioButton;
if (radioButton == null)
return;
DataRow row = radioButton.Tag as DataRow;
if (row == null)
return;
/* Post any processing here. e.g.
MessageBox.Show(row["ID"].ToString());
*/
}
This way you have all the data and it's strongly typed, which is a good thing.
We have a problem for focus a cell of DataGrid after Its data of bounded collection has Refreshed.
for example we set a filter for its collection and then we want to refocus a stored cell of stored column.
Is it true that we think a call to ScrollIntoView is synchronized it means after call it our desired row and cell are created and we can set focus? (again it means after we call to ScrollIntoView , Is it true we think that Itemsgenerator finished its work and we can surly find our desired cell)
$
//set filter of DataGrid Collection
DataGrid_Standard.ScrollIntoView(rowNumber,cellNumber);
//we sure our desired cell are created now
DataGridRow row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
// may be virtualized, bring into view and try again
DataGrid_Standard.ScrollIntoView(DataGrid_Standard.Items[index]);
row = (DataGridRow)DataGrid_Standard.ItemContainerGenerator.ContainerFromIndex(index);
}
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
// now try to bring into view and retreive the cell
DataGrid_Standard.ScrollIntoView(rowContainer, DataGrid_Standard.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column); cell.focus();
Related
Here's a datagrid Selection changed event handler that moves a virtualized row into view and then sets the focus to that row. This works for me:
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dg = (DataGrid)sender;
if (dg.SelectedItem == null) return;
dg.ScrollIntoView(dg.SelectedItem);
DataGridRow dg_row = (DataGridRow)dg.ItemContainerGenerator.ContainerFromItem(dg.SelectedItem);
if (dg_row == null) return;
dg_row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
EDIT: Using the dg_row.MoveFocus method had an undesriable effect (a checkbox column required two clicks to set instead of one) and it worked better for me to just use
dg_row.Focus();
Action action = () =>
{
dg .ScrollIntoView(dg .SelectedItem);
var item = dg.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
if (item == null) return;
item.Focus();
};
Dispatcher.BeginInvoke(DispatcherPriority.Background, action);
This should work fine for your case.