dropdownlist always returns first value even with EnableViewState set to true - asp.net

My dropdown list control always returns the first item on postback, I've tried every solution i've come across but to no avail.
Bascially, I have two data classes that are simply containers for data.
ConnectedRobots (representing connected robot with its controller's version, its IP address and some other properties), and MiseAJour (representing a single available update with its version and some other details describing it).
These two classes are then used to create objects representing each connected robot or update available. I'm then creating a List of update versions to use it as a data source for each Dropdown list.
as shown in the picture below :
Click to view
Here's the piece of code reflecting this view (Default.aspx) :
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplicationTest.WebForm1" Theme="Theme1" EnableEventValidation="false" EnableViewState="true"%>
...
<body>
<form runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
...
<div style="width:100%;">
<table class="table table-hover">
<thead>
<tr>
<th class="auto-style1">Référence Robot/Version Contrôleur</th>
<th class="auto-style1">Pays/Adresse IP</th>
<th class="auto-style1">Etat</th>
<th class="auto-style1">Versions des contrôleurs disponibles</th>
<th class="auto-style1">Planification</th>
<th>MAJ</th>
</tr>
</thead>
<tbody>
<asp:Repeater ID="repCRobots" runat="server" EnableViewState="true">
<ItemTemplate>
<tr>
<td>
<asp:Label ID="lblReferenceRobot" runat="server" Text='<%# Eval("ReferenceRobot") + " / " %> ' />
<asp:Label ID="lblVersionControleur" runat="server" Font-Bold="true" Text='<%# Eval("VersionControleur") %>'/>
</td>
<td>
<asp:Label ID="lblPays" runat="server" Text='<%# Eval("Pays") + " / " %> ' />
<asp:Label ID="lblIPRobot" runat="server" Font-Bold="true" Text='<%# Eval("IPRobot") %>'/>
</td>
<td>
<asp:Label ID="lblEtat" runat="server" Font-Bold="true" Text='<%# Eval("Etat") %>'/>
</td>
<td>
<asp:DropDownList ID="VersionsMAJs" runat="server" CssClass="bg-primary" EnableViewState="true" OnSelectedIndexChanged="VersionsMAJs_SelectedIndexChanged" AutoPostBack="true"></asp:DropDownList>
</td>
<td>
<span style="padding: 0px 10px 10px 10px">
<cc1:TimeSelector ID="TimeSelector1" runat="server" DisplayButtons="false" Font-Bold="true" BackColor="#cce6ff" BorderStyle="Dotted" CssClass="bg-info" BorderColor="White"></cc1:TimeSelector>
</span>
</td>
<td>
<asp:CheckBox ID='SelectMAJ' runat="server"/>
<asp:HiddenField ID="HiddenCheckBox" Value='<% #Eval("ReferenceRobot")%>' runat="server" />
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
<asp:Button ID="MAJButton" runat="server" Text="Mettre à jour" CssClass="btn btn-success btn-lg btn-block"/>
</div>
And the code behind is the following :
public partial class WebForm1 : System.Web.UI.Page
{
protected List<MiseAJour> ListeMAJs;
protected List<string> ListeVersionsMAJs;
protected List<ConnectedRobots> ListeRobotsConnectes;
protected List<string> ListeRefRobots;
protected DropDownList ddlVersionMAJ;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
GetConnectedRobots();
Repeater repCRobots = this.FindControl("repCRobots") as Repeater;
repCRobots.DataSource = ListeRobotsConnectes;
repCRobots.DataBind();
foreach (RepeaterItem item in repCRobots.Items)
{
ddlVersionMAJ = item.FindControl("VersionsMAJs") as DropDownList;
ddlVersionMAJ.DataSource = ListeVersionsMAJs;
ddlVersionMAJ.DataBind();
}
}
}
private void GetConnectedRobots()
{
WebserviceRobots ws = new WebserviceRobots();
string[] delimiters = new string[] { "|", "||" };
string connectedRobots = ws.getConnectedRobots();
string majsDetails = ws.getMajsDetails();
string[] connectedRobotsInfos = connectedRobots.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
string[] majsInfos = majsDetails.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
ListeRobotsConnectes = new List<ConnectedRobots>();
ListeRefRobots = new List<string>();
ListeMAJs = new List<MiseAJour>();
ListeVersionsMAJs = new List<string>();
for (int i = 0; i < majsInfos.Length - 1; i += 3)
{
ListeMAJs.Add(new MiseAJour() { VersionMAJ = majsInfos[i], DetailsMAJ = majsInfos[i + 1], Commentaires = majsInfos[i + 2] });
}
ListeVersionsMAJs = ListeMAJs.Select(v => v.VersionMAJ).ToList();
for (int i = 0; i < connectedRobotsInfos.Length - 1; i += 5)
{
ListeRobotsConnectes.Add(new ConnectedRobots() { ReferenceRobot = connectedRobotsInfos[i], VersionControleur = connectedRobotsInfos[i + 1], IPRobot = connectedRobotsInfos[i + 2], Pays = connectedRobotsInfos[i + 3], Etat = connectedRobotsInfos[i + 4], VersionsMAJ = ListeVersionsMAJs });
}
ListeRefRobots = ListeRobotsConnectes.Select(r => r.ReferenceRobot).ToList();
}
protected void VersionsMAJs_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList dll = (DropDownList)sender;
string test = dll.SelectedValue;
}
the GetConnectedRobots() method is used to retrieve both update versions, and connected robots using a web service and couple of dynamically generated xml files.
On selectedIndexChanged, I should get the selected value or so I thought. SelectedValue always returns the first element of the dropdown list. What am I doing wrong?
I do have EnableViewState="true" for persistence between postbacks.
I am open to all kinds of answers, even if it means restructuring the whole code,
Thank you for your answers,

So I resolved the issue after almost going insane, the problem weirdly enough was with getMajDetails() implemented in the WebserviceRobots. This method is used to deserialise an XML document containing updates versions and some other informations, and to return a string with these elements seprated by | character. However, it seems like XDocument automatically adds new line char at the end of each element, resulting in a string similar to this one :
1.7.1940\r\n| Détails concernant le MAJ 1.7\r\n| Commentaires 1.7\r\n||2.0.2542\r\n| Détails concernant le MAJ 2.0\r\n| Commentaires 2.0\r\n||1.8.2495\r\n| Détails concernant le MAJ 1.8\r\n| Commentaires 1.8\r\n||
So, each ListeVersionsMAJs element ends up with \r\n at the end. and When this list is used to populate the dorpdown list, it causses it to behave the way it did (returning the first value at each postback). the solution was to remove \r\n .
I have no explanation as to why this is happening, testing the dropdown list with a List of strings initialized with fixed string values with new line char at the end of each value resulted in the same odd behavior.
So if anyone could clear this up, it would be much appreciate it.

Related

Repeater causes postback of the whole page even if it's inside an update panel

I have an user control that contains an update panel with a repeater. The repeater has a button used to delete records.
The problem is when I press the delete button, and a record from the repeater gets deleted, a postback on the whole page is triggered. From my understanding, only the section inside the update panel should refresh.
I should also mention that on my master page I have a script manager with the property "EnablePartialRendering" set to true.
Can someone help me with this problem? Thanks in advance.
ASP file:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ActivityFiles.ascx.cs" Inherits="Training.User_Controls.ActivityFiles" %>
<asp:Repeater ID="FilesRepeater" runat="server">
<HeaderTemplate>
<table class="table table-bordered">
<tr>
<td><b>Name</b></td>
<td><b>Description</b></td>
<td><b>Actions</b></td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<tr>
<td><%# Eval("Name")%></td>
<td><%# Eval("Description")%></td>
<td>
<asp:LinkButton ID="DownloadFile" runat="server" OnClick="DownloadFile_Click" Font-Size="Large"
file-path='<%# Eval("Url")%>'>
<span class="glyphicon glyphicon-floppy-disk text-info" aria-hidden="true"></span>
</asp:LinkButton>
<asp:LinkButton ID="DeleteFile" runat="server" OnClick="DeleteFile_Click" Font-Size="Large"
file-id='<%# Eval("Id") %>'
file-path='<%# Eval("Url") %>'>
<span class="glyphicon glyphicon-trash text-danger" aria-hidden="true"></span>
</asp:LinkButton>
</td>
</tr>
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
.cs File:
protected void Page_Load(object sender, EventArgs e)
{
activityId = (int)Context.Items["activityId"];
if ( ! IsPostBack && Visible)
{
if (activityId != 0)
{
LoadFiles();
}
}
}
private void LoadFiles()
{
DataTable files = DatabaseHelper.SelectAsDatatable(FilesQueries.GET_ACTIVITY_FILES, new Dictionary<string, object> {
{ "activityId", activityId }
});
FilesRepeater.DataSource = files;
FilesRepeater.DataBind();
if (files.Rows.Count == 0)
{
FilesRepeater.Visible = false;
NoRecords.Visible = true;
}
}
protected void DeleteFile_Click(object sender, EventArgs e)
{
// TODO: modify this function to work only with the fild id
LinkButton deleteButton = (LinkButton)sender;
string fileId = deleteButton.Attributes["file-id"];
string filePath = deleteButton.Attributes["file-path"];
DatabaseHelper.ExecuteNonQuery(FilesQueries.DELETE_FILE, new Dictionary<string, Object>() {
{ "#fileId",fileId },
});
//delete file from disk
string path = Server.MapPath(filePath);
FileInfo file = new FileInfo(path);
if (file.Exists)
{
file.Delete();
}
LoadFiles();
}
Found the solution on another stackoverflow post (See Eugene S answer)
You have to manually add you control to Script Manager. You should do that inside File Repeater's Item created event. Good luck.

Hide EmptyDataTemplate but leave header visible

I have an EmptyDataTemplate on my ASP.NET webform which allows users to add a record to the database. Depending on the permissions of the user, this EmptyDataTemplate needs to be visible and hidden if no data is found (I have this working!)
For example, my user has Read Access only. When they search a specific criteria, no results are displayed they cannot see the EmptyDataTemplate. However, if they search a criteria, and there is data, data is displayed WITHOUT the headers.
Can someone please help explain why this is happening and if there's a way around it?
The headers are HeaderText on TemplateFields.
I'm hoping it's a general trick.
Thank you in advance for your help!
Please note, it's the HeaderText in the TemplateFields I want to display- not the in the emptyDataTemplate as they'll head up the columns of data that match the search criteria.
edit: code added as requested
For hiding the EmptyDataTemplate:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Control control = null;
control = GridView1.Controls[0].Controls[0];
if (userManagement.getMIFReadWriteAccess() == "Read")
{
control.Visible = false;
Export_All.Visible = true;
}
else if (userManagement.getMIFReadWriteAccess() == "Write")
{
control.Visible = true;
Export_All.Visible = true;
}
}
in markup for the header text (i've only shown one column but the markup is the same for all of them)
<asp:TemplateField HeaderText="ID">
<ItemTemplate>
<asp:Label ID="lbl_Index" runat="server" Text='<%#Eval("id") %>'></asp:Label>
<asp:Label ID="lbl_ID" runat="server" Text="" Visible="false"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
EmptyDataTemplate:
<EmptyDataTemplate>
<div id="emptyData" runat="server">
<tr>
<th></th>
<th>Serial Number</th>
<th>Comments</th>
<th>Review Date</th>
<th>Approved By</th>
</tr>
<tr>
<td>
<asp:Button runat="server" ID="btInsert" Text="In" OnClick="Add" CommandName="EmptyDataTemplate" Class="Button" OnClientClick="return confirm('You are about to confirm this action. Please confirm this action by clicking OK. If you do not wish to do this, please select Cancel.');" />
<br />
<asp:Button runat="server" ID="btInsertOut" Text="Out" OnClick="AddOut" CommandName="EmptyDataTemplate" Class="Button" OnClientClick="return confirm('You are about to confirm this action. Please confirm this action by clicking OK. If you do not wish to do this, please select Cancel.');" />
</td>
<td>
<asp:TextBox runat="server" ID="tb_Serial_Number" CssClass="text"></asp:TextBox>
</td>
<td>
<asp:TextBox ID="tb_comments" Width="100%" MaxLength="50" runat="server" placeholder="max 50 characters"/>
</td>
<td>
<asp:TextBox ID="tb_reviewDate" runat="server" DataFormatString="{0:dd/mm/yyyy}" Text='<%#Eval("review_by") %>'></asp:TextBox>
</td>
<td><asp:DropDownList ID="tb_approved_by" runat="server">
</asp:DropDownList> </td>
</tr>
</div>
</EmptyDataTemplate>
After trial and error, I found that programatically adding a header row in C# did the trick. Probably not the best way of doing it, but it worked.
Code is as follows:
#region show the emptyDataTemplate depending on user rights
Control control = null;
control = GridView1.Controls[0].Controls[0];
if (userManagement.getMIFReadWriteAccess() == "Read")
{
control.Visible = false;
GridViewRow HeaderRow = new GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Insert);
TableCell HeaderCell2 = new TableCell();
HeaderCell2.Text = "Country";
HeaderCell2.ColumnSpan = 1;
HeaderRow.Cells.Add(HeaderCell2);
//Repeat the above for every column of data you have!
GridView1.Controls[0].Controls.AddAt(0, HeaderRow);

NavigateUrl in ASP.Net

I am new to ASP.NET. I am having problem with NavigateUrl.
<td align="right" valign="middle">
<p id="posCstmr">
<asp:HyperLink ID="hlnkContact" CssClass="addbtn-cmplist" runat="server" NavigateUrl='<%# "Actions/Contact.aspx?ContactID=" + Eval("ContactID") + "&CompanyID=" + Eval("CompanyID") %>' Text="View"></asp:HyperLink>
</p>
</td>
When I click to view following hlnkContact, it redirects to the following link with specified values which is OK.
[http://localhost:1426/Actions/Contact.aspx?ContactID=78724&CompanyID=92971]
But I want to store these values in session variables on Page_load event of Contact.aspx.
if (!Page.IsPostBack)
{
Session["ContactID"] = String.IsNullOrEmpty(Request.QueryString["ContactID"].ToString()) ? String.Empty : Session["ContactID"];
}
But I cant store the Session variable on Page_Load because NavigateUrl show the values after loading of this page.
Please Help me.
Same type of question was answered HERE, you can tweak like below:
[Assuming that the td is inside any databound container, else Eval wouldn't work]
Change your markup to this:
<td align="right" valign="middle">
<p id="posCstmr">
<asp:LinkButton ID="LinkButton1" CssClass="addbtn-cmplist" runat="server"
Text="View" CommandName="Link" CommandArgument='<%#Eval("ContactID") + ";" + Eval("CompanyID") %>'
OnClick="ButtonLink_Click" />
</p>
</td>
Code:
protected void ButtonLink_Click(object sender, System.EventArgs e)
{
LinkButton lb = (LinkButton)sender;
string[] arguments = lb.CommandArgument.Split(';');
string ContactID = arguments[0];
string CompanyID = arguments[1];
//Save in session
Session["ContactID"] = ContactID ;
Session["CompanyID"] = CompanyID ;
//Redirect
Response.Redirect(string.Format("Actions/Contact.aspx?ContactID={0}&CompanyID={1}", ContactID, CompanyID));
}

create a filter row with textboxes on each column in asp.net gridview

I have a asp.net gridview, which i am binding at runtime with a custom List object. I want to add a filter row below the header row on each column and on click of filter button grid data should get filtered based on values written in the filter textboxes. requirement seems weird but this is what client wants. please help with some clue.
aspx code :
<asp:TemplateField>
<HeaderStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />
<ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="150px" />
<HeaderTemplate>
<table>
<tr>
<td align="center">
<asp:ImageButton runat="server" ID="imgFilter1" ImageUrl="../Images/filter.png" Style="height: 20px;
width: 20px;" OnClick="imgFilter1_click" />
</td>
<td align="center">
<asp:TextBox runat="server" ID="gridTextboxFilter1" AutoPostBack="true" onTextChanged="gridTextboxFilter1_text_changed">
</asp:DropDownList>
</td>
</tr>
<tr>
<td align="center" colspan="2">
//your column header
</td>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<asp:Label runat="server" Text='<%# Eval("your_dataFeild") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
cs code :
private void BindGrid(string strFilter)
{
try
{
// Simple created a table to bind with Grid view and
// populated it with data.
DataTable dt = new DataTable("sample");
dt.Columns.Add("ID");
dt.Columns.Add("Name");
DataRow dr ;
for(int counter=1;counter<11;counter++)
{
dr = dt.NewRow();
dr["ID"]=counter.ToString();
dr["Name"]= "Cat" + counter.ToString();
dt.Rows.Add(dr);
}
DataView dv = new DataView(dt);
if(strFilter != "")
dv.RowFilter="Name like '%" + strFilter + "%'";
if (CategoryFilter == "")
gvCategory.DataSource = dv;
else
gvCategory.DataSource = dv;
gvCategory.DataBind();
}
catch (Exception ex)
{
}
finally
{
}
}
protected void gridTextboxFilter1_text_changed(object sender, EventArgs e)
{
string text = ((TextBox)sender).Text;
BindGrid(text);
}
Add a textbox and button on the header template.
Write a query on button press and get the value.
The query something like select * from tbl where col like '%val%'
Bind the value to gridView.
I think this will solves for you

clearing checkboxlist

on my save button i want to clear all values of form i did the following for CheckBoxList beach.
But it doesn't work. Why so, it doesn't make values clear for checkbox list
Branch is filled like this:
protected void course_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
int courseId = Convert.ToInt32(course.SelectedValue);
DataTable dt;
dt = placementManager.GetBranchList(courseId);
if (dt.Rows.Count != 0)
{
Branch.DataSource = dt;
Branch.DataTextField = "branch_name";
Branch.DataValueField = "branch_id";
Branch.DataBind();
}
Btnsave.Visible = false;
GridView1.Visible = false;
}
catch (Exception ex)
{
COMMON.logger.Error("Error on course_SelectedIndexChanged:CompanySelected.aspx.cs", ex);
}
if (b)
{
gridNotExist.Text = "Records Successfully inserted for the displayed table, To insert new records select new entries";
this.ViewState.Remove("selectedList");
this.ViewState.Remove("dt");
Session.Abandon();
passout.SelectedIndex = 0;
company.SelectedIndex = 0;
txtpackage.Text = "";
course.SelectedIndex = 0;
Branch.DataSource = null;
Branch.DataBind();
vistDate.Text = "";
txtvenue.Text = "";
//GridView1.Visible = true;
}
}
aspx page has, of course, branch like this:
<asp:UpdatePanel id="update" runat="server">
<contenttemplate>
<td>
<asp:DropDownList ID="course" runat="server" AutoPostBack="True" OnSelectedIndexChanged="course_SelectedIndexChanged" />
<asp:CustomValidator ID="coursenecessaryForSaveButton" runat="server" ControlToValidate="course" ErrorMessage="Select A Course" OnServerValidate="coursenecessaryForSaveButton_ServerValidate" ValidationGroup="save" />
</td>
<td>
<asp:CustomValidator ID="courseNecessary" runat="server" ErrorMessage="Select A Course" OnServerValidate="courseNecessary_ServerValidate" ValidationGroup="verify" />
</td>
<td style="width: 101px">
Branch Name*
</td>
<td style="width: 126px">
<asp:CheckBoxList id="Branch" runat="server" />
</td>
</contenttemplate>
</asp:UpdatePanel>
<asp:CheckBoxList id="Branch" runat="server" >
is in a different UpdatePanel to the control which is triggering the asynchronous postback - and firing your eventhandler: course_SelectedIndexChanged.
Put the Checkbox List inside the UpdatePanel with id="update" and it will solve your problem.
Still, i would consider refactoring your HTML (and code while you're at it).
For instance - you have two UpdatePanel's - why?
The second one has nothing in it besides checkboxes. The purpose of an UpdatePanel is to dynamically update portions of a page (ie dynamic information) without a full postback.
Having nothing but static controls (checkboxes) inside an UpdatePanel isn't really serving any purpose.
However, my above answer is a stab in the dark at what you're after. You're code-behind code does'nt really make sense:
if (b == true)
Where is b defined??
Branch.DataSource = null
Branch.DataBind()
What are you binding??

Resources