TableRow.FindControl(cell.ID) returns null - c#

why doesn't the cell i just added to a row get found with FindControl()?
// cell
var cell = new System.Web.UI.WebControls.TableCell();
cell.ID = "cell";
// cell in row
var row = new System.Web.UI.WebControls.TableRow();
row.Controls.Add(cell);
// get cell from row
var foundCell = row.FindControl(cell.ID);
foundCell becomes null

To FindControl a dynamic item that created from back-end programming code, asp.net need to post_back to add the Control to DOM.
In your case, you need to separate your Adding Control function and Finding Control function in different asp.net life-cycle.
First, Create the Control in Page_Init:
public void Page_Init(object sender, EventArgs e)
{
// cell
var cell = new System.Web.UI.WebControls.TableCell();
cell.ID = "cell";
// cell in row
var row = new System.Web.UI.WebControls.TableRow();
row.Controls.Add(cell);
}
Then you can find the Control in Page_Load:
protected void Page_Load(object sender, EventArgs e)
{
// get cell from row
var foundCell = Page.FindControl("cell"); // or you can store the cell Id in a string variable
}
You can find more info on MSDN, on the ASP.NET Page Life Cycle article.

row.findControl(cell.ID) is not working in your case and you can replace it with below logic and its working fine.
var foundCell = row.Cells[row.Cells.GetCellIndex(cell)];

Related

string values of selected row in datagridview by clicking ANYWHERE in that row

I am using the code below to retrieve values from the selected row it works... but has a glitch.... It will only retrieve the strings if you click on the actual text in any cell of that row.... if you click anywhere of white area in a cell of that row it will not execute .. Any ideas as to how to fix this glitch??
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
listBox1.ClearSelected();
OnlineNamebox.Text = "";
OnlinePasswordbox.Text = "";
OnlineEmailbox.Text = "";
OnlineShortcodebox.Text = "";
ListCombobox.Text = dataGridView1.CurrentRow.Cells[0].Value.ToString();
OnlineNamebox.Text = dataGridView1.CurrentRow.Cells[1].Value.ToString();
OnlineEmailbox.Text = dataGridView1.CurrentRow.Cells[2].Value.ToString();
OnlinePasswordbox.Text = dataGridView1.CurrentRow.Cells[3].Value.ToString();
OnlineShortcodebox.Text = dataGridView1.CurrentRow.Cells[5].Value.ToString();
}
I found a work around for obtaining the cell values based off of dash's answer on a kind of similar question using the cellmouseclick instead of cellclick
with the code below it dont matter where you click at in the row it executes the strings even if not directly clicking on the text in a cell
private void DatagridView1_CellMouseClick(Object sender, DataGridViewCellMouseEventArgs e)
{
ListCombobox.Text = this.dataGridView1.CurrentRow.Cells[0].Value.ToString();
OnlineNamebox.Text = dataGridView1.CurrentRow.Cells[1].FormattedValue.ToString();
OnlineEmailbox.Text = dataGridView1.CurrentRow.Cells[2].Value.ToString();
OnlinePasswordbox.Text = dataGridView1.CurrentRow.Cells[3].Value.ToString();
OnlineShortcodebox.Text = dataGridView1.CurrentRow.Cells[5].Value.ToString();
}
and I added the code below to the load event
dataGridView1.CellMouseClick += DatagridView1_CellMouseClick;
hope it helps anyone who runs into this particular problem or that is looking for the basics

Change visible state of DataGridView only given its name

I have a form application where multiple DataGridView objects are to be displayed (but not at once). They should be created on top of each other and it should then be possible to toggle the displayed DataGridView using a ComboBox.
I have a function which should create new DataGridView every time its called and then adds the name to the ComboBox:
private void readCSV(string DBname)
{
DataGridView tagDBname = new DataGridView();
tagDBname.Location = new System.Drawing.Point(24, 260);
tagDBname.Name = DBname;
tagDBname.Size = new System.Drawing.Size(551, 217);
tagDBname.TabIndex = 6;
tagDBname.Columns.Add("Column1", "Col1");
tagDBname.Columns.Add("Column2", "Col2");
tagDBname.Visible = false;
comboBoxTag.Items.Add(DBname);
}
Then I would like to change the visibility state of a DataGridView given the selected name from the ComboBox. This should be done in the function called when the index changes:
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
DataGridView tagDatabase = ? // Here the DataGridView should be selected given the name "selectedTagDB"
tagDatabase.Visible = true;
}
In the above, I do not know how to assign the DataGridView only given its name. Any help would be appreciated - even if it means that the selected approach is inappropriate of what I am trying to achieve. If the question is answered elsewhere, feel free to guide me in the right direction :)
I would store the gridviews in a dictionary by using the DB name as key;
private readonly Dictionary<string, DataGridView> _tagDBs =
new Dictionary<string, DataGridView>();
private void readCSV(string DBname)
{
DataGridView tagDBname = new DataGridView();
// Add the gridview to the dictionary.
_tagDBs.Add(DBname, tagDBname);
tagDBname.Name = DBname;
tagDBname.Location = new System.Drawing.Point(24, 260);
tagDBname.Size = new System.Drawing.Size(551, 217);
tagDBname.TabIndex = 6;
tagDBname.Columns.Add("Column1", "Col1");
tagDBname.Columns.Add("Column2", "Col2");
tagDBname.Visible = false;
this.Controls.Add(tagDBname); // Add the gridview to the form ot to a control.
comboBoxTag.Items.Add(DBname);
}
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
foreach (DataGridView dgv in _tagDBs.Values) {
dgv.Visible = dgv.Name == selectedTagDB; // Hide all gridviews except the selected one.
}
}
If you need to do something with the selected gridview, you can get it with:
if (_tagDBs.TryGetValue(selectedTagDB, out DataGridView tagDatabase)) {
// do something with tagDatabase.
}
Note: you must add the gridview to the form or to a container control on the form. E.g.
this.Controls.Add(tagDBname);
You can loop through all DataGridViews of the form to display the expected one using its name, while hidding the others ones.
This solution isn't pretty but works
private void ShowOneDataGridViewAndHideOthers(string name)
{
foreach (var DGV in this.Controls.OfType<DataGridView>())
{
DGV.Visible = DGV.Name == name;
}
}
And call it this way :
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
ShowOneDataGridViewAndHideOthers(selectedTagDB);
}
The method can be made a bit more generic this way :
private void ShowOneControlAndHideOthers<T>(string name, Control controls) where T : Control
{
foreach (var control in controls.Controls.OfType<T>())
{
control.Visible = control.Name == name;
}
}
private void comboBoxTag_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the name of the DataGridView which should be visible:
string selectedTagDB = comboBoxTagDatabases.SelectedItem.ToString();
ShowOneControlAndHideOthers<DataGridView>(selectedTagDB, this);
}

Add hyperlink to gridview programmatically

I have a gridview and need to add controls to header row. I am able to add text, but how can I add a hyperlink to the header row.
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.Header)
{
GridView HeaderGrid = (GridView)sender;
GridViewRow HeaderGridRow = new GridViewRow(0, 0, DataControlRowType.Header, DataControlRowState.Insert);
TableCell HeaderCell = new TableCell();
HeaderCell.Text = "Logistics Details";
HeaderCell.ColumnSpan = 2;
HeaderGridRow.Cells.Add(HeaderCell);
GridView1.Controls[0].Controls.AddAt(0, HeaderGridRow);
HyperLink hl = new HyperLink();
hl.ID = "hlDetail";
hl.Text = "Details";
//the below line doesn't add controls
HeaderGridRow.Controls.Add(hl);
}
}
I think you would have to add the control to a specific Cell within the row, e.g.
HeaderGridRow.Cells[0].Controls.Add(hl);
Since it's a grid, it's not logical for items to exist within a row outside a cell - then there is no way to know where exactly to display it.
You probably also need to set the NavigateUrl property of the Hyperlink, otherwise it does not know where to navigate e.g.
hl.NavigateURL = "https://www.google.com"

Accessing dynamically generated dropdownlist in Gridview_RowUpdating event

I am using Gridview with AutoGenerateColumns="True", so gridview columns are generated dynamically. Now in case of edit, I am adding dropdownlist dynamically for one of the field in the gridview. Please see following code:
protected void grdViewConfig_RowEditing(object sender, GridViewEditEventArgs e)
{
grdViewConfig.EditIndex = e.NewEditIndex;
BindGridView();
clientBAL = new TMIWsBALClient();
var lstAppIds = clientBAL.GetDistinctApplicationIds();
GridViewRow grdRow = grdViewConfig.Rows[e.NewEditIndex];
for (int i = 0; i < grdRow.Cells.Count; i++)
{
if (grdRow.Cells[i].GetType().Equals(typeof(DataControlFieldCell)))
{
DataControlFieldCell dcField = (DataControlFieldCell )grdRow.Cells[i];
if (dcField.ContainingField.HeaderText.ToLower().Equals("applicationid"))
{
DropDownList drpDwnAppIds = new DropDownList();
drpDwnAppIds.ID = "drpDwnAppIds";
drpDwnAppIds.DataSource = lstAppIds;
drpDwnAppIds.DataBind();
var tb = dcField.GetAllControlsOfType<TextBox>(); ;// grdRow.Cells[i].GetAllControlsOfType<TextBox>();
TextBox firstTb = (TextBox)tb.First();
foreach (ListItem lstItem in drpDwnAppIds.Items)
{
if (firstTb.Text.Equals(lstItem.Text, StringComparison.CurrentCultureIgnoreCase))
{
lstItem.Selected = true;
}
}
dcField.Controls.Remove(firstTb);
dcField.Controls.Add(drpDwnAppIds);
}
}
}
}
Now in Gridview_RowUpdating event, I am trying to fetch the dropdownlist in similar way, but I am unable to get it. GetAllControlsOfType() is an extension method, which will return all the child controls under selected parent. In this case, parent is gridview cell and child control is dropdownlist. But it is returning null.
protected void grdViewConfig_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
strTableName = txtTable.Text.Trim();
string strAppId;
GridViewRow grdRow = grdViewConfig.Rows[grdViewConfig.EditIndex];
for (int i = 0; i < grdRow.Cells.Count; i++)
{
if (grdRow.Cells[i].GetType().Equals(typeof(DataControlFieldCell)))
{
DataControlFieldCell dcField = (DataControlFieldCell)grdRow.Cells[i];
if (dcField.ContainingField.HeaderText.ToLower().Equals("applicationid"))
{
var drpDwn = dcField.GetAllControlsOfType<DropDownList>();
DropDownList drpDwnAppIds = (DropDownList)drpDwn.First();
strAppId = drpDwnAppIds.SelectedValue;
}
}
}
}
What am I missing? Please help. Also let me know if more information is needed.
Thank you in advance.
Dynamically generated controls need to be recreated on every postback. In your case the DropDownList controls you created no longer exist when you hit the grdViewConfig_RowUpdating handler.
Generally in this sort of case you would set AutoGenerateColumns to false and manually define your columns which would allow you to define a TemplateField which contains an ItemTemplate for read only mode and an EditItemTemplate for edit mode which could then contain your DropDownList.

Checked_Change Event of programatically generated Checkbox inside GridView Row

I have a GridView which holds user data. When the Page_Load Method is called, I get data using a DataTable and then bind it to the GridView. At the end of each row, I have added a CheckBox. This CB is used as a pointer for which entity the user wants to edit.
My problem is the Check_Changed Event of the CheckBoxes. I do not know how to add a handler if the control is generated programmatically. I also need the index of the row (a field value is also possible, but the column header and the column itself are hidden).
foreach (GridViewRow gvr in grdMitgliedsliste.Rows)
{
//add checkbox for every row
TableCell cell = new TableCell();
CheckBox box = new CheckBox();
cell.Controls.Add(box);
gvr.Cells.Add(cell);
//Hide columns for userid, status, etc.
gvr.Cells[0].Visible = false;
gvr.Cells[3].Visible = false;
gvr.Cells[4].Visible = false;
gvr.Cells[5].Visible = false;
gvr.Cells[8].Visible = false;
gvr.Cells[9].Visible = false;
}
I have already tried implementing the handler from here, but it gives me no index argument so the program cannot determine in which row the checkbox was checked.
protected void Page_Load(object sender, EventArgs e)
{
List<string> names = new List<string>();
names.Add("Jhonatas");
this.GridView1.DataSource = names;
this.GridView1.DataBind();
foreach (GridViewRow gvr in GridView1.Rows)
{
//add checkbox for every row
TableCell cell = new TableCell();
CheckBox box = new CheckBox();
box.AutoPostBack = true;
box.ID = gvr.Cells[0].Text;
box.CheckedChanged += new EventHandler(box_CheckedChanged);
cell.Controls.Add(box);
gvr.Cells.Add(cell);
}
}
void box_CheckedChanged(object sender, EventArgs e)
{
string test = "ok";
}
TableCell cell = new TableCell();
CheckBox box = new CheckBox();
box.Check += new EventHandler(Checked_Changed);
cell.Controls.Add(box);
gvr.Cells.Add(cell);
sorry, im allready about to drive home so its just an fast answer.
mabye you have to correct the event after box."event" ...
You should go this way:
first of all when you are generating the checkbox
CheckBox box = new CheckBox();
box.AutoPostBack=true;
provide an id to the checkbox as
box.ID=Convert.toString(Session["Count"]);
do initialize the "Count" when the page loads in the session.
also increment the "Count" everytime you add a new checkbox.
secondly, define the event handler for your dynamic check box like this:
box.CheckedChange += MyHandler;
and define the MyHandler
protected void MyHandler(object sender, EventArgs e)
{
//Do some stuff
}
now you may get the id for the checkbox from which the event has been fired inside the MyHandler, which will actually be the row number.
CheckBox cb = (CheckBox)sender;
string id = cb.ID;

Categories