Double pass required for TextBox Postback in FormView - c#

This is a follow up to an earlier issue which I provided my own answer to but there is a new wrinkle in the process that I'm looking for an answer.
Scenario:
Have a asp.TextBox embedded inside of a asp.FormView control. Prior issue was that I couldn't populate the TextBox from code behind (C#). This was corrected by adding AutoPostBack = "true" to the TextBox.
Issue:
The postback corrected the population of the Text box but now two passes on the control assignment have to be executed in order to see the textbox populated.
Specific Question
How can correct this so it doesn't require a second click of the button to see the textbox populated.
Code Examples:
/*-- This is the fragment of code in the aspx which is related to the issue: --*/
<asp:FormView runat="server" ID="EditImpStndPreamble" DataSourceID="ImpStndPreambDS" OnItemCommand="EditImpStndPreamble_ItemCommand" DefaultMode="Edit" DataKeyNames="ARS_Index">
<InsertItemTemplate>
<asp:Label runat="server" Font-Size="Small" Font-Bold="true" Width="60" Text="Index #"></asp:Label>
<asp:Label Text='<%# Eval("ARSEL_Index") %>' runat="server" ID="ARSEL_IndexLabel1" Width="74" />
<asp:Label runat="server" Width="60" Font-Size="Small" Font-Bold="true" Text="Control #"></asp:Label>
<asp:TextBox Text='<%# Bind("ARSControlNum") %>' runat="server" ID="ARSControlNumTextBox" Width="74" />
<asp:LinkButton runat="server" Text="Insert" CommandName="Insert" ID="InsertButton" CausesValidation="True" /> <asp:LinkButton runat="server" Text="Cancel" CommandName="Cancel" ID="InsertCancelButton" CausesValidation="False" />
</InsertItemTemplate>
</asp:FormView>
// This is the fragmentof code in the C# code behind related to the issue
// This is where we update the control number
Label ctrnum = (Label)EditElementsFV.Row.FindControl("ARSControlNumLabel");
if (ctrnum != null)
ctrnum.Text = Session["CurrentControl"].ToString();
Any insight here would be welcomed. I've tried several things but haven't come up with a means of making this work like I want it to. I'm thinking if I could trigger a second postback of only the TextBox control here that could resolve it. The problem is every method of doing a postback from code behind seems to reset the page which by default has this FormView invisible.
Regards,
Updated 03/24/17 1:06PM Central US:
I took a bit of a break from this issue to work on another segment of the project. I tried several more thing but the last thing I did was track several variables through the debugger and examine the flow of the code as I stepped through the pertinent sections of code.
To the double tap issue I discovered that the first time you click on the Insert Implementation Standards button that the execution was routed through 'Item Template' of the FormView and then it ran through the 'Insert Template' before coming to rest.
Conversely the second click of the button executed as I would have expected and ONLY executed the 'Insert Template of the FormView.
I also observed all the variables that are used in the DataSource related to the FormView being properly populated prior to the execuation of either the Item Template and/or the Insert Template of the FormView.
So, this is even more baffling that I originally ran into it because at first all that I was dealing with was the lack of visibility of two TextBoxes, now however, we have the curiosity of the code executing the Item Template of the FormView prior to walking through the Insert Template.
Ken...
Updated: 03/27/17 9:55AM Central US
I have been working on this and searching for examples of similar issues that I might be able to leverage from and so have now attempted using a FormView.ItemInserting block (Which is bypassed prior to actual execution of the 'insert') and FormView.DataBound blocks. The DataBound was able to trigger but I had to encompass the block in a conditional 'if (IsPostBack)' to avoid trigging a null reference error. This properly routed through the block however the result on the screen draw was the same wit the fields not being populated as intended. Here is the last block as last attempted:
protected void EditElementsFV_DataBound(object sender, EventArgs e)
{
if (IsPostBack)
{
Label ctrnum = (Label)EditImpStndPreamble.Row.FindControl("ARSControlNumLabel");
if (ctrnum != null)
ctrnum.Text = Session["CurrentControl"].ToString();
Label famlbl = (Label)EditImpStndPreamble.Row.FindControl("ColumnTagLabel");
if (famlbl != null)
famlbl.Text = Session["CurrentFamily"].ToString();
}
}
Pressing on but could really use some other eyes on this.
Update: 03/29/17 7:42AM Central US
I wanted to post this update yesterday but got pulled off on a different project for a bit. My latest attempt to resolve this issue I thought for certain that it would work. But it has also failed to load the values into the insert mode of the forum until the button has been selected the second time.
What this does is from the trigger of 'DataBound' in the FormView it directes the flow to a function FillDefaultValue which assigns default values to the two parameters that are in the FormView that control the TextBox displays.
In my mind this 'should have' resolved the issue as the default value would then be the values contained in the Session variables instead of being blank(null).
public void FillDefaultValueInFormView()
{
if (EditElementsFV.CurrentMode == FormViewMode.Insert)
{
EditElementsDS.SelectParameters["ARSControlNum"].DefaultValue = Session["CurrentControl"].ToString();
EditElementsDS.SelectParameters["ColumnTag"].DefaultValue = Session["CurrentColumn"].ToString();
}
}
protected void EditElementsFV_DataBound(object sender, EventArgs e)
{
if (IsPostBack)
{
FillDefaultValueInFormView();
}
}
So the mystery continues...

I ended up using the function FillDefaultValueInFormView() defined in the question to resolve this.
I watch in debut the flow over and over again and realized what was happening was that when I set the FormView's mode to Insert that it was flushing the value assignments that I was placing on the TextBox.
Then I realized that what I needed to do was assign the default value in the DataSource to be what I desired in the TextBox 'prior' to setting the mode of the FormVeiw to Insert. So, I added the call to the function in the early portion of my Button_click event immediately followed by changing mode of the FormView to Insert.
protected void AddImpStadBTN_Click(object sender, EventArgs e)
{
Session["CurrentColumn"] = "IMP";
FillDefaultValueInFormView();
EditElementsFV.ChangeMode(FormViewMode.Insert);
... More code follows to complete this but left off as it doesn't effect the results...
}
After doing this the change to insert mode on the FormView was successfully prepopulated as I had intended for the user. I'll now change them to ReadOnly so the user can't change them, making them programmatically driven fields within the form.

Related

C# code jumps to uncalled function upon completion of another function in asp .NET

Background:
I have a place in my webpage where the user can submit an ID number. They can either enter the ID into a textbox or select a heavily used ID from the drop down list. Since these two sources of input essentially do the same thing, I use the same callback function for both of them. There are checks in this function to see whether the sender was the textbox or the drop down (and appropriate validation checking).
The Problem:
I'm getting some very strange behavior from this function. When this function is called and the sender is the drop down list, everything works as it is supposed to. However, when this function is called and the sender is the text box, everything appears to be fine up until it is time to exit the function. Once the function has exited, control immediately jumps to another unrelated function that I have not called anywhere inside that function. It makes this jump both on the web when I test it and in the debugger. It always jumps to the same function. This function is itself a callback function for a push button somewhere else on the page (that is only being called when the user explicitly presses the button).
I do not know of any reason why it would be doing this and cannot figure out what is going wrong.
Relevant Code
Note: both the textbox and drop down list are in the EditItemTemplate of a GridView, if that matters.
<asp:TextBox ID="TextBoxCQ" runat="server" BackColor="#ffcccc" Text="Enter CQ here" onclick="$(this).val('');" OnTextChanged="cq_Selected_In_Edit"></asp:TextBox>
<asp:DropDownList ID="AssociatedCQList" runat="server" BackColor="#ffcccc" AppendDataBoundItems="True" Font-Size="Smaller" AutoPostBack="True" DataSourceID="SqlDataSource_CQList" DataTextField="cqdetail" DataValueField="cqID" OnSelectedIndexChanged="cq_Selected_In_Edit">
<asp:ListItem Selected="True" Enabled="true" Value="Select from list of CQ's">Select from list of CQ's </asp:ListItem>
</asp:DropDownList>
Code Behind:
protected void cq_Selected_In_Edit(object sender, EventArgs e)
{
object type = sender.GetType();
string name = ((System.Reflection.MemberInfo)(type)).Name;
bool isTextbox = (name == "TextBox"); // to be used throughout the function
GridViewRow Row;
string text;
if (isTextbox) // it's the textbox calling
{
Row = (GridViewRow)((System.Web.UI.WebControls.TextBox)(sender)).NamingContainer;
text = ((System.Web.UI.WebControls.TextBox)(sender)).Text;
}
else // it's the dropdown calling
{
Row = (GridViewRow)((System.Web.UI.WebControls.DropDownList)(sender)).NamingContainer;
text = ((System.Web.UI.WebControls.ListControl)(sender)).Text;
}
// do more processing, etc etc
}
The ID of the control is TextBoxQC and you're comparing that against TextBox in order to find the correct object. This is evaluating to false because the 2 strings are not equal.
As you want to use the code throughout, change it to
bool isTextbox = (name.Contains("TextBox"));
As the function suggests it is checking that the string contains the text TextBox.
I still don't know exactly what causes this, although it appears to have something to do with the fact that textboxes have an affinity for wanting to press buttons.
What fixed the issue was placing the textbox in a panel, and then have the panel press an invisible button which called the code behind function (of course, slight modifications were also needed in the code behind). A simple implementation is shown below:
<asp:Panel runat="server" DefaultButton="btnSearch">
<asp:TextBox id="txtSearch" runat="server" />
<asp:Button id="btnSearch" runat="server" text="Start search" />
</asp:Panel>
Code Source: How can I fire a Button Click event when Enter Key is pressed based on what textbox has focus?

ASP.NET Repeater with UserControl & Postback

I have an ASP.NET Repeater with a custom user control defined as follows:
<asp:Repeater ID="feedCards" runat="server">
<ItemTemplate>
<vsan:card ID="card" VFeed='<%# Container.DataItem %>' runat="server" />
</ItemTemplate>
</asp:Repeater>
The repeater is databound in the code behind OnInit with the standard method:
List<someObject> data = ...;
feedCards.DataSource = data;
feedCards.DataBind();
This works fine until I introduce the need for periodic updating of the data on the page. There's an asp:Timer on the page that fires every 30 seconds. When the timer fires it checks some server side data an updates the page if necessary.
The problem is, that when the timer fires, I lose all of the data in each of the repeater's cards. The correct # of cards are displayed, but they have no data in them.
Is there a way to have the user control maintain its data through asp.net's postback?
If I understood correctly your question the data is bounded but does not appear in your repeater right? So this code may help you to solve it:
protected void yourRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
MyDataBoundedObject bounded = (MyDataBoundedObject)e.Item.DataItem;
Label lbText = (Label)e.Item.FindControl("myText");
lbText.Text = bounded.myText;
}
In your OnInit method, what happens if you save the List<someObject> you retrieve to ViewState as well as binding it? That way, when your Timer Ticks, if you don't have new data, you just rebind to the stored data in ViewState.
There were several problems that I had to overcome, here's what I ended up doing:
ASP.NET was not storing my object in the session information, even though I had EnableViewState and ViewStateMode at either Enabled or True. To get around this, I changed my property slightly
object realObj = null;
public object VFeed
{
get { return realObj; }
set
{
realObj = value;
ViewState["objectID"] = realObj.ID;
}
}
Then I could pull back the real object in Page_Load of the user control by pulling the object back out of the database (using the saved ViewState ID).
Then there was a problem with the way my timer was implemented. I tried several things:
Just putting the timer on the page, not contained in any kind of update panel, etc.
This didn't work as the entire page refreshed, and so did all of my user controls
Setting the timer as a trigger for the update panel that contains my list of items
That worked better - as only that section of the page refreshed, but in this case that wasn't sufficient
I don't want all my fancy user controls blinking every 30 seconds.
What ended up working was to put the timer in its own update panel, with the timer set as the trigger to the update panel. I found the solution here, here's the code
<asp:UpdatePanel runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false"
ID="upTimer">
<ContentTemplate>
<asp:Timer ID="GameClock" runat="server" Interval="5000" Enabled="true" OnTick="GameClock_Tick">
</asp:Timer>
</ContentTemplate>
</asp:UpdatePanel>

Why is ASP.NET submitting the original value of a TextBox control when the contents have been changed?

I have a web form that allows the user to modify data in certain fields (mostly TextBox controls, with a couple of CheckBox, DropDownList, and one RadioButtonList control) with a submit button to save the changes. Pretty standard stuff. The catch is, I need to keep track of which fields they modified. So I'm using ASP.NET HiddenField controls to store the original value and then on submit comparing that to the value of the corresponding TextBox (for example) control to determine which fields have been modified.
However, when I submit the form and do the comparison, the value of the TextBox control in the code behind still reflects the original value, even though I have changed the contents of the TextBox, so it isn't registering the change. Here is an example of a set of TextBox/HiddenField pairings (in this case last, first, middle names) in my ASP.NET form:
<div id="editName" class="editField" style="display: none">
<asp:TextBox ID="tbxLName" runat="server" class="editable"></asp:TextBox>,
<asp:TextBox ID="tbxFName" runat="server" class="editable"></asp:TextBox>
<asp:TextBox ID="tbxMName" runat="server" class="editable"></asp:TextBox>
<asp:HiddenField ID="hdnLName" runat="server" />
<asp:HiddenField ID="hdnFName" runat="server" />
<asp:HiddenField ID="hdnMName" runat="server" />
</div>
I'm setting the original values of all these controls (".Text" for the TextBox controls, ".Value" for the HiddenField controls) on PageLoad in the code behind.
Here's an example of where I'm doing the comparison when I submit the form (I'm adding the field name, old value, and new value to List<string> objects if the values differ):
if (tbxLName.Text != hdnLName.Value)
{
changes.Add("ConsumerLastName");
oldVal.Add(hdnLName.Value);
newVal.Add(tbxLName.Text);
}
But when I enter a new value into the TextBox control and click Submit:
then step through the code in the debugger, it shows me that the value of the control is still the old value:
Why is the comparison happening against the original value of the TextBox even though the new value is there when I click the submit button?
Update: #David gets the credit for this, even though he didn't post it as an answer -- I was forgetting to enclose the method for pre-filling the original values of the controls in a check for IsPostBack; I really should have known better, I've been doing this for quite a while!
Are you checking for IsPostback in Page_Load so you don't overwrite the values sent in the Postback?
Make sure that you are not overwriting your values in the Page_Load method:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
someTextField = "Some Value";
}
}
It took a while for me to get that the Page_Load method works as an "before anything goes" method and not only a method that is being ran when you visit the page with GET.
Make sure you're not overwriting the value for the textbox somewhere in page init or load without checking for the IsPostback flag.
It may happen due to postback. If you code for set textbox not in !isPostBack then put it.
i.e.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
tbxLName.Text="anything";
}
}

Validation prevent check box to auto postback

I have following checkboxes on my page:
<asp:CheckBox ID="rbBuilding" runat="server" AutoPostBack="True" OnCheckedChanged="HandlerPackageOnCheckedChanged" Checked="True" CausesValidation="False" />
<asp:CheckBox ID="rbContent" runat="server" AutoPostBack="True" OnCheckedChanged="HandlerPackageOnCheckedChanged" CausesValidation="False" />
There is an logic on postback based on combination of checkboxes clicked. Everything is working fine except one case:
I'm opening additional telerik radwindow which has some validation within its own validation group. If I close the window with any validation error, then the first click on any of that checkboxes
does not do postpack.
Only FIRST click is not working. next time I click everything is working fine. I've tried to add check boxes to theirs own validation group and change casing validation to true. But behaviour is exactly the same. When I add test javascript method to onclick for that checkboxes then this method is fired without issue. There is just no postback.
I also tried to reset all validators for window validation group on window close, they are reset, but behaviour is not checking, and first click is not working.
UPDATE:
I've made one more check and realized it only happens if I do in javascript:
window.Page_ClientValidate("MyGroup")
Which I have to do before do some calculations on popup window.
During dynamic validators, when updating validatable controls eveything is working properly, even if validation fails. So the problem is *Page_ClientValidate*
I know this is an old question but I ran into almost the exact issue and thanks to the following link I was able to resolve the issue:
Issue with postbacks and clicking on controls twice
I ended up adding this code to my code behind to add a javascript event handler for the checkbox's click event:
Checkbox1.Attributes.Add("onclick", "checkboxChanged();");
I then added the following javascript:
function checkboxChanged(arg1) {
Page_BlockSubmit = false;
}
The checkbox in my situation was also set to have CausesValidation set to false but I don't think that's required for this fix. Hopefully this helps someone.

UpdatePanel reloads the whole page

I'm building an asp.net cutom control inside which I have two dropdownlists: companyIdSelection and productFamilySelection.I populate the companyIdSelection at Page_Load and in order to populate the productFamilySelection depending on the selected item in companyIdSelection.I'm using UpdatePanels to achieve this, but for some reason every time I update companyIdSelection Page_Load is being called ( which as far as I know should happen only when the entire page is reloaded ), the list is being reloaded again and the item the user selected is lost( the selected item is always the top one ).Here's the code
<asp:UpdatePanel ID="updateFamilies"
runat="server"
UpdateMode="Always">
<ContentTemplate>
Company ID:<br>
<br></br>
<asp:DropDownList ID="companyIdSelection"
runat="server"
AutoPostBack="True"
OnSelectedIndexChanged="companyIdSelection_SelectedIndexChanged">
</asp:DropDownList>
<br></br>
Product Family:
<br></br>
<asp:DropDownList ID="productFamilySelection" runat="server"
AutoPostBack="True"
onselectedindexchanged="productFamilySelection_SelectedIndexChanged">
</asp:DropDownList>
<br>
</ContentTemplate>
</asp:UpdatePanel>
protected void Page_Load(object sender, EventArgs e)
{
this.companyIdSelection.DataSource = companyIds(); //companyIds returns the object containing the initial data items
this.companyIdSelection.DataBind();
}
protected void companyIdSelection_SelectedIndexChanged(object sender, EventArgs e)
{
// Page_Load is called again for some reason before this method is called, so it
// resets the companyIdSelection
EngDbService s = new EngDbService();
productFamilySelection.DataSource = s.getProductFamilies(companyIdSelection.Text);
productFamilySelection.DataBind();
}
Also, I tried setting the UpdateMode of the UpdatePanel to "Conditional" and adding an asyncpostback trigger
but the result was the same.
What am I doing wrong?
PS:
I fixed the updating problem, by using Page.IsPostBack in the Page_Load method, but I would still want to avoid a full postback if possible
I think you misunderstand how UpdatePanels work. They DO actually do a full page postback, it's just that during the rendering stage they capture only a portion of the output and send it back in the AJAX response so the page can be updated. More info here.
So you will still need to check whether it is a postback in your page_load event and only perform your data load if it isn't one.
The update panel call back will go through the page load on every call back. In face, the pull page lifecycle (minus render and prerender) will occur. Update panels give the appearance of ajax, but your client side code still posts back to the same page - which is the problem you are describing. If you can avoid using Update Panels, I suggest you do so. Use something like jQuery instead. If not, then use this in your Page_Load
if (Page.IsCallback) { } //Do callback specific code here
else { } //Do Postback specific code here
Hope this helps. Good Luck.

Categories