I'm in the process of creating a submission form that generates a PDF through ASP with back end VB and iTextSharp. Some of the questions are CheckBoxLists where multiple values can be selected and I need to keep track of which ones are selected by the user so certain triggers can happen upon PDF generation. From my research, I would think it would be as simple as checking the Selected property of each ListItem in the given CheckBoxList like so:
Public Sub getCheckBoxValues(checkboxlist As CheckBoxList)
Dim strchklist As String
Dim testItems As New List(Of ListItem)
For Each li As ListItem In checkboxlist.Items
If li.Selected Then
'insert code here (adding to List for checks in this case)
End If
Next
End Sub
However in trying to run and work with it (in VS 2017), I keep getting an error that states "'Selected' is not a member of 'ListItem'" which makes no sense to me. Every source that I've found through ASP Snippets, Asp Forums, and other sources etc. gives me every indication that this property should still exist.
Is there something that I'm not aware of or another method, property, or solution out there that does what I'm trying to do that I'm not aware of? I would love some assistance and guidance on this.
Thank you very much!!
Related
I'm designing a custom ASP.NET drop down list for a Web application to display a list of a lot of organizations.
Btw: I reviewed every other SO question related to dynamically creating a drop-down-list and I couldn't find an answer.
Since there's a lot of organizations I want to build the item list as fast as possible.
Here's my ideas:
I'd share the list like this:
Imports System.Web.UI.WebControls
Public Class Organizations
Inherits DropDownList
Private Shared m_Organizations As List(Of Organization) = Nothing
Public Sub CreateChildControls()
' If list not populated get list from database.
If m_Organizations Is Nothing Then
m_Organizations = Get_Organizations()
End If
For Each Org As Organization in Organizations
Item_Obj = New ListItem(Org.Name, Org.OrgId)
Items.Add(Item_Obj)
Next
MyBase.CreateChildControls()
End Sub
End Class
I did a test. I created a single web page with two copies the drop down list. I ran the web page.
On initial startup of the web page I see m_Organization Is Nothing and Get_Organizations is called.
When I select an organization I see m_Organizations IsNot Nothing so Get_Organizations is not called. That's what I wanted.
When I click on a Submit button on the test page I see m_Organizations IsNot Nothing so Get_Organizations is not called. That's what I wanted.
So Organizations is persisted across page postbacks.
Now my question.
Suppose 3 users are using the web application at the same time and they display the web page with the Organizations drop down list.
Will m_Organizations be shared with all three web applications so it is loaded only once for all three users?
Or, is each user in their own process and therefore GET_Organizations will be called a total of three times?
Thanks, Ed
Each user has their own web page, controls, and code values. They each get their own code copy and their code runs just FOR each user.
So, to load up the dropdown list? It not clear why you pulling into a list?
The base .net objects such as row, and dateable run a lot faster then lists. And these base types can be directly binded to the drop down list (no need for a loop).
So, your on load would be something like:
So, in page load event, you have this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
Me.Instutions.DataSource = Myrst("select ID,Institution from Institutions")
Me.Instutions.DataBind()
End If
End Sub
So, only on the page load do we fill up the combobox (drop down list). You check the "isPostback" value.
Now it possible that you using datasets (or the newer EF) for the data. But even in that case, you can get/grab the data table from that, and shove it directly into the dropdown list data source. You as a general rule will NOT run loops to fill these types of controls (gridview, listview, dropdownlist). They can be bound directly to the result of the data source without loops. And since each users will get their own copy of the data, and your code runs for each user? Then you do want to avoid things like loops - since that code will run separate for each user and each page post back.
So yes, each user gets their own web page, gets their own variables, and runs their own code 100% separate from each user. And that includes a copy of the datasets you have.
When the user selects a value from the drop down list? (yes, we have auto postback = true), and thus the code for that wlll look like:
Protected Sub Instutions_SelectedIndexChanged(sender As Object,
e As EventArgs) Handles Instutions.SelectedIndexChanged
' pk id from drop list = Instutions.SelectedValue
' text value from drop list = Instutions.DataTextField
End Sub
So, it only takes two lines of code to load up the dropdown list - even when you don't have a dataset, or are using EF.
Now, I did use a helper routine called myrst(), and it can be used to fill dropdown lists, datagrids, listviews etc. and once again only two lines of code, and no looping.
that "handy" routine is this:
Public Function Myrst(strSQL As String) As DataTable
Dim mycon As New SqlConnection(My.Settings.Test4)
Dim oReader As New SqlDataAdapter
Dim rstData As New DataTable
oReader.SelectCommand = New SqlCommand(strSQL, mycon)
Try
oReader.Fill(rstData)
Return rstData
Catch
Debug.Print(Err.Description)
Return Nothing
End Try
End Function
So when they select a value in the drop down list? You do get a full page post back, and your on-load event will run. And yes, EACH user has their own web page, and own copy of that code running - they are not relegated to each other in ANY way, and all local, global variables and code is run 100% in a separate session for each user. And each user also has their own Session() variables - and again they are 100% separate and not shared between all users.
So yes, all 3 users will each call and each load up their own copy of that data. (yes, it called 3 times). if that was not the case, then what would occur if you wanted to filter only companies or records belonging to the one user? so you can consider all code and even loading of data a 100% separate thing/concept and process for each user.
I usually make user controls containing forms for adding and editing data for a particular table in my database. I then show or hide these controls as the user clicks "edit" buttons, etc. It's common practice (for me) to put properties in the code-behind, that are used for setting the ID of the item being edited, into a hidden label on the page, and of course leaving it blank for new items being inserted. I usually only use C#, however, this time around I have to use VB.NET.
So in C# I would do the following:
public static int EditID
{
get
{
return Convert.ToInt32(lblEditID.Text);
}
set
{
lblEditID.Text = value;
}
}
..and then when the user, say, clicks an "edit" link from a gridview, I would
//set the ID of the corresponding record, something like this:
MyUserControl.EditID = MyGridView.SelectedDataKey[0];
Cool. So now I need to do this in VB.NET, and here's my code:
Public Shared Property EditID As Integer
Get
Return Convert.ToInt32(lblEditID.Text)
End Get
Set(value As Integer)
lblEditID.Text = value
End Set
End Property
but I get a syntax error that says: "Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.", highlighting the lblEditID for both the getter and setter.
I can't find any other SO questions about this, and I have Google'd just about every permutation of keywords I can think of, so this must be something really stupid.
What am I doing wrong here?
EDIT: Yes I realize I could just use a Session variable instead of the label, but I would still like to know why this doesn't work and how I could make it work with a label.
You don't want a Shared property for this. lblEditID is a label that exists in an instance of a WebForm class:- it can't exist until an instance of this class has been created, hence the error.
I don't really understand how the C# worked as this should be the same but I'm not a C# expert.
If you remove the Shared keyword it will work as you want I believe
I've got a .net web form, back end is in vb.net. A few dropdownlists are added to the form, with their controls following the naming convention "ddlCol" + integer, so "ddlCol0", "ddlCol1", etc.
When I try and grab one of these dropdownlists to code against the control, I'm getting a conversion error from string to integer: Conversion from string "ddlCol0" to type 'Integer' is not valid.
Here is the code I'm using:
sDDL = "ddlCol" + iDDLControlCounter.ToString()
Dim ddl As DropDownList = CType(Me.Controls(sDDL), DropDownList)
I admit my vb.net is a bit rusty. Is there something dumb I'm doing wrong?
You have to use & if you want to concat strings in VB.NET (as oposed to C#):
sDDL = "ddlCol" & iDDLControlCounter.ToString()
However, that should not cause your conversion error. Maybe sDDL is declared as Int32.
Anyway, you should set OPTION STRICT to On because i suspect that the error is caused by an implicit conversion. Late binding should be avoided if possible.
See: Option Strict Statement
Edit: Controls.Controls is a collection which has an indexer. So you can get the first control via Me.Controls(0). So that is the main reason for the exception because sDDL is a String. But thisknowledge does not help further to find your DropDownLists.
So read more ...
Could the fact that these dropdowns are in the header row of a
gridview make a difference? I was of the mindset that a control is a
control is a control, but maybe there are rules I don't know about
with this?
No, that doesn't make a difference. Then you would get a NullReferenceException when you try to use your DropDownList.
But you need to use Control.FindControl to get a reference of a control via it's ID.
If it is really in a header row of a GridView you have to use FindControl on the correct NamingContainer which is the HeaderRow:
If grid.HeaderRow IsNot Nothing Then
Dim ddl = DirectCast(grid.HeaderRow.FindControl("ddlCol" & iDDLControlCounter), DropDownList)
End If
The issue isn't with your string concatenation, but rather with your assumption about how the Controls collection works; it only takes a numeric value.
Instead, I believe the method you need to be using is FindControl:
sDDL = "ddlCol" & iDDLControlCounter.ToString()
Dim ddl As DropDownList = CType(Me.FindControl(sDDL), DropDownList)
Note that if you know the precise type, DirectCast is (fractionally) faster than CType.
The actual error in the OP is that Me.Controls() only takes an integer as an arguement, not a string.
This seems really simple, but for some reason Im stumped..
Im dynamically generating an HTML Select Box, lets call it myselect. Im creating this select box based on some database values Im generating an HTML Select Box.. almost like a string that Im just spitting out to the page. So it's never a control in the codebehind, just part of a string thats rendered as HTML by the browser. If I submit my form, and in my codebehind I perform:
Dim myVal as String = Request.Form("myselect")
That code will give me the VALUE of the myselect select box. How can I refer to this control to cast it as a System.Web.UI.HtmlControls.HtmlSelect control? Request.Form seems to give me the value, but I want to reference the object itself..
If this select box isn't declared statically on your page (that is, you're adding it to the Control Collection), you'll have to do something like this: Dim MySelect as HtmlSelect = Page.FindControl("MySelect") as HtmlSelect
You'll have to forgive me if my casting syntax is a bit off -- I'm used to casting in C#.
If your dynamically generating the control in your code file, then it will not be available to you on post back. As long as you generate it again before the viewstate is processed (you can do it in your oninit), then you can access it as you would anything else.
MySelect.SelectedValue
In response to the comments above (thanks for your help), I found what Gabriel McAdams and jwiscarson had to say were true. In browsing the Request object, I found that its nothing more than a collection of key\value pairs. Performing Request.Form("myformobj") will return a value, because thats all thats available to the application. If necessary, I suppose I can whip up some nifty javascript to track form object types, but it's certainly not necessary in my case.
Thanks for the help
I've two issues currently preventing me from finishing two projects properly. I'll put them both here as I believe they're connected to the asp.net page lifecycle, but I can't find a way around them.
First I have a DropDownList which I must sort in codebehind. It only contains text, so I should be able to do that with the following method called in page load:
Dim alist As ArrayList = New ArrayList
For Each litem As ListItem In ltEsittelyDropDownList.Items
alist.Add(litem.Text)
Next
alist.Sort()
Dim uusiDDList As New DropDownList
For i As Integer = 0 To alist.Count - 1
Dim litem As New ListItem
litem.Text = alist(i).ToString
litem.Value = alist(i).ToString
uusiDDList.Items.Add(litem)
' Response.Write(alist(i).ToString)
Next
ltEsittelyDropDownList = uusiDDList
ltEsittelyDropDownList.DataBind()
As you can see, there's a commented response.write in there, which shows the list is actually sorted. So why, when I load the page, can't I see any effect?
The other problem, which is more critical and difficult, is as follows:
In the aspx page I'm binding a SQL Server 2005 datasource to a gridview. And in the code-behind I catch on to the RowDataBound event in which I handle some links and properties inside the gridviews' cells. But I cannot get this to work on the first page load, only after the first extra postback.
So, what is there to do? And thanks for all advice in front!
Your first problem is calling DataBind on a control you have filled manually. You likely have a DataSource specified in the control declaration, which is being used when DataBind is called. You can simplify the code by just adding the list items to the original control:
For i As Integer = 0 To alist.Count - 1
ltEsittelyDropDownList.Items.Add(New ListItem(alist(i).ToString())
Next
Alternatively, as you have a collection already, you can just bind it to the control:
ltEsittelyDropDownList.DataSource = alist
ltEsittelyDropDownList.DataBind()
For your second problem, some example code would help - specifically, where and how the control is databound and the code in RowDataBound.