for each MenuItem RemoveAt - asp.net

I developed a basic system in that loops through the menuitems in a menu collection on page load (items are hardcoded, so can't use rowdatabound event) and disables those that don't meet a certain user level criteria:
For Each item As MenuItem In NavigationMenu.Items
Dim value As Int32 = Convert.ToInt32(item.Value)
Dim level As Int32 = Convert.ToInt32(Session.Item("uxID"))
If value > level Then item.Enabled = False
Next
It works great and disables all of the menuitems that it should and ignores the rest. The catch is that as time has gone by the amount of menuitems has increased, and its difficult for some users to know what they do and don't have access to.
My understanding is that menuitems don't have a visible property, but can be removed (http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.menuitemcollection.removeat.aspx) but I'm stumped on how to get the index of the menuitem in order to do so.

Just do the same:
Dim i As Integer = 0
While i < NavigationMenu.Items.Count
Dim value As Int32 = Convert.ToInt32(NavigationMenu.Items(i).Value)
Dim level As Int32 = Convert.ToInt32(Session.Item("uxID"))
If value > level Then : NavigationMenu.Items.RemoveAt(i)
Else : i += 1
End If
End While
Keep in mind that you can not do a foreach and remove items inside, because you will get an Exception about modifying the array which is looping.

Related

Trouble reading Attributes from control adapter

I am trying to integrate an adapter to get support for the OptGroup tag in .net. i took the same adapter as i usually did (been a while, but no build errors or warnings). I set attributes when i add items into the DropDownList, and attempt to read them in the adapter and they seem to be set to Nothing. I entered breakpoints at points of interest and after being set, i can see the Attributes having a value. And in the adapter, the item remains but without said attribute.
To get every possible glitch out of the way i went into full hardcode for adding items, and here we have the result. The display does not group up, as the !=nothing never is met on the adapter.
declaration of list:
Dim item1 As New ListItem("potatoes", "1")
item1.Attributes("OptionGroup") = "optionGroup1"
Dim item2 As New ListItem("Onions", "2")
item2.Attributes("OptionGroup") = "optionGroup2" 'here the optiongroup is set, and debugger sees value to it.
Me.cboMaterial.Items.Add(item1)
Me.cboMaterial.Items.Add(item2)
where it fails in the adapter:
Dim list As DropDownList = Me.Control
Dim currentOptionGroup As String = ""
Dim renderedOptionGroups As New Collection
For Each item As ListItem In list.Items
If item.Attributes("OptionGroup") = "" Then 'here, the item is worth something (potatoes) but the OptionGroup is nothing.
RenderListItem(item, writer)
Else
If currentOptionGroup <> item.Attributes("OptionGroup") Then
If currentOptionGroup <> "" Then
RenderOptionGroupEndTag(writer)
End If
currentOptionGroup = item.Attributes("OptionGroup")
RenderOptionGroupBeginTag(currentOptionGroup, writer)
End If
RenderListItem(item, writer)
End If
Next
i must be missing something, perhaps trivial, but I've been looking at the same thing for too long. any help would be welcome.
edit: i have tried adding the attribute with secondary syntax... by desperation i guess.
item2.Attributes.Add("OptionGroup","optionGroup2")
it changes nothing :P

Type-casting entity framework results in ItemDataBound

So I've trying to optimize performance of a page which generates the navigation menu for a website. Basically there is a table called T_product_cat which contains 4 fields I care about:
product_cat_name (the product category name)
product_cat_uid (the unique identifier of the row)
product_cat_thumbnail_path (the image that represents the category)
product_cat_parent_uid (the unique identifier of the product category
that we sit underneath - since these "product folders" can nest)
I need to create a top navigation bar which has just the names of the top level product categories and then for the dropdown navigation I need to output the sub product categories along with their images and links etc. I've got a basic ASP:Repeater control with a nested ASP:Repeater to handle the sub-product categories
Basically though I want to start using EF to start querying for my data. Initially I did a query to just pull the top level items and then in the ItemDataBound event of the repeater, I'd access the data and query the database again for the sub categories. But this was hitting the database 8x (since I've got 7 top level categories). To speed things up I've been trying different iterations of an initial query. Here's my final one for reference:
Using db As New RmpEntities
' query all the items and then all their subitems at the same time so that we don't have to repeatedly hit the database
Dim qry = (
From
productCat In db.T_product_cat
Where
productCat.company_uid = WmsSession.company_uid AndAlso
productCat.enabled = 1 AndAlso
productCat.product_cat_parent_uid = GUIDs.GlobalGuids.RootCategoryUid AndAlso
productCat.product_cat_hide <> 1
Order By
productCat.product_cat_sequence
Select
categoryName = productCat.product_cat_name,
categoryUid = productCat.product_cat_uid,
imagePath = productCat.product_cat_thumbnail_path,
subCategories = (
From
productSubCat In db.T_product_cat
Where
productSubCat.company_uid = WmsSession.company_uid AndAlso
productSubCat.enabled = 1 AndAlso
productSubCat.product_cat_parent_uid = productCat.product_cat_uid AndAlso
productSubCat.product_cat_hide <> 1
Order By
productSubCat.product_cat_sequence
Select
categoryName = productSubCat.product_cat_name,
categoryUid = productSubCat.product_cat_uid,
imagePath = productSubCat.product_cat_thumbnail_path
)
)
rptMainNav.DataSource = qry.ToList()
rptMainNav.DataBind()
End Using
When the repeater's ItemDataBound event fires I do have working code to pick apart the results and bind the data to the sub-repeater (this code works):
Protected Class CategoryInfo
Public Property categoryName As String
Public Property categoryUid As Guid
Public Property imagePath As String
End Class
Private Sub rptMainNav_ItemDataBound(sender As Object, e As RepeaterItemEventArgs) Handles rptMainNav.ItemDataBound
Dim rItem As RepeaterItem = e.Item
Select Case rItem.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem
Dim dataItem = rItem.DataItem
Dim subRepeater As Repeater = rItem.FindControl("rptSubNav")
Dim parentUid As Guid = dataItem.categoryUid
Dim st = DateTime.Now
Dim x As New List(Of CategoryInfo)
For Each item In dataItem.subCategories
x.Add(New CategoryInfo With {.categoryName = item.categoryName, .categoryUid = item.categoryUid, .imagePath = item.imagePath})
Next
subRepeater.DataSource = x
dTime.Add(New MyTimes With {.g = parentUid, .ts = DateTime.Now - st})
subRepeater.DataBind()
End Select
End Sub
But how can I cast the Object type returned by accessing the repeater's DataItem to a more strongly-typed object so I can get intellisense?
Or is there some way I can give up on the worries about typing and just use the query results directly as a DataSource for the sub-repeater? That was my first goal but when I tried to take
dataItem.subCategories.ToList()
It failed with:
Public member 'ToList' on type 'CompensatingCollection(Of VB$AnonymousType_1(Of String,Guid,String))' not found.
When I tried to modify my CategoryInfo class to have another property to hold a list of CategoryInfo classes (subcategories) and have the main query return structured data (so I'd have a type to cast to in the ItemDataBound) things failed even worse. The original query's .ToList failed so I couldn't even do the initial bind.
What is the correct way to handle this? Continue working on properties of an Object which represents an anonymous type? Surely there must be something better.
EDIT:
Robert - Thanks for your suggestions. It turned out that I did NOT have a navigation property to SubCategories. The reason being that the people who came before me designed the database such that all top level categories end up with an artificial product_cat_parent_uid (just some random GUID). It doesn't point to a real product category in the database - it just acts as a placeholder. I question why they didn't just use NULL but it's too late to change it. At any rate since the item doesn't exist in the database, the database itself doesn't have the foreign key since it's faking the link. The databse won't create the link with product categories pointing to a product categorie that is not in the database. I did use your suggestion to find more information about what could be done and I used this article (Entity Framework - Add Navigation Property Manually) to add those links I need.
The question still remains though - can I get strong typing within the ItemDataBind event?

add dataitem(from string array) to listview

To preface this, I've looked through several of the postings containing listviews and nothing really is comparing to what I'm trying to do.
I'm trying to take values determined through a loop that has several If Statements similar to what follows:
If Convert.ToInt32(GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_DAYS", DefaultValue)) > 0 Or _
Convert.ToInt32(GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_HRS", DefaultValue)) > 0 Or _
Convert.ToInt32(GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_MINS", DefaultValue)) > 0 Then
msChargeDays = GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_DAYS", DefaultValue)
msChargeHours = GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_HRS", DefaultValue)
msChargeMins = GetData(ds.Tables("HRIS").Rows(i), "ABS_CO_RULE_MINS", DefaultValue)
msHowPaid = "CR DAYS"
AbsenceLine() 'calls sub
End If
This block of code returns valid results from the dataset that it calls from. Now in the following code block, I am trying to assimilate values that are determined by the main code block which is about 40 if statements similar in structure to the block above, all contained within a For loop.
In the following code block I am trying to insert an object of ListViewItem type into the ListView. This is where I'm getting my error denoted by comment string following it. The function that fills the ListViewItem is at the bottom, all of the variables returned are all class variables and return valid values to the ListViewItem. I have double checked this via the debugger.
Private Sub AbsenceLine()
Dim sTypeReason As String
If msType = "" Then
sTypeReason = Left(msReason, 25)
Else
sTypeReason = msType & "--" & msReason
End If
Dim item As ListViewItem
item = New ListViewItem(ListViewItemType.DataItem)
item.DataItem = FillListView(sTypeReason)
absence_lv.Items.Add(item) 'this line here is what is givine me issues
End Sub
Private Function FillListView(typeReason As String) As IEnumerable(Of String)
Return {msDate, msVoid, msCont, msDays, msHours, msMinutes, typeReason, msChargeDays, msChargeHours,
msChargeMins, msHowPaid} 'all values returned are of String type
End Function
Now with the background:
Am I completely off base with what I'm trying to do?
Is there an easier way to do this with a gridview instead?
I think you're misusing the DataItem property of the ListViewItem class. That's really used to get the underlying object that the ListViewItem represents when the ListView itself is bound.
Since your FillListView function is returning an IEnumerable(Of String), you can just set the ListView's DataSource property to the function call.
absence_lv.Datasource = FillListView(sTypeReason)
absence_lv.Databind()
As you can see, there is no need to manually add each item.

array not holding value when updated

i can add a value to array(0), but when i then add a value to array(1) it clears the value for array(0). I've tried every way I can think of to declare and create the array. My code looks like this:
Dim aryEstimateInfo() As String = New String(7) {}
Private Sub wzrdEstimateWizard_NextButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles wzrdEstimateWizard.NextButtonClick
Select Case wzrdEstimateWizard.ActiveStepIndex
Case 0 'first estimate wizard step
aryEstimateInfo(0) = rad_lstVehicleType.SelectedItem.ToString
Case 1 'second estimate wizard step
Dim DamageZoneSelected As Boolean = False
For Each cntrl As Control In pnlDamageZone.Controls
If TypeOf cntrl Is RadioButton Then
Dim RadButton As RadioButton = cntrl
If RadButton.Checked Then
DamageZoneSelected = True
DamageZone = RadButton.Text.ToString
Exit For
Else
DamageZoneSelected = False
End If
End If
Next
If DamageZoneSelected = True Then
lblDamageZoneError.Visible = False
aryEstimateInfo(1) = DamageZone
Else
'if no damage zone is selected a message is displayed
wzrdEstimateWizard.ActiveStepIndex = 2
wzrdEstimateWizard.ActiveStepIndex = 1
lblDamageZoneError.Visible = True
End If
Case 2 'third estimate wizard step
'assigns the number of dents to the estimate array
aryEstimateInfo(2) = ddlNumberOfDents.SelectedValue.ToString
'sets the average dent size in the estimate arrau
aryEstimateInfo(3) = ddlDentSize.SelectedValue.ToString
'sets the add-on code and number of oversized dents
If ddlOverSized.Enabled = True Then
'aryEstimateInfo.SetValue("3", 4)
aryEstimateInfo(4) = "3"
aryEstimateInfo(7) = ddlOverSized.SelectedValue.ToString
Else
End If
Case 3 'fourth estimate wizard step
Case Else
End Select
End Sub
I'm using this in an ASP.Net wizard control and in basic, visual studio 2010.
The problem is that each button click is posting back the page, which causes your aryEstimateInfo to be re-created on each postback.
In order to handle this situation elegantly, improve the maintenance of the page, and make it easier to debug this sort of situation in the future, I recommend the following changes:
1) Change the array to a class with properties:
Public Class EstimateInfo
Public VehicleType As String = ""
Public DamageZone As String = ""
Public NumberOfDents As String = ""
Public DentSize As String = ""
Public AddOnCode As String = ""
Public Oversized As String = ""
End Class
Note that all of the properties are declared as string, but the data types should probably be changed to more accurately reflect the underlying content.
This approach will help debugging because you can change the auto-implemented property to a getter/setter so that you can place a breakpoint to see where the value is getting cleared:
Private m_sVehicleType As String = ""
Public Property VehicleType As String
Get
Return m_sVehicleType
End Get
Set (Value As String
' You could set a breakpoint here to discover where the value is getting cleared.
m_sVehicleType = Value
End Set
End Property
And if you need to have the values in a string array for export to a different application or database, for example, you could add a method to the class to produce an appropriate string array.
2) Add a property to the page to store the current answer class in the page's ViewState so that you won't have to continuously re-populate the array. For example:
Private Property EstimateInfo As EstimateInfo
Get
' Add a new record to the viewstate if it doesn't already exist
If ViewState("EstimateInfo") Is Nothing Then
Me.EstimateInfo = New EstimateInfo
End If
Return ViewState("EstimateInfo")
End Get
Set (value As EstimateInfo)
ViewState("EstimateInfo") = value
End Set
End Property
Once you do this, your wizard code becomes much easier to understand and maintain:
Select Case wzrdEstimateWizard.ActiveStepIndex
Case 0 'first estimate wizard step
Me.EstimateInfo.VehicleType = rad_lstVehicleType.SelectedItem.ToString
when you declare the new array someehere in the code you cannot reuse it again after post back.
I suggest to build the array on finish wizard event
you can use the controls in whole steps where ever step you in
I guess it will be fine
otherwise you need to store the array after every update in session or view state but I don't like both
sorry I couldn't view example becoz I'm using mobile

DevExpress how to set and get tree node text and name at run time?

I am new in dev express technology. I am having a problem with devexpress XtraTreeList because i am unable to get node "NAME" and "TEXT" property.Please any one help me out through code.
One thing you need to keep in mind is that each node can be made up of multiple values. Based on the number of columns that are displayed. So, what you actually want to access is the particular column of a node in order to access or set the values for that column in the node.
For example:
TreeListColumn columnID1 = treeList1.Columns["Budget"];
// Get a cell's value in the first root node.
object cellValue1 = treeList1.Nodes[0][columnID1];
and
string columnID2 = "Budget";
// Get the display text of the focused node's cell
string cellText = treeList1.FocusedNode.GetDisplayText(columnID2);
Check out the devExpress documentation too. It's pretty helpful.
Maybe this example can help you:
Public Sub LoadTree()
TreeList1.Columns.Add().Name = "DisplayColumn"
Dim node1 = TreeList1.Nodes.Add("Father")
node1.Tag = "Father"
Dim node1_1 = TreeList1.Nodes.Add("Child Node")
node1_1.Tag = "Child Node"
Dim node1_1_1 = node1.Nodes.Add("This is a grandchild node")
node1_1_1.Tag = "Grandchild 1"
Dim node1_1_2 = node1.Nodes.Add("Another grandchild node")
node1_1_2.Tag = "Grandchild 2"
End Sub
Public Sub DisplayNodeValue(ByVal tag As String)
Dim valueToPresent = FirstTagValueInNode(TreeList1.Nodes, tag)
MsgBox(valueToPresent.ToString)
End Sub
Public Function FirstTagValueInNode(ByVal nodes As DevExpress.XtraTreeList.Nodes.TreeListNodes, ByVal tagSearch As Object)
For Each node As DevExpress.XtraTreeList.Nodes.TreeListNode In nodes
If node.Tag = tagSearch Then
Return node.GetValue(TreeList1.Columns(0))
End If
If node.Nodes.Count > 0 Then
Return FirstTagValueInNode(node.Nodes, tagSearch)
End If
Next
Return Nothing
End Function

Resources