I have a CheckBoxList nested in a Repeater that is dynamically populated in the Repeater's OnItemDataBound. On a button click I would like to save the changes to each check box list, but the selected property is always TRUE after postback.
HTML:
<asp:Repeater id="rptFields" runat="server" OnItemDataBound="rptField_OnItemDataBound">
<ItemTemplate>
<asp:HiddenField id="hFieldID" runat="server" Value='<%#DataBinder.Eval(Container.DataItem,"ID")%>' />
<asp:Label id="lblDesc" runat="server" Text='<%#DataBinder.Eval(Container.DataItem,"Description")%>' />
<asp:CheckBoxList id="chkOptions" runat="server" ></asp:CheckBoxList>
</ItemTemplate>
</asp:Repeater>
<asp:Button id="btnSave" runat="server" Text="Save" OnClick="btnSave_Click" />
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
rptFields.DataSource = Fields;
rptFields.DataBind();
}
}
protected void rptField_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
|| (e.Item.ItemType == ListItemType.AlternatingItem)
{
CheckBoxList chkOptions = (CheckBoxList)e.Items.FindControl("chkOptions");
Field ThisField = (Field)e.Item.DataItem;
for (int i = 0; i < ThisField.Options.Length; i++)
{
ListItem liOption = new ListItem (ThisField.Options [i].Description, ThisField.Options [i].ID.ToString ());
liOption.Selected = ThisField.Options [i].Selected;
chkOptions.Items.Add (liOption);
}
}
}
protected void btnSave_Click(object sender, EventArgs e)
{
foreach (RepeaterItem rptItem in rptFields)
{
int iFieldID = int.parse(rptItem.FindControl("hFieldID"));
Field ThisField = GetFieldByID(iFieldID);
CheckBoxList chkOptions = (CheckBoxList)rptItem.FindControl("chkOptions");
foreach(Option ThisOption in ThisField.Options)
{
for(int i = 0;i < chkOptions.Items.Count; i++)
{
int OptionID = int.parse(chkOptions.Items[i].Value);
if(ThisOption.ID == OptionID)
{
//HERE IS THE PROBLEM
//SELECTED IS ALWAYS TRUE
ThisOption.Selected = chkOptions.Items[i].Selected;
ThisOption.Save();
}
}
}
}
}
All the data from the repeater persists, including the text and value fields of the check box list items. All except the selected property.
I have searched and searched for an answer and none exist. Every similar issue was people re-binding the list in each postback. As you can see that is not the case here. And for what it's worth, the exact same solution works for radio button lists no problem.
EDIT: For the record this project is running Mono.net 4.5
UPDATE: The same solution works in another project we have built using .Net 2.0. I'm not sure if it's a Mono issue or there is a configuration setting that changes the behaviour of the post back.
I had a similar problem recently, to solve it you can store it in querystring.
Related
I am trying to store the text of the currently selected item of an Asp:Listbox in a variable. The value is always stored a null, or I receive the error
"System.NullReferenceException: 'Object reference not set to an instance of an object.'"
Listbox declaration below
<asp:ListBox ID="lbModules" runat="server" AutoPostBack="true" OnSelectedIndexChanged="lbModules_SelectedIndexChanged" ></asp:ListBox>
Code for SelectedIndexChanged below
`
protected void lbModules_SelectedIndexChanged(object sender, EventArgs e)
{
string code = lbModules.SelectedItem.Text;
int week = 1;
UpdateTextBox(week, code);
}
`
The listbox is being populated elsewhere with a method looping and adding values with listbox.items.add
I have tried
listbox.SelectedItem.Text, listbox.SelectedValue.Text, listbox.SelectedItem.Value, listbox.SelectedValue.Value,
Nothing I try returns the text of the selected value, always throws an exception or returns null.
Ok, first up, it does not make much sense to use the selected index change event UNLESS you have a autopostback=true.
So, if the user is to enter some info into text box etc., then the user say hits your submit button, then I not really sure of any value of using the selected index change event. But, with autopost-back it does.
hence, this markup:
<h2>Select Hotels</h2>
<asp:ListBox ID="ListBox1" runat="server" AutoPostBack="true"
DataValueField="ID"
DataTextField="HotelName"
OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"
Width="190px" Height="160px" >
</asp:ListBox>
<h3>Selected value</h3>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
And code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL =
"SELECT ID,HotelName FROM tblHotelsA ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
conn.Open();
DataTable rstData = new DataTable();
rstData.Load(cmdSQL.ExecuteReader());
ListBox1.DataSource = rstData;
ListBox1.DataBind();
}
}
}
protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListBox1.SelectedIndex >= 0)
{
TextBox1.Text = ListBox1.SelectedItem.Value;
TextBox2.Text = ListBox1.SelectedItem.Text;
}
}
Note VERY but BEYOND careful that we ONLY load the listbox ONE time. Since for any event trigger on a page, the on-load event fires first, and THEN you code stub for the given button or event. Thus, if you load up the lb, or grid or in fact "any" data, but fail to include the all important if !IsPostBack code stub?
Then you cannot actually build a working web page!!! (so, my last 200+ web pages I have built ALL have and ALWAYS have that real first page load, since as noted, the on-load event triggers always on post-backs. So, if you load up the lb or anything again, it will blow out and overwrite your selections you have made).
So, above results in this:
However, if user is to enter data, select things, and THEN hit a submit button, then of course you probably would remove the autopostback = true. And place the above code behind the button click, and NOT use the selected index change event.
Even if you add items to the lb with code, the above rules still apply.
So, say this listbox:
<h2>Select Hotels</h2>
<asp:ListBox ID="ListBox1" runat="server" AutoPostBack="true"
OnSelectedIndexChanged="ListBox1_SelectedIndexChanged"
Width="190px" Height="160px" >
</asp:ListBox>
<h3>Selected value</h3>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<br />
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
We still need the autopostback, and thus this code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
for (int i = 1; i <= 6; i++)
{
string MyText = "Item # " + i;
ListBox1.Items.Add(new ListItem(MyText, i.ToString()));
}
}
protected void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (ListBox1.SelectedIndex >= 0)
{
TextBox1.Text = ListBox1.SelectedItem.Value;
TextBox2.Text = ListBox1.SelectedItem.Text;
}
}
And now we get/see this:
So, either you are missing autopostback, or you are re-running your code to fill the lb each time on post-back, and that will as noted blow out any selecting the user makes.
I have a FormView with data(DataSource,DataBind) that I fill with value='<%# Eval("Name") %>' , but after I'm changing the text in TextBox and press update button I see the same value that before, I cant see new value that I have typed.
What I am missing here?
my html
<asp:FormView ID="MainFormTemplate" runat="server">
<ItemTemplate>
<li class="li_result" runat="server">
<div class="col-3">
<input id="txt_Name" runat="server" value='<%# Eval("Name") %>'>
</div>
</li>
</ItemTemplate>
</asp:FormView>
<asp:Button id="btn_Update" runat="server" OnClick="btn_Update_Click" Text="Update" />
Server side
protected void Page_Load(object sender, EventArgs e)
{
using (DB_MikaDataContext data = new DB_MikaDataContext())
{
MainFormTemplate.DataSource = data.File_Projects.Where(x => x.Num_Tik.Equals("12")).ToList();
MainFormTemplate.DataBind();
}
}
public void btn_Update_Click(object sender, EventArgs e)
{
//using System.Web.UI.HtmlControls
HtmlInputText twt = (HtmlInputText)MainFormTemplate.FindControl("txt_Name");
string text = twt.Value;//i see old value ,not new one that i typed in text box
}
In every postback, you are always getting the old value from your database. The solution is check if the page is being rendered for the first time (!IsPostBack) then set your MainFormTemplate's DataSource else if is being loaded in response to a postback (IsPostBack) get the txt_Name's value like this:
HtmlInputText twt;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
using (DB_MikaDataContext data = new DB_MikaDataContext())
{
MainFormTemplate.DataSource = data.File_Projects.Where(x => x.Num_Tik.Equals("12")).ToList();
MainFormTemplate.DataBind();
}
}
else
{
twt = MainFormTemplate.FindControl("txt_Name") as HtmlInputText;
}
}
protected void btn_Update_OnClick(object sender, EventArgs e)
{
string text = twt.Value; // You will get the new value
}
with Page_Load executing every postback, you are always writing value from database (?), and value sent from browser is lost (although still exist in Page.Request.Form member).
In ASP.NET, When a page is submitted, the Page_Load event runs before the button click event. So, the textbox value gets repopulated with its original value before the click event looks at that value.
If this is the situation, then you can wrap the code that assigns the value to the textbox in an if block like this:
if (!IsPostBack)
{
HtmlInputText twt = (HtmlInputText)MainFormTemplate.FindControl("txt_Name");
string text = twt.Value;
}
Hope this helps you.
I bind data to the repeater on Page Init:
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
repeaterInfo.DataSource = //getDataSource;
repeaterInfo.DataBind();
}
}
Here's the markup page
<table class="beautifulTable">
<asp:Repeater runat="server" ID="repeaterInfo" OnItemCreated="repeaterInfo_ItemCreated">
<ItemTemplate>
<tr>
<td style="display: none">
<asp:TextBox runat="server" Width="90%" ID="txtUserInput"></asp:TextBox>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
Here's the Item created event:
protected void repeaterInfo_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (e.Item.DataItem == null)
return;
TextBox txtUserInput= e.Item.FindControl("txtUserInput") as TextBox;
txtUserInput.Text = "0.0"; //Default value
}
And I would like to save the user input to database when the user clicks the submit button:
protected void btnSubmit_Click(object sender, EventArgs e)
{
List<repeaterType> source = repeaterInfo.DataSource as List<repeaterType>;
for (int z = 0; z < source.Count; z++)
{
TextBox txtUserInput = repeaterInfo.Items[z].FindControl("txtUserInput") as TextBox;
//Get text and do logic here
}
//Saves data to database
}
And here's the problem:
The repeaterInfo datasource is null on postback
If I remove the !IsPostBack, the txtUserInput text will be resetted (0.0)
I've enabled the viewstate on the markup page using EnableViewState="true"
How I can get the text in txtUserInput?
The repeater's datasource is not persisted in cross postbacks. If you just want to iterate and get the user inputs, you can just iterate through the items and get those like this:
foreach (RepeaterItem item in repeaterInfo.Items)
{
if(item.ItemType == ListItemType.Item)
{
var txtUserInput = item.FindControl("txtUserInput") as TextBox;
}
}
If you want the datasource to be persisted (may be to avoid database calls), use the ViewState (watch out for large number of rows):
ViewState["myDataSource"] = myDatasource;
I am building a web application in ASP.net and I have a little problem.
I have a LISTVIEW to display data from a data source, and in that listview I have included a BUTTON in every row to be visible if the result of the query in the Page_load is 0.
The Query works, but I don't know how to select the button in the query.
I have tried
ListView1.FindControl("hiddenButton").visible = false;
this is the buttons code
<asp:Button ID="hiddenButton" runat="server" CommandArgument ='<%# Eval("ProfileId") %>' Text="Add Friend" CssClass="btn btn-info pull-right" OnClick="addFriend_Click" Width="105px" allign="right"/>
But its not working.
You can do this in ItemDataBound event:-
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType==ListViewItemType.DataItem)
{
if (YourCondition)
{
Button hdn = (Button)e.Item.FindControl("hiddenButton");
hdn.Visible = false;
}
}
}
You need to associate this event handler in your mark-up(if not already done):-
<asp:ListView ID="ListView1" OnItemDataBound="ListView1_ItemDataBound">
</asp:ListView>
You can use ItemDataBound event To set Buttons visible to True/False
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
ListViewDataItem dataItem = (ListViewDataItem)e.Item;
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Button hiddenButton=(Button) dataItem.FindControl("hiddenButton");
hiddenButton.Visible = false;
}
}
I have a TextBox control inside a panel and this panel is inside DataList ItemTemplate.
After firing the ItemCommand event, everything works fine except that the TextBox.Text property is always an empty string "" although there is some text in it.
I tried several ways but without success. I would really appreciate if someone can assist me with this. Simplified code is shown below.
Thank you!
ASPX page:
<asp:DataList ID="dlDataList" runat="server" onitemcommand="dlDataList_ItemCommand">
<ItemTemplate>
<asp:Panel ID="pnlReply" runat="server" Visible="False">
<asp:TextBox ID="txtTextBox" runat="server"></asp:TextBox><br />
<asp:LinkButton ID="lnkbtnSend" CommandName="Send" runat="server">Send</asp:LinkButton>
</asp:Panel><br />
<asp:LinkButton ID="OpenPanel" CommandName="OpenPanel" runat="server">Open panel</asp:LinkButton>
</ItemTemplate>
</asp:DataList>
</asp:Content>
ASPX.CS Page code behind
protected void Page_Load(object sender, EventArgs e)
{
FillDataList();
}
private void FillDataList()
{
List<string> list = new List<string>();
list.Add("First");
list.Add("Second");
list.Add("Third");
dlDataList.DataSource = list;
dlDataList.DataBind();
}
protected void dlDataList_ItemCommand(object source, DataListCommandEventArgs e)
{
if (e.CommandName == "OpenPanel")
{
Panel pnlReply = (Panel)e.Item.FindControl("pnlReply");
pnlReply.Visible = true;
}
if (e.CommandName == "Send")
{
TextBox txtTextBox = (TextBox)e.Item.FindControl("txtTextBox");
//I tried this way also..
//TextBox txtTextBox = (TextBox)e.item.FindControl("pnlReady").FindControl("txtTextBox");
Label1.Text = txtTextBox.Text;
}
}
Please use IsPostBack in page load event. Without it your FillDataList(); is executing on every postback and resetting your DataList.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
FillDataList();
}
}