Programatically created events in RowDataBound not firing - c#

I have a GridView which is populated from a database, and includes a textbox. Through the code behind, I want to subscribe the textbox on each row to a certain event, but only if a field of the row matches some if statement.
So I have the following:
protected void grdRates_RowDataBound(object sender, GridViewRowEventArgs e)
{
TextBox txt = (TextBox)e.Row.FindControl("txtValue");
DataRowView dataView = (DataRowView)e.Row.DataItem;
if ((bool)dataView["isAuto"])
{
txt.AutoPostBack = true;
txt.TextChanged += new EventHandler(txt_TextChanged);
}
}
protected void txt_TextChanged(object sender, EventArgs e)
{
//Other stuff here
}
The problem is, the text changed event never fires - the AutoPostBack property is being set, as the page posts back when they move out of the TextBox, but the text changed event does not fire. Am I missing something here?

You should change the implementation so that you are not adding an event handler at the time of data binding, which will get you in all sorts of problems with the page lifecycle.
Instead, you could bind the AutoPostBack property declaratively and just set the event handler there as well.
<asp:TextBox ID="SomeInput" runat="server" ...
AutoPostBack='<%# (bool)Eval("IsAuto")'
OnTextChanged="SomeInput_TextChanged" />
The event will only fire automatically (i.e. when the input loses focus) when IsAuto == true, but it may still fire when the user clicks another button in the same row and the text in the input was changed. So you need an extra check in the event handler:
protected void SomeInput_TextChanged(object sender, EventArgs e)
{
TextBox input = (TextBox)sender;
if(input.AutoPostBack)
{
// Other stuff here
}
}
Notice that by declaratively binding we need to worry less about page life cycle, and we can use the bound property of the input to check against in the event handler.

Related

Set focus to control after datagridview selected index change

I am struggling with this issue for a long time now.
I have a user control in a tab page which contains:
datagridview
tablelayout with label, textbox and button controls which are set based on the row selected in the datagridview
Now the catch is that the focus must also change to a control within the tablelayout:
If the selected item has state 'foo' , control 'foobar' must have the focus, but if the selected item has state 'foofoo', control 'foofoobar' must have the focus.
I handle this by using the SelectionChanged event.
This all works fine, if I manually click the selected item.
When the control is initially loaded and the first row is selected, the focus is not set correctly.
My guess is, this has to do with the taborder setter of the Control class which overrides my focus, but I cannot figure out which event triggers the taborder setter.
I tried :
overriding OnLoad and OnLayout and call the same code as called in the SelectionChanged event
overriding OnLoad and OnLayout and first set the 2nd row, after which I set the 1st row to trigger the SelectionChanged event
But nothing works.
Any ideas are most welcome.
private void ResultGridView_SelectionChanged(object sender, EventArgs e) {
SelectInput();
}
private void SetInputFocus() {
if (isValid) {
foo.Focus();
}
else {
foofoo.Focus();
}
Set the focus in the YourTabControl_Layout event as you do in your SelectionChanged event.
You can also set focus initially on any control, even on a tabpage and tablelayout with the Form1_Load event.
private void Form1_Load(object sender, EventArgs e)
{
ActiveControl = SomeControl;
}
private void YourTabControl_Layout(object sender, LayoutEventArgs e)
{
if (YourTabControl.SelectedIndex == 0)
SomeControl.Focus();
}

Why does my dynamically created user control doesn't fire button click event

i have a problem with user control.
i create it dynamically on my aspx page after clicking on a button:
protected void btnAddRules_Click(object sender, EventArgs e)
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
MyPanel.Controls.Add(Control);
}
when i click on a button of my user control, the button event wont fire and the user control will disappear. here is the button event:
protected void btnAdd_Click1(object sender, EventArgs e)
{
WowzaRule rule = GetRuleFromGUI();
RuleList.Add(rule);
//Session["RuleList"] = RuleList;
//List<WowzaRule> test = new List<WowzaRule>();
SaveToXMLFiles(txtdbnum.Text, RuleList);
}
i understand that after pressing the button on mypage the usercontrol is released and if its not created on pag_init or page Load it wont stay, but i need to create it on my button click event and find a way for it not to disapper.
thanks in advance, Daniel
You might have to add an event handler that it can fire the click event and call your delegate
Control.Click += btnAdd_Click1;
Dynamically created controls, once added, have to be on a page on every page load in order to work correctly. What happens in your case:
RuleProperty is added after the button click
Page loads with this control
User clicks on the button within RuleProperty
Control is not added to the control tree during the page load (corresponding code is only in the button click handler, and that button was not clicked)
ASP.NET does not know which control triggered the event, so the event is not processed
To go around this issue you need to add you control on every page loading, for example using some flag stored in ViewState:
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["AddRuleProperty"] != null && (bool)ViewState["AddRuleProperty"])
{
AddRulePropertyControl();
}
}
protected void btnAddRules_Click(object sender, EventArgs e)
{
AddRulePropertyControl();
ViewState["AddRuleProperty"] = true;
}
private void AddRulePropertyControl()
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
MyPanel.Controls.Add(Control);
}
Update.
If you want to remove the control from the page later on in the control's click handler, you need to remove corresponding ViewState key. This is not possible from the control directly, since property Page.ViewState is protected, and also this would have created an unwanted dependency.
What seems as the right way to do this is to subscribe to the very same event from the Page (you might need to make this event visible from the controller) and reset the key in there. Like this:
private void AddRulePropertyControl()
{
RuleProperty Control = (RuleProperty)LoadControl("RuleProperty.ascx");
Control.ButtonClick += RuleProperty_ButtonClick;
MyPanel.Controls.Add(Control);
}
private void RuleProperty_ButtonClick()
{
ViewState["AddRuleProperty"] = false;
}
Please note that event name here is not real, this is just a sketch of what can be done.

How can i catch onclick event of Dynamically loaded control?

I have a dropdownlist (on Page) which has OnSelectedIndexChange event thats Loads different Control (ascx) dynamically each time ( with LoadControl Command) - into the page.
Each Control Has a Button(runat=server) and TextBox(runat=server).
When i click on the button - i cant get into the Onclick function .
How can i get into the OnClick Function of the Ascx ?
I know that each SelectedIndexChange its makes postback - so i know i have to save something in the viewstate. but i dont know how to save it and later get the values eneterd on the TexstBox. ( of Each ascx)
You need to add an event handler to the user control, like this:
public event EventHandler ButtonClick;
And in the click event of the button:
protected void Button1_Click(object sender, EventArgs e)
{
if (this.ButtonClick != null)
this.ButtonClick(this, e);
}
Then, from the page, you can get the click event like this:
<UC:MyUserControl ID="UserControl1" runat="server" OnButtonClick="UserControl1_ButtonClick" ... />
protected void UserControl1_ButtonClick(object sender, EventArgs e)
{
//Handle the click event here
}
If you're loading the controls dynamically, then you'll need to make sure the controls are rehydrated after postback, and emulate the code above by assinging the event handler through code:
MyUserControl ctrl = (MyUserControl)this.LoadControl("...");
ctrl.ButtonClick += new EventHandler(UserControl1_ButtonClick);

How do I attach an event handler to an ASP.NET control created at runtime?

Good morning everybody.
I have a question connected with controls and event handling. Lets say I want to create a LinkButton.
protected void loadLinkButton()
{
ContentPlaceHolder content = (ContentPlaceHolder)this.Master.FindControl("MainContent");
LinkButton lnk = new LinkButton();
lnk.ID = "lnikBtn";
lnk.Text = "LinkButton";
lnk.Click += new System.EventHandler(lnk_Click);
content.Controls.Add(lnk);
}
Here is the event handler:
protected void lnk_Click(object sender, EventArgs e)
{
Label1.Text = "ok!";
}
If I run the loadLinkButton function inside Page_Load everything is ok. But when I try to run the loadLinkButton by clicking simple button, link button is created but event is not handled.
protected void Button1_Click(object sender, EventArgs e)
{
loadLinkButton();
}
I there any way to solve it? Or loadLinkButton must always regenerated on Page_Load, Page_init etc.
When working with dynamic controls, I always add the control in Page_Init, because viewstate loading will happen right after Init. If you add it to Page_Load, there is a chance that you will lose viewstate. Just make sure you provide a unique control ID.
It is important to know how ASP.Net determines which events to invoke. The source of each event is passed using a hidden field:
<input type="hidden" name="__EVENTTARGET" value="" />
Whenever the page loads, it pulls in the source of the event from that field and then determines which event to invoke. Now this all works great for controls added through markup because the entire control tree is regenerated on every request.
However, your control was only added once. When a Postback occurs, your control no longer exists as a Server control in the tree, and therefore the event never fires.
The simply way to avoid this is to make sure your Dynamic Controls are added every time the page loads, either through the Page_Init event, or the Page_Load event.
You are right. This is the expected behavior. Page_Load and Page_Init would be the events where you should be adding it.
That would be because when you click your dynamically generated linkbutton, you do a postback to the server. There you do an entirely new pageload, but your original buttonclick (that generates the link) never happened now, so the linkbutton is never made, and the event can not be thrown.
An alternative is to add the linkbutton you add dynamically, to your page statically, with Visible = false. And when you click the other button, make it visible.
I am not exactly sure what problem you are facing but you should put the dynamic controls code in Page_Init as suggested by #johnofcross:
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Page_Init(object sender, EventArgs e)
{
CreateControls();
}
private void CreateControls()
{
var lb = new LinkButton();
lb.Text = "Click Me";
lb.Click += lb_Click;
ph.Controls.Add(lb);
ph.DataBind();
}
void lb_Click(object sender, EventArgs e)
{
lblMessage.Text = "Button is clicked!";
}
}

Triggering a checkbox value changed event in DataGridView

I have a grid view that has a check box column, and I want to trigger a drawing event as soon as the value of the cell is toggled. I tried the ValueChaged and the CellEndEdit and BeginEdit, and chose the selection mode as CellSelect. As for the the first 2 events, the event was triggered upon the finishing of the edit mode, like moving out of the current cell, or going back and forth. It's just a weird behavior.
Is there anything that triggers the event on the grid view as soon as the cell value is changed?
I use the CellContentClick event, which makes sure the user clicked the checkbox. It DOES fire multiple times even if the user stays in the same cell. The one issue is that the Value does not get updated, and always returns "false" for unchecked. The trick is to use the .EditedFormattedValue property of the cell instead of the Value property. The EditedFormattedValue will track with the check mark and is what one wishes the Value had in it when the CellContentClick is fired.
No need for a timer, no need for any fancy stuff, just use CellContentClick event and inspect the EditedFormattedValue to tell what state the checkbox is going into / just went into. If EditedFormattedValue = true, the checkbox is getting checked.
A colleague of mine recommends trapping the CurrentCellDirtyStateChanged event. See http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx.
Another way is to handle the CellContentClick event (which doesn't give you the current value in the cell's Value property), call grid.CommitEdit(DataGridViewDataErrorContexts.Commit) to update the value which in turn will fire CellValueChanged where you can then get the actual (i.e. correct) DataGridViewCheckBoxColumn value.
private void grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// do something with grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value
}
Target .NET framework: 2.0
Small update.... Make sure you use EditedFormattedValue instead of value as I tried value but it never give right status that is checked/unchecked most of the site still use value but as used in latest c# 2010 express below is one way to access..
grdJobDetails.Rows[e.RowIndex].Cells[0].EditedFormattedValue
Also _CellValueChanged event suggested or used by few must be usable for some cases but if you are looking for every check/uncheck of cell make sure you use _CellContentClick else per my notice I see not every time _CellValueChanged is fired.. that is if the same checkbox is clicked over & over again it does not fire _CellValueChanged but if you click alternately for example you have two chekbox & click one after other _CellValueChanged event will be fired but usually if looking for event to fire everytime the any cell is check/uncheck _CellValueChanged is not fired.
Try hooking into the CellContentClick event. The DataGridViewCellEventArgs will have a ColumnIndex and a RowIndex so you can know if a ChecboxCell was in fact clicked. The good thing about this event is that it will only fire if the actual checkbox itself was clicked. If you click on the white area of the cell around the checkbox, it won't fire. This way, you're pretty much guaranteed that the checkbox value was changed when this event fires. You can then call Invalidate() to trigger your drawing event, as well as a call to EndEdit() to trigger the end of the row's editing if you need that.
I finally implemented it this way
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
if (dataGridView1[e.ColumnIndex, e.RowIndex].GetContentBounds(e.RowIndex).Contains(e.Location))
{
cellEndEditTimer.Start();
}
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{ /*place your code here*/}
private void cellEndEditTimer_Tick(object sender, EventArgs e)
{
dataGridView1.EndEdit();
cellEndEditTimer.Stop();
}
I had the same issue, but came up with a different solution:
If you make the column or the whole grid "Read Only" so that when the user clicks the checkbox it doesn't change value.
Fortunately, the DataGridView.CellClick event is still fired.
In my case I do the following in the cellClick event:
if (jM_jobTasksDataGridView.Columns[e.ColumnIndex].CellType.Name == "DataGridViewCheckBoxCell")
But you could check the column name if you have more than one checkbox column.
I then do all the modification / saving of the dataset myself.
"EditingControlShowing" event doesn't fire on checkbox value change. Because display style of the checkbox cell doesn't not change.
The workaround i have used is as below. (I have used CellContentClick event)
private void gGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (string.Compare(gGridView1.CurrentCell.OwningColumn.Name, "CheckBoxColumn") == 0)
{
bool checkBoxStatus = Convert.ToBoolean(gGridView1.CurrentCell.EditedFormattedValue);
//checkBoxStatus gives you whether checkbox cell value of selected row for the
//"CheckBoxColumn" column value is checked or not.
if(checkBoxStatus)
{
//write your code
}
else
{
//write your code
}
}
}
The above has worked for me. Please let me know if need more help.
I found a simple solution.
Just change the cell focus after click on cell.
private void DGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == "Here checkbox column id or name") {
DGV.Item(e.ColumnIndex, e.RowIndex + 1).Selected = true;
//Here your code
}
}
Don't forget to check if the column of your (ckeckbox + 1) index exist.
Every one of the CellClick and CellMouseClick answers is wrong, because you can change the value of the cell with the keyboard and the event will not fire. Additionally, CurrentCellDirtyStateChanged only fires once, which means if you check/uncheck the same box multiple times, you will only get one event. Combining a few of the answers above gives the following simple solution:
private void dgvList_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvList.CurrentCell is DataGridViewCheckBoxCell)
dgvList.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void dgvList_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// Now this will fire immediately when a check box cell is changed,
// regardless of whether the user uses the mouse, keyboard, or touchscreen.
//
// Value property is up to date, you DO NOT need EditedFormattedValue here.
}
cellEndEditTimer.Start();
this line makes the datagridview update the list of checked boxes
Thank you.
I found a combination of the first two answers gave me what I needed. I used the CurrentCellDirtyStateChanged event and inspected the EditedFormattedValue.
private void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridViewCell cell = dgv.CurrentCell;
if (cell.RowIndex >= 0 && cell.ColumnIndex == 3) // My checkbox column
{
// If checkbox checked, copy value from col 1 to col 2
if (dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue != null && dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue.Equals(true))
{
dgv.Rows[cell.RowIndex].Cells[1].Value = dgv.Rows[cell.RowIndex].Cells[2].Value;
}
}
}
Use this code, when you want to use the checkedChanged event in DataGrid View:
private void grdBill_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grdBill.CurrentCell = grdBill.Rows[grdBill.CurrentRow.Index].Cells["gBillNumber"];
}
private void grdBill_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
calcBill();
}
private void calcBill()
{
listBox1.Items.Clear();
for (int i = 0; i < grdBill.Rows.Count - 1; i++)
{
if (Convert.ToBoolean(grdBill.Rows[i].Cells["gCheck"].Value) == true)
{
listBox1.Items.Add(grdBill.Rows[i].Cells["gBillNumber"].Value.ToString());
}
}
}
Here, grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox in Grid (Second column).
So, when we want to fire checkchanged event for each click, first do the CellContentClick it will get fire when user clicked the Text box, then it will move the current cell to next column, so the CellEndEdit column will get fire, it will check the whether the checkbox is checked and add the "gBillNumber" in list box (in function calcBill).
Working with an unbound control (ie I manage the content programmatically), without the EndEdit() it only called the CurrentCellDirtyStateChanged once and then never again; but I found that with the EndEdit() CurrentCellDirtyStateChanged was called twice (the second probably caused by the EndEdit() but I didn't check), so I did the following, which worked best for me:
bool myGridView_DoCheck = false;
private void myGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (!myGridView_DoCheck)
{
myGridView_DoCheck = true;
myGridView.EndEdit();
// do something here
}
else
myGridView_DoCheck = false;
}
Using the .EditedFormattedValue property solves the problem
To be notified each time a checkbox in a cell toggles a value when clicked, you can use the CellContentClick event and access the preliminary cell value .EditedFormattedValue.
As the event is fired the .EditedFormattedValue is not yet applied visually to the checkbox and not yet committed to the .Value property.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
bool isChecked = (bool)checkbox.EditedFormattedValue;
}
The event fires on each Click and the .EditedFormattedValue toggles

Categories

Resources