ASP.NET TreeView control - CheckedNodes is always empty - asp.net

I have an ASP.NET TreeView control with the "ShowCheckboxes" state set to "All".
If I check the boxes on the tree, then the tree.CheckedNodes property is always "False".
I've also tried looking at the individual Nodes(i).Checked property, but those are also all false.
If I manually set the Checked property to True from code, then it does get reflected in the .CheckedNodes property.
I feel like I must be missing something obvious- why would this simple boolean property fail to reflect what I've done in the UI?
Protected Function GetChosenIDs() As List(Of Guid)
Try
Dim result As List(Of Guid) = New List(Of Guid)
'This loop never executes, because nothing is marked "Checked".
For Each node As TreeNode In tree.CheckedNodes
result.Add(New Guid(node.Value))
Next
Return result
Catch ex As Exception
Throw ex
End Try
End Function

Related

How to set visibility on public property in VB.NET

I am maintaining some old code, I am a c# developer.
We have a usercontrol with a tablecell that I want to hide with my code on my other aspx page. It is reference and all that good stuff.
But how do you write a property to set visibility in vb.net.
Something like this, but not working.
Public Property vis As TableCell
Get
LogoArea.Visible = False
End Get
Set(value As TableCell)
LogoArea.Visible = True
End Set
End Property
Use this instead:
Public Property LogoVisible As Boolean
Get
Return LogoArea.Visible
End Get
Set(value As Boolean)
LogoArea.Visible = value
End Set
End Property
This wraps around the Visible property of the LogoArea cell. Assuming it's a TableCell from your previous example, which is the web controls version, not the HtmlControls version.

DataContext Disposal error resolved but why?

I am working with VB.Net. I have resolved a behavior where the code returns with an error of "Cannot access a disposed object. Object name: 'DataContext accessed after Dispose.'."
My problem : I simply don't understand why it works !
Here is my code when happens the error :
Public Function Element_Import(ByVal id_element As Integer) As elements
Using db As New GlobalDataContext(MyConnexion)
Return (From element In db.elements
Select element
Where element.id_element = id_element).First
End Using
End Function
Then I try to retreave the data :
Dim myElement As elements = _MyConnection.Element_Import(id_element)
Dim myLocal As List(Of elements_localisation) = myElement.elements_localisation.ToList '-- ObjectDisposedException !
When I import my element then try to access sub-tables called "elements_localisation" and "elements_files" an ObjectDisposedException occures. That's fair as the DataContext is not available.
So I have done something different :
Public Function Element_ImportContext(ByVal id_element As Integer) As elements
Dim myElement As elements
Dim myElementLocalisation As New List(Of elements_localisation)
Dim myElementFiles As New List(Of elements_files)
Using db As New GlobalDataContext(MyConnexion)
myElement = (From element In db.elements
Select element
Where element.id_element = id_element).First
myElementLocalisation = myElement.elements_localisation.ToList
myElementFiles = myElement.elements_files.ToList
End Using
Return myElement
End Function
Then I try to retreave the data :
Dim myElement As elements = _MyConnection.Element_ImportContext(id_element)
Dim myLocal As List(Of elements_localisation) = myElement.elements_localisation.ToList '-- IT WORKS !
I really wanna understand what happened as, in both case, the DataContext is disposed.
Can anyone explain ?
When you write LINQ, you write a query to be executed against some data, that query is only executed when another part of the code needs the data.
In your case, you are returning the myElement variable because you have used .First(), which forces the query to be executed and the first item to be returned.
The properties elements_localisation and elements_files are likely to be virtual properties that are only loaded when you request them. (This is certainly the case with Entity Framework, I'm not sure what you're using here).
Your program will try to access the virtual property which will then go off to the data context to get the next bit of data you requested, but in your case the data context is disposed.
Your second approach works because you have used ToList() on the virtual properties, which forces the data to be retrieved then and there, before your data context has been disposed.

dynamically set control ID

i have few texboxt and dropdownlist, which their id would be something like "txtName1, txtName2, txtName3..." and "ddlAction1, ddlAction2, ddlAction3...."! I would to to dynamically set the textboxt and dropdownlist id into something like this:
for i as integer = 0 to 6
a = txtName+i.text
b = ddlAction+i.SelectedValue
next i
Need help from you guys to do this! thanks....
The key is FindControl, which looks up a control by its expected ID:
For i As Integer = 0 To 5
Dim txt As TextBox = TryCast(Me.Page.FindControl("txtName" & i.ToString()), TextBox)
Dim ddl As DropDownList = TryCast(Me.Page.FindControl("ddlAction" & i.ToString()), DropDownList)
If txt IsNot Nothing AndAlso ddl IsNot Nothing Then
Dim a As String = txt.Text
Dim b As String = ddl.SelectedValue
End If
Next
It will return null/nothing if a control with that ID isn't found.
Note that FindControl will only search the given control's (or Page's) immediate children, not the entire control tree. To search recursively, you need to use your own FindControl method.
Private Function FindControlRecursive(ByVal control As Control, ByVal id As String) As Control
Dim returnControl As Control = control.FindControl(id)
If returnControl Is Nothing Then
For Each child As Control In control.Controls
returnControl = child.FindControlRecursive(id)
If returnControl IsNot Nothing AndAlso returnControl.ID = id Then
Return returnControl
End If
Next
End If
Return returnControl
End Function
.Net requires you to resolve your variable names at compile time, rather than runtime like your code is trying to do. This is a good thing, as it prevents you from making certain kinds of errors. But it does mean you'll need to look at an alternative approach for this particular problem.
One option is a FindControl -based method. But odds are the controls you care about are grouped together on the page. If they aren't already, put them in a common container control, like a panel. Then you can do something like this (requires System.Linq):
For Each t As TextBox In MyContainer.Controls.OfType(Of TextBox)()
a = t.Text
Next t
For Each d As DropDownList In MyContainer.Controls.OfType(Of DropDownList)()
b = d.SelectedValue
Next d
Also, I hope you're really doing something other than assignment inside your loop. Otherwise, most of the work is for nothing as you will exit the loop having simply assigned the value from the last iteration to your variable.
Finally, it seems like these controls might work in pairs. To me, that's a situation that calls out for you to implement a user control.
I'm not a webforms expert, but I believe the page stores a reference to each control present in the page.
You can think of webforms like an n-ary tree... each control has a parent and can have 0 to many children. So, if these are static controls you should just be able to grab a reference to their parent and iterate over that... with no need for the children's ids.
Also, you can query for children based on their id... something like myControl["myID1"] so you can concat the number with the string and get the control that way.
Lastly, if these are purely dynamic controls, i.e. you don't know how many there are, just store references to them in an ordered collection and iterate over them that way.
EDIT:
Here we go:
WebControl myControl;
myControl.Controls.Add(someControlReference);
Then, to grab a control by ID:
WebControl someControl = myControl.FindControl("someControlID1");
From there you can do like:
string a = someControl.Text

ASP.NET Setting SelectedValue that doesn't belong to the list does not trigger Exception

I have an ASP.Net form where I use a DropDownList control to display data retrieved from a table. However setting the SelectedValue of the DropDownList to a value not existing in the dropdown list does not trigger an exception.
Try
dropDownList.SelectedValue = value
Catch ex as Exception
Throw
End Try
In the code above, if I assign a value that does not belong to the list's item, it does not throw an Exception. It just selects the first item in the list when the HTML is rendered.
Any ideas why?
By the way, I have a blank (String.Empty) item as the first item in the list. I also used DataBind() to bind the listItem to a DataTable. Does that make any difference?
Thanks guys for answering. What I ultimately did was used the FindByValue() method of the Dropdownlist and see if the value exists in the list:
If Not DropDownlist.Items.FindByValue(value) Is Nothing Then
' do what the Exception is supposed to do '
Else
DropDownList.SelectedValue = value
End If
The FindByValue() returns Nothing if the passed parameter does not belong to the list. I avoided using an Exception (which is heavy on processing) as a way to trap the problem, and it works exactly as I needed.
When the selected value is not in the
list of available values and a
postback is performed, an
ArgumentOutOfRangeException is
thrown:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listcontrol.selectedvalue.aspx
you can use this method for easy to set SelectedValue
private void DropDownSelectSafeValue(this DropDownList Drp, string Value) {
if (Drp.Items.FindByValue(Value) == null)
Drp.SelectedValue = Value;
}
I think the NOT should be removed. Otherwise, it's the reverse. This is what I did.
If ddAssignedDTL.Items.FindByValue(sqlreader("C_AssignedDTL").ToString) Is Nothing Then
' do what the Exception is supposed to do '
ddAssignedDTL.Items.Add(New ListItem("<Invalid DTL-" & sqlreader("C_AssignedDTL").ToString & ">", sqlreader("C_AssignedDTL").ToString))
ddAssignedDTL.SelectedValue = sqlreader("C_AssignedDTL").ToString
DTL = sqlreader("C_AssignedDTL").ToString
ddAssignedDTL.BackColor = Drawing.Color.Red
Else
ddAssignedDTL.SelectedValue = sqlreader("C_AssignedDTL").ToString
DTL = sqlreader("C_AssignedDTL").ToString()
End If

Asp.Net Button Event on refresh fires again??? GUID?

The obvious issue here is that on refresh a button event is recalled and duplicate posts are created in the database. I have read other questions on this site about the very same issue.
Apparently the answer is for every post create a GUID and check to make sure the GUID is unique? I am not really sure how to implement this.
Does that mean on refresh, it will try and create a duplicate post with the same GUID?
How do you implement a GUID into your database? Or if this is not the answer, what is?
Thank you!
The idea is that you create a unique number for the form, and when the form is posted you save this unique number in the database in the record that you are editing/creating. Before saving you check if that number has already been used, in that case it's a form that has been reposted by refreshing.
If you are updating a record, you only have to check if that record has been saved with the same unique number, but if you are adding a new record you have to check if any other record has that number.
A Guid is a good number to use as it's very unlikely that you get a duplicate. A 31 bit random number that the Random class can produce is also pretty unlikely to give duplicates, but the 128 bits of a Guid makes it a lot more unlikely.
You don't have to create the Guid value in the database, just use Guid.NewGuid() in the code that initialises the form. You can put the Guid in a hidden field in the form. In the database you only need a field that can store a Guid value, either a Guid data type if available or just a text field large enough to hold the text representation of the Guid.
You can use the ToString method to get the string representation of a Guid value (so that you can put it in the form). Using id.ToString("N") gives the most compact format, i.e. 32 hexadecimal digits without separators. Using id.ToString("B") gives the more recognisable format "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}". To get the Guid back from a string (either format), you just use new Guid(str).
Here's a RefreshValidator control that I use. Just drop it on your page, and check Page.IsValid before saving to the database. You can add an error message like other validators, or catch the Refreshed event if you want to do something special. Since it's a Validator, GridViews and the like will already take notice of it - except for Delete or Cancel actions (yeah, I have a custom GridView that solves that too...)
The code is pretty simple - store a GUID into ControlState, and a copy in Session. On load, compare the 2. If they're not the same - then it's a refresh. Rinse, repeat, and create a new GUID and start over.
''' <summary>
''' A validator control that detects if the page has been refreshed
''' </summary>
''' <remarks>If <see cref="SessionState.HttpSessionState" /> is not available or is reset, validator will return Valid</remarks>
Public Class RefreshValidator
Inherits BaseValidator
Private isRefreshed As Boolean
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
Page.RegisterRequiresControlState(Me)
End Sub
Protected Overrides Function SaveControlState() As Object
Dim obj As Object = MyBase.SaveControlState()
Return New System.Web.UI.Pair(_pageHashValue, obj)
End Function
Protected Overrides Sub LoadControlState(ByVal savedState As Object)
Dim pair As System.Web.UI.Pair = TryCast(savedState, System.Web.UI.Pair)
If pair IsNot Nothing Then
_pageHashValue = TryCast(pair.First, String)
MyBase.LoadControlState(pair.Second)
Else
MyBase.LoadControlState(savedState)
End If
End Sub
Private _pageHashValue As String
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
If HttpContext.Current Is Nothing OrElse HttpContext.Current.Session Is Nothing Then
isRefreshed = False
Return
End If
' Get hash value from session
Dim currHashValue As String = CType(HttpContext.Current.Session(Me.UniqueID & ":pageHashValue"), String)
If _pageHashValue Is Nothing OrElse currHashValue Is Nothing Then
' No page hash value - must be first render
' No current hash value. Session reset?
isRefreshed = False
ElseIf currHashValue = _pageHashValue Then
' Everything OK
isRefreshed = False
Else
' Was refreshed
isRefreshed = True
End If
' Build new values for form hash
Dim newHashValue As String = Guid.NewGuid().ToString()
_pageHashValue = newHashValue
HttpContext.Current.Session(Me.UniqueID & ":pageHashValue") = newHashValue
End Sub
Protected Overrides Function ControlPropertiesValid() As Boolean
Return True
End Function
Protected Overrides Function EvaluateIsValid() As Boolean
If isRefreshed Then OnRefreshed(EventArgs.Empty)
Return Not isRefreshed
End Function
Protected Overridable Sub OnRefreshed(ByVal e As EventArgs)
RaiseEvent Refreshed(Me, e)
End Sub
''' <summary>
''' Fires when page is detected as a refresh
''' </summary>
Public Event Refreshed As EventHandler
End Class

Resources