strange conversion error when grabbing dropdownlist from form - asp.net

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.

Related

What happenned to the 'Selected' property of the ListItem?

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!!

How to access a ListViewDataItem datakeys

I am wondering how to access the datakeys of a ListViewDataItem that is a member of a ListView.
What I find strange is that when debugging it is possible to access the DataKeysContainer which can be seen here
However when attempting to access the DataKeyContainer during coding it is impossible, which can also be seen here
Any advice on how to access the datakeys and their values for a ListViewDataItem would be greatly appreciated.
You can use late binding, i.e. box your loop variable in an Object. This allows you to defer member validation until when the member is accessed at run-time. It is similar to dynamic in c#.
For Each itemObject As Object In lstViewModules.Items
' the DataKeysContainer you were looking for
Dim container = CType(itemObject.DataKeysContainer, Control)
' the same l in your loop
Dim l = CType(itemObject, ListViewDataItem)
' from here on, the rest of your loop code should work
Dim key As DataKey = lstViewModules.DataKeys(l.DataItemIndex)
Dim value = key("name")
Next
Since you know it's a ListView, you could also cast container to ListView for design-time ease.
Note: you must have Option Strict Off for this to work.

ASP Net - Casting a Request.Form control from Code Behind

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

Help with dynamically added controls in .net

I'm stuck! I understand the page lifecycle and how i need to add the dynamic controls on page_init if I want to take advantage of viewstate. Also I know that I should try to avoid dynamic controls when possible. The dynamic controls are created depending on an object that is created from custom event arguments sent from a custom treeview. Problem is I need viewstate so I need to create them in page_init but I don't have the event args to create the object that tell me what controls to add until later in the lifecycle. Solution...
Private Function GetEventArgs() As npTreeViewEventArgs
Dim control As Control = Nothing
Dim e As npTreeViewEventArgs = Nothing
Dim ctrlname As String = Page.Request.Params("__EVENTTARGET")
Dim args As String = Request.Params("__EVENTARGUMENT")
If ctrlname IsNot Nothing AndAlso ctrlname <> String.Empty Then
control = Page.FindControl(ctrlname)
End If
If TypeOf control Is npTreeView AndAlso Not String.IsNullOrEmpty(args) Then
e = New npTreeViewEventArgs(args)
End If
Return e
End Function
I use this in page_init to create my object and controls. This feels very dirty to me. Is there another way to handle this?
This is actually the most straightforward solution to this type of problem. If you can't add all the controls to the page on every postback and use visibility to control their appearance, then what you are doing there is exactly what I would recommend. (And have recommended before.)
I cringe when I see people resort to redirects, or implementing their own viewstate tracking, or doing extreme dynamic control manipulation to solve this. It may feel dirty, but it's infinitely more understandable and maintainable than the alternatives.
Yes. The way I did it is to overload the viewstate of the dynamic controls to store it in their parents viewstate. Also overload the reading of the dynamic controls view state. Then you can create them late in the page cycle.
Of course it is a little trickier than that... but you get the idea. (I would post code examples, but it was a prior job and don't have access to them right now.)

Why is the DataBind() method necessary?

Simple question, I guess.
For a long time I've blindly followed a (supposedly) common pattern when programmatically databinding my ASP.NET controls. Namely:
gridView1.DataSource = someList;
gridView1.DataBind();
However, if I were setting my GridView to bind to a DataSource control via the DataSourceID property, the call to DataBind() is unnecessary. Namely:
gridView1.DataSourceID = LinqDataSource1;
is sufficient.
Furthermore, if you try to set the DataSource property in ASPX markup, you are greeted with the following:
You cannot set the DataSource property declaratively.
I assume these are related, but I am still stumped as to why DataBind() is necessary. The difference between DataSource and DataSourceID is secondary - I can understand some magic taking place there. The real question is why doesn't the DataSource propery setter cause databinding automatically? Are there any scenarios in which we want to set the DataSource but not bind to it?
In ASP.Net, it's often important to have certain data available and ready at certain points in the page life cycle, and not before. For example, you may need to bind to a drop down list early to allow setting the selected index on that list later. Or you might want to wait a bit to bind that large grid to reduce the amount of time you hold that connection active/keep the data in memory.
Having you explicitly call the .DataBind() method makes it possible to support scenarios at both ends of the spectrum.
DataSource is a property of the BaseDataBoundControl class. DataSourceID is a property of the DataBoundControl class, which inherits from BaseDataBoundControl and did not exist before ASP.NET 2.0.
Since DataBoundControl is explicitly for displaying data in a list or tabular form, and BaseDataBoundControl cannot make that assumption, binding is not automatic when DataSource is set because the type of control may not match the structure of the data.
Of course, this is all just a guess based on the MSDN documentation, so I could be wrong.
I noticed that without using DataBind() that nothing will be displayed in my GridView so I always include it as shown in this section of code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' TableAdapter object.
' Provide communication between this application and the database.
'-----------------------------------------------------------------
Dim suppliersAdapter As New SuppliersTableAdapter
' Get the data from the TableAdapter into the GridView.
'------------------------------------------------------
GridView1.DataSource = suppliersAdapter.GetSuppliers()
' Display the result set from the TableAdapter in the GridView.
'--------------------------------------------------------------
GridView1.DataBind()
End Sub
Please forgive the extra commenting as I'm also still learning ASP.Net as well and the comments will help me learn better "what and why" to use certain statements.
Try this:
if (GridView1.EditIndex == e.Row.RowIndex)
{
TextBox t2 = (TextBox)e.Row.FindControl("TextBox2");
DateTime dt2;
if (DateTime.TryParse(t2.Text, out dt2))
{
t2.Text = dt2.ToString("yyyy-MM-dd");
}
}

Resources