Sorting for Ajax Combo-Box - asp.net

I am wondering if there is any other way of sorting ajax combo box apart from this following example;
Public Class ListItemComparer
Implements IComparer(Of ListItem)
Public Function Compare(ByVal x As ListItem, ByVal y As ListItem) As Integer _
Implements IComparer(Of ListItem).Compare
Dim c As New CaseInsensitiveComparer
Return c.Compare(x.Text, y.Text)
End Function
End Class
Public Shared Sub SortDropDown(ByVal cbo As AjaxControlToolkit.ComboBox)
Dim lstListItems As New List(Of ListItem)
For Each li As ListItem In cbo.Items
lstListItems.Add(li)
Next
lstListItems.Sort(New ListItemComparer)
cbo.Items.Clear()
cbo.Items.AddRange(lstListItems.ToArray)
End Sub
----------Binding and Sorting Combo-Box----------
ddlClients.DataTextField = "ClientName"
ddlClients.DataValueField = "ClientID"
ddlClients.DataBind()
SortDropDown(ddlClients)
In the SP, i am using order by clause on Client Name but somehow combox doesn't bind ClientNames in order.
I like to to place this function in CommonFunction Class so i can call it from different places within the project. I am not able to add the above function in the BusinessLayer becuase of 'AjaxControlToolkit.ComboBox'

Related

VB.NET Asynchronous Task keeping HttpContext

I'm using .NET Framework 4.0.
I have a function that creates and calls a Task. In some part of its process I need a value stored in the Session, but it returns Nothing because the Task doesn't have the HttpContext.
Here's an example:
Public Class Example
Inherits System.Web.Mvc.Controller
<AcceptVerbs("GET", "POST")>
Public Sub DoSomething()
Dim products As List(Of Product)
Dim something As New Task(Sub()
For Each product In products
product.Name = product.Name.ToUpper
product.Save()
Next
End Sub)
something.Start()
End Sub
End Class
Public Class Product
Public Sub OnProductSave()
Dim session = Web.HttpContext.Current.Session
Dim log As New Log()
log.UserId = session("UserId")
log.Date = DateTime.Now()
log.Save()
End Function
End Class
There is a way that I could use the HttpContext in the Task?
Obs.: In the example I could pass the value of UserId to the function, but in the real case it's more complex than that.
Obs.2: I know that I could create a variable with the value of HttpContext and after set it to the Task's HttpContext, but I think there could be a better way. :)

Property binding to web controls in asp.net with linq and reflection

I'd like to "bind" properties from a DTO to corresponding controls, for example checkboxlists or textboxes. This is so that I can use a dto (passed through the querystring) to set the initial state of the control, and then have the control set it's value to the dto when it comes time to leave the page. I could do this with two mapping functions (control->DTO, DTO->Control) but instead I'm using Linq and Reflection to maintain a list of property<->control relationships.
I've never done this before and I suspect there may be a better way ... how would you maintain a property<->control relationship?
Here is the code I've used:
Public Class ObjectPropertyMapper
''' <summary>Provides a binding of a control to one or more properties in a DTO.</summary>
Private Class ControlBinding
''' <summary>A reference to the control which will be bound.</summary>
Public Property Control As Control
''' <summary>The property(ies) which the control will be bound to.</summary>
Public Property Props As New List(Of PropertyInfo)
Public Sub New(ctrl As Control, props As IEnumerable(Of PropertyInfo))
Me.Control = ctrl
Me.Props.AddRange(props)
End Sub
End Class
''' <summary>A list of all the control to dto bindings for this page.</summary>
Private Property ControlBindings As New List(Of ControlBinding)
''' <summary>Returns the property info from a linq expression.</summary>
Private Function GetPropertyFromExpression(Of T)(linqExpression As System.Linq.Expressions.Expression(Of Func(Of T))) As PropertyInfo
If TypeOf linqExpression.Body Is MemberExpression Then
Return DirectCast(linqExpression.Body, MemberExpression).Member
Else
Dim op = (CType(linqExpression.Body, UnaryExpression).Operand)
Return DirectCast(op, MemberExpression).Member
End If
End Function
''' <summary>Binds a control to a single property of the DTO.
''' Usage: BindControlToProperty(cblFundTypes, Function() Me.SearchParams.FundTypeIDs) ... </summary>
Protected Overloads Sub BindControlToProperty(Of T)(ctrl As Control, linqExpression As System.Linq.Expressions.Expression(Of Func(Of T)))
' This works by passing through a linq expression, which in turn has a reference to the property.
' We can therefore extract the property from the linq expression, allowing us to store a reference to the property against the reference to the control
Dim prop As PropertyInfo = GetPropertyFromExpression(linqExpression)
ControlBindings.Add(New ControlBinding(ctrl, {prop}))
End Sub
End Class
And the consumer:
Public Class MyPage
Public Sub OnLoad
BindControlToProperty(myCheckBoxList, Function() MyDTO.IntListProperty)
End Sub
End Class
The only alternate method I found was projecting properties onto an anonymous type, as per https://stackoverflow.com/a/1984190/767599
An example would be:
Public Class exampleDTO
Public Property MyProp1 As String
Public Property MyProp2 As String
End Class
Public Function GetVariableName(Of T)(obj As t) As String
Dim properties As System.Reflection.PropertyInfo() = obj.GetType.GetProperties
If properties.Length = 1 Then
Return properties(0).Name
Else : Throw New Exception
End If
End Function
Public Sub BindToControl(Of T)(ctrl As Control, prop As T)
Response.Write(GetVariableName(prop))
End Sub
Public Sub Main
Dim c As New Control
Dim dto As New exampleDTO
BindToControl(c, (New With {dto.MyProp1}))
End Sub
However I have no idea which solution is "better".

Assigning value to item within an arraylist by index

I have this VB.NET ArrayList object which is working quite well. I have built it like this. It's the first one I have used.
Public Class MyObj
Private _str1 As String
Private _str2 As String
Public Property Str1() As String
Get
Return _str1
End Get
Set(ByVal value As String)
_str1 = value
End Set
End Property
Public Property Str2() As String
Get
Return _str2
End Get
Set(ByVal value As String)
_str2 = value
End Set
End Property
Public Sub New(ByRef pStr1 As String)
_str1 = pStr1
End Sub
End Class
Then I initiialise it doing this...
Dim MyObj1 As ArrayList = New ArrayList()
MyObj1.Add(New MyObj("myTestString"))
So this is all working later on. So I pack up the arraylist and store it in a class level variable. Then in a different method I grab my arraylist. I then want to assign a value to _str2. Does anyone have advice on how I would go about this. I keep trying to know avail. This is the sort of thing I mean.
For i = 0 To MyObj1.Items.Count - 1
MyObj1.Item(i)("Str2") = "tesstring2"
Next
As Tim wrote, you will be better off using a List instead of the old ArrayList.
To set it up and then access the property Str2 of the instances of MyObj:
Dim myList As New List(Of MyObj)
myList.Add(New MyObj("Hello"))
For i = 0 To myList.Count - 1
myList(i).Str2 = "World"
Next
Notice how it is .Str2, not ("Str2").

Problems implementing a recursive find extension method

I am attempting to implement a recursive extension method in VB.net that will find all objects with a certain property set so I can call it like so...
Dim camp As New CampaignStructure 'Populated with a full structure of course
Dim lstFoundItems As List(Of CategoryStructure) = camp.Categories.FindRecursive((Function(c) c.Found = False), 3)
My VB.Net classess and modules currently look like this
Imports System.Runtime.CompilerServices
Namespace MyStructure
Public Class CategoryStructure
Public Property CategoryID As Integer = Nothing
Public Property Name As String
Public Property Rank As Integer
Public Property Found As Boolean = False
Public Property Children As New List(Of CategoryStructure)
End Class
Public Class CampaignStructure
Public Property CampaignID As String = Nothing
Public Property Categories As List(Of CategoryStructure)
End Class
Public Module ControlExtensions
<Extension()> _
Public Function FindRecursive(cs As List(Of CategoryStructure), predicate As Func(Of CategoryStructure, Boolean), depthLimit As Integer) As List(Of CategoryStructure)
If cs Is Nothing OrElse cs.Count = 0 Then
Return New List(Of CategoryStructure)()
End If
If depthLimit = 0 Then
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
Else
'**ERROR IS THROWN HERE**
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList().Union(cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList())
End If
End Function
End Module
End Namespace
However I'm having casting problems when I'm unioning the recursive result with the current list at the point in the code marked. I can see why that's happening, just have no idea how to resolve it. Please do not send me C# examples as there is no 'yield' alternative in VB.net
That's because both sides of UNION have different signatures.
cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
This returns List(Of CategoryStructure).
cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList()
This one returns List(Of List(Of CategoryStructure))
I think what you're looking for is:
Return cs.OfType(Of CategoryStructure)().Where(predicate).Union(cs.Cast(Of CategoryStructure).SelectMany(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1))).ToList()
SelectMany returns flattened collection typed as IEnumerable(Of CategoryStructure).

Do I Need a Class if I only need 1 Property (at the moment)?

Update: I didn't make it clear but I meant this to be a question about where/how I would use a function to return a list of strings when I'm trying to just work with classes.
I have a class called Account.
I have data access class called AccountDAO.
I have various functions that return lists of objects like GetAllAccounts, GetAccountByID etc.
I want to populate a drop down list with just the account names and nothing else. It's proving rather slow when using lists of objects and databinding them to the dropdownlist.
I feel like I should be using a simple "Select Account_Name From blah" type statement and returning a list of strings but I don't know how to work this into my class and data access class.
How should I handle this predicament?
You can use a list of string,s and bind the list of strings to a dropdownlist no problem... the DDL can support that, just leave out DataTextField and DataValueField props, and it will display the account name as is, which that name would be accessible through the ListItem's Text and Value property.
I like to use objects to be consistent with the rest of the app (which other areas might need a class), and if for some reason you want to add AccountKey later, if you use an object, all you need to do is add a property. Otherwise, if using strings, you'd have to switch up the binding later to point to the object.
HTH.
There is nothing wrong by making a function that only returns a list of strings. YOu could however wonder if it's not better to restrict the number of records you want to put in the list and use some kind of paging.
Assuming that you're using a List<>, you can try something like this:
IEnumerable<string> nameList = accountList.Select(t => t.AccountName);
Or if you need a List:
List<string> nameList = accountList.Select(t => t.AccountName).ToList();
Go with your feelings. Use a datareader to select the list and then load them into an arraylist which can then be bound to the dropdown. Alternately, use something like this method I use to provide both a DisplayMember and a ValueMember which uses a class (with both values) as members of the arraylist. This should give you the general idea. (Note: I normally include this code in a data access class (MyBase) where StartReader, _datRdr, ReadNext and_ReaderValid are a members. But the general idea is intact.)
Public Sub LoadDataSource(ByRef PlantDataSource As PlantSource, Optional ByVal Filter As String = "", Optional ByVal IncludeBlankItem As Boolean = False)
PlantDataSource = New PlantSource
If IncludeBlankItem Then
PlantDataSource.Add(0, "")
End If
If Filter = String.Empty Then
Call StartReader(" Order by PlantName")
Else
Call StartReader(String.Concat(" Where ", Filter, " Order by PlantName"))
End If
If _DatRdr.HasRows Then
While MyBase._ReaderValid
PlantDataSource.Add(PlantId, PlantName)
ReadNext()
End While
End If
Call CloseReader()
End Sub
Private Class PlantListing
Private _PlantList As New ArrayList
Public Sub Add(ByVal PlantId As Integer, ByVal PlantName As String)
_PlantList.Add(New PlantDataItem(PlantId, PlantName))
End Sub
Public ReadOnly Property List() As ArrayList
Get
Return _PlantList
End Get
End Property
End Class
Private Class PlantDataItem
Private _PlantId As Integer
Private _PlantName As String
Public Sub New(ByVal pPlantId As Integer, ByVal pPlantName As String)
Me._PlantId = pPlantId
Me._PlantName = pPlantName
End Sub
Public ReadOnly Property PlantName() As String
Get
Return _PlantName
End Get
End Property
Public ReadOnly Property PlantId() As Integer
Get
Return _PlantId
End Get
End Property
Public ReadOnly Property DisplayValue() As String
Get
Return CStr(Me._PlantId).Trim & " - " & _PlantName.Trim
End Get
End Property
Public Overrides Function ToString() As String
Return CStr(Me._PlantId).Trim & " - " & _PlantName.Trim
End Function
End Class

Resources