I have a Form, that contain a DataGridView control named gridParameters.
I'm adding control on-top of it, based on some values, to add controls that are not available (for example, DateTimePicker):
DateTimePicker dtp = new DateTimePicker();
gridParameters.Controls.Add(dtp);
dtp.Location = rowCellLocation;
dtp.Size = rowCellSize;
dtp.CustomFormat = "yyyy/MM/dd";
dtp.Format = DateTimePickerFormat.Custom;
dtp.Tag = rowId;
dtp.ValueChanged += dtp_SelectedValueChanged;
dtp.Visible = true;
That code is inside a loop that iterate throgh the grid rows, and is in an If statement (I add DateTimePicker for some rows and NumericUpDown for others based on a row cell value). The variables rowCellLocation, rowCellSize and rowId are set in a loop for each row.
My DataGridView selection mode is a full row selection.
I want to make the added control (DateTimePicker, NumericUpDown...) get focus when I switch to the row, for example, when I click on a row with the mouse.
To do so, I've tried the following:
In the loop that creates the controls, I set the control to the relevant row Tag property.
In the grid Row_Enter event (I also tried CurrentCellChanged) I added the following code:
if (gridParameters.CurrentRow.Tag != null)
{
((Control)gridParameters.CurrentRow.Tag).Focus();
}
I've also tried using Select() and also
this.ActiveControl = (Control)gridParameters.CurrentRow.Tag;
None of the above sets focus to the control.
I place a break point, and the code is getting to this line, the Tag property contain the control that need to be focused, and execute it, but I can't get the control to focus.
UPDATE: Setting focus to another control outside of the DataGridView, works just fine (for example, setting focus to an "OK" button works).
Related
I have a GridView(GV_AssignedCRNs) where users can select a row through a checkbox and in the same row they also select from a radio button list. I want to be able to then display the selected radio button list value in another gridview(GridView1). My problem is that I don't know how to set the cell value without having to specify which row to set it in. How can I set the cell value programatically? See LAST line of code. Thank you!
foreach (GridViewRow row in GV_AssignedCRNs.Rows)
{
//gets checkbox value which is the crn of selected row
string checkboxvalue = Request.Form["chkboxrequest"];
//places commas in the correct order if more than one crn value selected by checkbox
string replacementchkbxval = checkboxvalue.Replace(",", "','");
//gets radio button value stores it in a string, then a session variable
RadioButtonList rad = (RadioButtonList)row.FindControl("FormRadioButton");
string selectedRad = rad.SelectedValue;
//if they selected a checkbox for the courses
if (replacementchkbxval != null)
{
ShowResults.Visible = true;
//Oracle connection stuff goes here
if (oracleDS3.Tables[0].Rows.Count > 0)
{
GridView1.DataSource = oracleDS3;
GridView1.DataBind();
if (selectedRad != null)
{
`GridView1.Rows[0].Cells[7].Text` = selectedRad;
}
Would it not be better to fire a event when they check the box, or "change" the radio button list?
In fact, would not just clicking on that row make sense to trigger display of the other “div” with the grid that displays information based on the current row from the grid?
In other words?
Clicking on the grid row.
Or clicking on the check box on that grid row.
Or clicking on the radio button “list” on that grid row?
Does not all of the above warrant that we really just want the “show details” event to trigger in all of the above cases?
So, if they click on a row – then we trigger the detail display. And if while on that row, if we click the text box, or the radio button list – once again our event should fire.
And of course if they click on a check box (or radio button) on a differ row, then we need that control to change and THEN AGAIN fire our display list. So we want the 2nd event + display to follow the above design (at least I think we do???)
So, it seems to me our goal is:
Clicking on a row – be it the result of clicking on a check box radio button or “just” on the row – we need to get that row information and “send” it to our second display grid (or whatever it may be). That way, a user can click on any row - our details (other grid or whatever) will now display.
Ok,
So, lets first use a neat-o trick to get the row index changed event to fire ALWAYS WHEN we click on that row (don’t matter if check box, don’t matter if radio button list, don’t matter if any place else on the row). (we can pick up the values anyway)
So, in our row data bound event, we can add this little gem. (it’s a bit ugly), but ONCE done, then we can just write easy pure code to deal with EVERYTHING else!
Ok, so in our row data bound, we add this to ALWAYS ensure that the selected index changed event fires.
That magic act, that Rosetta stone, that miracle? That of having Santa Clause climb down the chimney and give you presents?
We do this:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onclick") =
Page.ClientScript.GetPostBackClientHyperlink(GridView1, "Select$" & e.Row.RowIndex)
e.Row.ToolTip = "Click to select this row."
End If
End Sub
So now, we have the all valuable "index change" event to fire anytime we click on a row.
Now the Christmas present time.
It turns out that even if you click on the row again the index change fires. So, clicking anywhere - and that includes the radio button, or check box? Our index change event fires!! and that is EXACTLY what we need and want.
So, now we just move ALL of our "update/display/show/fill/" of that 2nd grid areas display.
Our code now becomes this because that all important index change fires:
Protected Sub GridView1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles GridView1.SelectedIndexChanged
' get selected index of row selected
Dim ixRow As Integer = GridView1.SelectedIndex
Debug.Print("sel grid index row = " & ixRow)
' (might not need the above, but with index into grid
' - the world is at your beck and call
' get current grid row:
Dim gv As GridViewRow = GridView1.SelectedRow
' (we we could I suppose use GridView1.Rows(ixRow)
' now get Radio button value:
Dim MyRadioList As RadioButtonList = gv.FindControl("RadioButtonlist1")
Debug.Print("Radio selection value = " & MyRadioList.SelectedValue)
Debug.Print("Radio selection index = " & MyRadioList.SelectedIndex)
' get the check box value
Dim MyCheckBox As CheckBox = gv.FindControl("CheckBox1")
Debug.Print("check box value = " & MyCheckBox.Checked)
' code here to update your 2nd display
' walk the dog - do whatever you want
' Call displayInfo2(gv)
End Sub
if anything changes - such as the radio button, or the check box, our index event will fire again - and does so even if the Radio button list and the check box on that row changes - again just what the doctor ordered.
This also means we toss out all kinds of looping code.
So now, Bob is your uncle!
I'm trying to replicate this behavior in the ColumnMappings window from SQL Management Studio:
Image Here
When you click inside a destination cell, the type changes from text
to combobox (it seems), and when you leave the cell, it takes the selected value from the combobox and changes back to textboxCell with the value included.
It does this for every cell in that column.
So, when I load the data, all the cells are textbox, and when the user enters any cell in that column, I do this:
private void dgvwMapping_CellEnter(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
string txt = dgvwMapping[e.ColumnIndex, e.RowIndex].Value.ToString();
DataGridViewComboBoxCell cbbxDestination = new DataGridViewComboBoxCell() { DataSource = new List<string>(someList) };
cbbxDestination.Value = txt;
dgvwMapping[e.ColumnIndex, e.RowIndex] = cbbxDestination;
}
}
So far so good, if I change from cell to cell everything goes fine, except when I click the cell that has the coordinates [1,1]. The only one that throws the "Operation is not valid because it results in a reentrant call to the SetCurrentCellAddressCore" exception is the one with the columnIndex equal to the rowIndex.
I already tried wrapping the line where I reassign the Cell Type in an invoke call, like this:
dgvwMapping.BeginInvoke(new MethodInvoker(delegate ()
{
dgvwMapping[e.ColumnIndex, e.RowIndex] = cbbxDestination;
}));
But It loops indefinitely the event. Even wrapping all the code inside the event makes the event loop indefinitely.
I haven't coded anything inside the CellEndEdit or the CellLeave yet.
Does anyone have any advice? Perhaps my aproach at replicating that behavior is not the best.
Thanks
Your issue:
When you click inside a destination cell, the type changes from text to combobox (it seems), and when you leave the cell, it takes the selected value from the combobox and changes back to textboxCell with the value included.
is just a simple style setting for the DataGridViewComboBoxColumn property:
yourGridColumnComboBox.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
This will make it appear like a TextBox, but when it has focus with selectable items, it will show the drop down button.
I have WinForms DataGridView and BindingNavigator on the From bind to the same BindingSource.
When user enter text into a cell of DataGridView (cell text editor is visible) and press "Move next" in BindingNavigator,
it is assumed that the grid close cell text editor, text should be written in the DataTable Field and record end edit.
But the grid simply ignore the entered text, and returns the old value in to the cell.
Is it possible make grid to write the entered value when navigating through BindingNavigator?
It's possible. All you need is to set the CausesValidation property of the BindingNavigator class to true.
Note that this property is false by default and also is hidden by the BindingNavigator base class ToolStrip, so you cannot do that at design time (also the documentation of the property is misleading). But you can do that via code (for instance, inside your form Load event):
this.bindingNavigator.CausesValidation = true;
I have a form which initially has one row of boxes for user input. I have a button which, when clicked, should create an identical row below the previous. The button should be able to be clicked more than once, to add multiple rows.
How can I go about implementing this, in a way which gives each control in each row its own unique name (so I can refer to it in my program), and also keeping proper formatting of the rows?
I have tried to set up a class for rows as below:
class SubjectRow
{
//every row has these boxes, plus some more textboxes
public ComboBox subjectBox;
public Label maxBox;
public TextBox aBox;
public SubjectRow(ComboBox _subjectBox, Label _maxBox, TextBox _aBox)
{
subjectBox = _subjectBox;
maxBox = _maxBox;
aBox = _aBox;
}
}
...But I am stumped on how to have the button generate the new controls with their own names. My idea was something like this:
buttonClicked
{
SubjectRow row1 = new SubjectRow(subjectBox1, maxBox1, aBox1);
}
But I need a way to change the control names here without manually typing them all out; there could possibly be a lot of rows on the form.
Is there a way to add more rows to my form using a button, giving each control in each row a unique name? This needs to be done in some kind of loop.
The last column in my Datagrid is hyperlinked, every cell has an individual hyperlink. I want to be able to click on a cell, get the data within that cell, and using the hyperlink, redirect to another form, passing that data selected.
string AuditsRequired = (dgFake.Items[0] as DataRowView).Row.ItemArray[5].ToString();
xamlAllocteAudits AA = new xamlAllocteAudits(AuditsRequired);
AA.Show()
This is my first attempt at fetching the cell-data, however due to the code, I have specified a column and row, whereas I want the cell to be which ever cell I click, rather than specifying in code.
Here is my datagrid, showing the cells that have been hyperlinked:
http://i.stack.imgur.com/v7Uyw.png
If i understand your question correctly, you want to click on a cell and obtain the data from that cell. I suspect that the cellclicked event or currentcellchanged event are going to be the most useful to you for this task.
you could try something like
private void dgFake_CurrentCellChanged(object sender, EventArgs e)
{
int row = e.row;
int col = e.col;
if e.value !=null
{
string AuditsRequired = dgfake[row,col].value.tostring();
xamlAllocteAudits AA = new xamlAllocteAudits(AuditsRequired);
AA.Show()
}
}
You may or may not know this, but you can get VS to make this event method (or any event method) for you by clicking on the object (in your case the datagridviewer) in the designer and then clicking the events (little lightning bolt) icon in the properties window.
Hope that helps.
Cheers.