Infragistics UltraDropDown not displaying - vb.net

I have an infragistics grid control that features two columns: one of strings showing the names of certain settings and the other with a drop-down menu containing the values available for the name it's associated with. All the values are the same. I added the drop-down in the designer after instantiating it and adding it to the control like so:
Me.settingLevelDrpDown.DataSource = MyDict.ToList()
Me.settingLevelDrpDown.ValueMember = "Key"
Me.settingLevelDrpDown.DisplayMember = "Value"
In this case, MyDict is a Dictionary(Of MyEnum, String) where MyEnum is just an enum. The code that displays these is:
settingLevelDrpDown.Visible = True
settingLevels.DisplayLayout.Bands(0).Columns(1).ValueList = settingLevelDrpDown
I'm having two issues so far:
The first is that, when I display a drop-down, I get a table with one row for Key and a list of the enum keys and a row for Value with a list of the strings I actually want to display. How can I ensure that the enum-keys are bound to the drop-down selection while ensuring that the string values are displayed?
The second is performance. I've read section three of this and, as far as I can tell, I've not stumbled on any of the points listed, yet load times are really slow and the application lags super-hard even after the forms load.
Any help with these two problems would be greatly appreciated.

I would work to avoid the UltraDropDown in your code.
I would just use the ValueList property of the column.
Suppose that your MyDict is an instance of this class
Dim myDict As Dictionary(Of Int32, String) = New Dictionary(Of Int32, String)
I would transform it in a ValueList with a method like this
Public Function ToValueList(settings As Dictionary(Of Int32, String)) As ValueList
Dim result As ValueList = New ValueList()
For Each kvp As KeyValuePair(Of Int32, String) In settings
result.ValueListItems.Add(kvp.Key, kvp.Value)
Next
Return result
End Function
Now in your InitializeLayout event of your grid you could write
Dim b as UltraGridBand = settingLevels.DisplayLayout.Bands(0)
' Just to avoid the user typing something not expected
' Default is an editable DropDown
b.Columns(1).Style = ColumnStyle.DropDownList
b.Columns(1).ValueList = ToValueList(MyDict)

Related

Return values from Dictionary key

I'm a bit of a vb.net noob - apologies if this is a silly question.
I have a collection named Applications and these store objects of type application.
Dim Applications As New Dictionary(Of String, Application)()
Each application is created and added to this collection using
Public Sub New(dbid As String, name As String, status As String, mode As String)
csv_dbid = dbid
csv_app = name
csv_status = status
csv_mode = mode
End Sub
See the image i've included which shows in the debug/output my collection created with the objects and values associated.
I want to know a way I can access a Key and return all the corresponding values of csv_dbid, csv_app, csv_status and csv_mode. I've been googling for a bit and struggling.
Many thanks in advance.
Gary Waddell
In the case of the posted screenshot you would do:
Dim app = Applications("100")
app Will be a HealthCareApplication like any other so you can just use it as you would:
app.csv_dbid = "123"
You can also just refer to the dictionary item without a variable:
Applications("100").csv_dbid = "123"
To find out if the dictionary knows of a key, use the ContainsKey method. This can be particularly useful if you're iterating a colection and want to handle duplicates:
For Each thing in someList
if Applications.ContainsKey(thing.Key) Then
HandleDuplicate(thing)
Else
Applications(thing.Key) = New HealthCareApplication
End if
'It certainly exists in the collection now and this won't crash with KeyNotFound
Applications(thing.Key).csv_dbid = thing.DbId
Next thing
If you enumerate a dictionary you get a collection of KeyValuePair, the Key is (in this case) the "100" you used as the indexer. The Value is a HealthCareApplication type
For Each kvp in Applications
console.Write(kvp.Key)
Console.Write(kvp.Value.csv_dbid)
Next kvp

Get data from a collection

I want to make a collection to have data available
Example:
Dim b As New Collection
colb = New Collection
b.Add("system", "1001", "SYSTEM")
b.Add("network", "1002", "NETWORKA")
b.Add("networksecond", "1010", "NETWORKB")
colb.Add(b, "list")
im looking for a function to get data from this collection:
I want to, based on the ID (Second number) get the first and third value
So if I search for 1010, I need to have the value Network and NETWORKA
VB6 called, they want their Collection back.
No, seriously, please consider using a Dictionary instead of the old, legacy Collection class. Behold the beauty of generics and strong typing:
Dim dic As New Dictionary(Of Integer, Tuple(Of String, String))
dic.Add(1001, Tuple.Create("system", "SYSTEM"))
dic.Add(1002, Tuple.Create("network", "NETWORKA"))
dic.Add(1010, Tuple.Create("networksecond", "NETWORKB"))
' Search
Dim t As Tuple(Of String, String) = Nothing
If dic.TryGetValue(1002, t) Then
Console.WriteLine(t.Item1) ' prints "network"
Console.WriteLine(t.Item2) ' prints "NETWORKA"
End If
As soon as you have more than two values, I suggest that you use a specialized class instead of a Tuple to increase readability.
Also, you can simply use List(Of T). In most cases this is enough. Dictionary is good for fast search out long list by a single key.
'declare model
Public Class NetworkModel
Public Property Id As Integer
Public Property Name1 As String
Public Property Name2 As String
End Class
' load list of models
Private _modelList As New List(Of NetworkModel)()
.......
' search using LINQ
Dim model As NetworkModel = _modelList.FirstOrDefault(Function(m) m.Id = 1001)
If model IsNot Nothing Then . . . . .

Combo Box items - Display Member for List(Of String)?

My project is in Visual Basic. I am trying to create a custom & savable "filter" for a DataGridView using several TextBoxes. Right now, any List(Of String) that is added to the Combo Box is displayed in the box as (Collection). I want my users to be able to select the one they created, so I would like the Lists to have a display name that can be selected in the Combo Box. Here is some of the code.
Dim savedFilter As New List(Of String)
savedFilter.Add(NameTextBox.Text)
savedFilter.Add(AgeTextBox.Text)
savedFilter.Add(NotesTextBox.Text)
ComboBoxSavedFilters.Items.Add(savedFilter)
Is it possible to add a display name for a List?
Or if you are lazy use buid-in generic class Tuple From MSDN.
Create collection of Tuple(Of String, List(Of String)) and use approach suggested by #Plutonix for binding collection to ComboBox
Dim savedFilter As New List(Of Tuple(Of String, List(Of String)))()
savedFilter.Add(
Tuple.Create("default",
New List From {"filter1", "filter2", "filter3"}))
savedFilter.Add(
Tuple.Create("Blue ones",
New List From {"filter4", "filter5"}))
savedFilter.Add(
Tuple.Create("Old ones",
New List From {NameTextBox.Text, AgeTextBox.Text, NotesTextBox.Text}))
With ComboBoxSavedFilters
.DisplayMember = "Item1" 'Name of first property in Tuple type
.ValueMember = "Item2" 'Name of second property in Tuple type -List
.DataSource = savedFilter
End With
Then SelectedValue will contain currently selected filter's collection,
which can be accessed like that
Dim filter As List(Of String) =
DirectCast(Me.ComboBoxSavedFilters.SelectedValue, List(Of String))
You could setup under My.Settings a StriingCollection
Initializing (you can omit the items added if so desired)
If My.Settings.Filters Is Nothing Then
My.Settings.Filters = New StringCollection() From {"One", "Two"}
End If
Setup items in a ComboBox
ComboBox1.Items.AddRange(My.Settings.Filters.Cast(Of String).ToArray)
Adding an item
My.Settings.Filters.Add(Now.ToShortDateString)
You can remove and clear items too.
Provide a Display Member for List(Of String)
Apparently, these are less a collection of filters than a collection of criteria or clauses for one Filter:
I condensed the code in the question, but there are 14 fields that can be filtered and there are multiple filters that can be applied on one field.
For the multiples per field, I am not sure I would want to store those individually, but keep the field criteria together. So, if you want to apply a name to these, a class would not only do that but could help manage the filter elements:
Public Class SuperFilter
Public Property Name As String
Public Property Elements As SortedList
Public ReadOnly Property FilterText As String
Get
Return GetFilterText()
End Get
End Property
Public Sub New(n As String)
Name = n
Elements = New SortedList
End Sub
Public Sub AddItem(filter As String)
Elements.Add(Elements.Count, filter)
End Sub
Public Sub InsetAt(index As Int32, filter As String)
Elements.Add(index, filter)
End Sub
Private Function GetFilterText() As String
Dim els(Elements.Count - 1) As String
Elements.Values.CopyTo(els, 0)
Return String.Join(" ", els)
End Function
Public Overrides Function ToString() As String
Return String.Format("{0} ({1})", Name, Elements.Count.ToString)
End Function
End Class
You would need to add methods and properties like Remove and Count but this should be enough to demonstrate. I am not sure about the SortedList, a Dictionary using the field name might be better, but something to control the order seems worthwhile. I am also unsure I would expose the Elements collection - managing it might be better left to the class.
Hopefully, the Combo displaying a set of these (as opposed to the filter elements/clauses) is the goal.
Private filters As New List(Of SuperFilter)
Add filter items to the list:
Dim item As New SuperFilter("Default")
item.AddItem("Id = 7")
filters.Add(item)
item = New SuperFilter("Blue Ones")
item.AddItem("Color = Blue")
filters.Add(item)
item = New SuperFilter("Complex")
item.AddItem("[Name] like %Bob% OR [Name] like %Alice%")
item.AddItem("AND Color = 'Blue'")
item.AddItem("AND Active=True")
item.AddItem("AND AccessRequired < 3")
item.AddItem("AND DateAdded > #2/11/2010#")
item.AddItem("AND CreatedBy = 'ziggy'")
filters.Add(item)
cbo1.DataSource = filters
cbo1.DisplayMember = "Name"
cbo1.ValueMember = "FilterText"
The value member could be the Elements - the collection of filter clauses, or it could be the query text. The GetFilterText method joins them together for you as part of what a filter manager class could/should:
For n As Int32 = 0 To filters.Count - 1
Console.WriteLine("Name: {0} Count: {1}{2}Text:{3}", filters(n).Name,
filters(n).Elements.Count,
Environment.NewLine, filters(n).FilterText)
Next
Result:
Name: Default Count: 1
Text:Id = 7
Name: Blue Ones Count: 1
Text:Color = Blue
Name: Complex Count: 6
Text:[Name] like %Bob% OR [Name] like %Alice% AND Color = 'Blue' AND Active=True AND AccessRequired < 3 AND DateAdded > #2/11/2010# AND CreatedBy = 'ziggy'
If you use "Elements" as the ValueMember you will get back the collection.
The combo displays the Name for the user. On the right, a label displays the ValueMember in this case, it is the FilterText or joined Elements. As I said, you could get back the actual collection as the SelectedValue instead, but that is available as part of SelectedItem.
If savable means beyond the life of the application instance, that is another question, but these are very easily serialized.

Passing Enums as parameters - as a dictionary(of string, enum) (VB 2012)

This might be impossible or a bit wrong headed, however in WinForms I've got combo boxes that need populating with specific options. The project uses about 10 different forms, all with similar but slightly different functionality: hence why I didn't use just one form and hide/show controls as appropriate.
Now I made a simple dictionary of options and fed the values with an Enum. Now I realise I've got duplicate code and would like to consolidate it. The option sets are date order and name order, but I've got one or two more to list.
This is what I've tried but cannot pass the dictionary into:
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As Dictionary(Of String, [Enum]))
nameorder.Items.Clear()
For Each item In Options
nameorder.Items.Add(item)
Next
nameorder.DisplayMember = "Key"
nameorder.ValueMember = "Value"
End Sub
Property NameOrderOptions As New Dictionary(Of String, PersonList.orderOption) From {{"First Name", PersonList.orderOption.FirstName},
{"Last Name", PersonList.orderOption.LastName},
{"Room Number", PersonList.orderOption.RoomNumber}}
Property DateOrderOptions As New Dictionary(Of String, OrderDate) From {{"Newest First", OrderDate.NewestFirst}, {"Oldest First", OrderDate.OldestFirst}}
I've tried a few variations with Type and [enum].getnames etc but I can't pass the differing dictionary types in at all - I think I've overcomplicated the whole business by now but feel I'm missing an elegant solution. Shortly I'll either convert back to string matching alone, or just have functions per box type - evil duplication but I can move on.
Am I right in thinking there is a nicer way to do this? Unless I just define some kind of global resource for the options maybe-but globals are bad right?
Edit: Fixed thanks to Steven. In case anyone finds it useful OR better yet, anyone can critique and make nicer, here's the module code that all the forms can use to generate their options.
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As IDictionary)
nameorder.Items.Clear()
For Each item In Options
nameorder.Items.Add(item)
Next
nameorder.DisplayMember = "Key"
nameorder.ValueMember = "Value"
End Sub
Property NameOrderOptions As New Dictionary(Of String, orderOption) From {{"First Name", orderOption.FirstName},
{"Last Name", orderOption.LastName},
{"Room Number", orderOption.RoomNumber}}
Property DateOrderOptions As New Dictionary(Of String, OrderDate) From {{"Newest First", OrderDate.NewestFirst}, {"Oldest First", OrderDate.OldestFirst}}
Property personStatusOptions As New Dictionary(Of String, personStatus) From {{"Active", personStatus.Active},
{"InActive", personStatus.InActive},
{"All", personStatus.All}}
Public Sub BuildComboBoxes(ListBoxes As Dictionary(Of ComboBox, IDictionary))
For Each pair In ListBoxes
BuildOrderOptions(pair.Key, pair.Value)
Next
End Sub
Public Enum OrderDate
OldestFirst
NewestFirst
End Enum
Public Enum personStatus
Active
InActive
All
End Enum
Public Enum orderOption
None
FirstName
LastName
RoomNumber
End Enum
And here's the way I've got one form using it - yes, I could have had a bunch of parameters or multiple function calls: I just like having a single object giving me a single parameter to pass on.
BuildComboBoxes( New Dictionary ( Of ComboBox , IDictionary ) From {{NameOrder, NameOrderOptions},
{DateOrder, DateOrderOptions},
{personStatus, PersonStatusOptions}})
You just need to change your method to accept any IDictionary object rather than a specific type of dictionary:
Public Sub BuildOrderOptions(nameorder As ComboBox, Options As IDictionary)
When you are using generics, such as Dictionary(Of TKey, TValue), the generic type is not really a type at all. You can think of it like a template for any number of specific types. So each time you use a generic type using different type parameters, they are entirely different and incompatible types. For instance:
' This works fine because both d1 and d2 are exactly the same type
Dim d1 As New Dictionary(Of String, String)()
Dim d2 As Dictionary(Of String, String) = d1
' This will not compile because d1 and d2 are completely different types
Dim d1 As New Dictionary(Of String, Integer)()
Dim d2 As Dictionary(Of String, Boolean) = d1
As you have found out, even if you try to use a base class as the generic type parameter, the two are still incompatible. So, even though Stream is the base class for MemoryStream, you still cannot do this:
' This will not compile because d1 and d2 are completely different types
Dim d1 As New Dictionary(Of String, MemoryStream)()
Dim d2 As Dictionary(Of String, Stream) = d1

IndexOf a ComboBox just will not work for me

VB2010. I am trying to populate a ComboBox with the contents of an Enumeration of units. I have managed to do this with a Dictionary. Something like
Dim dUnits As New Dictionary(Of String, Integer)
Dim da As String
For Each enumValue As eUnits In System.Enum.GetValues(GetType(eUnits))
da = ConvertEnumToCommonName 'gets unique name for an enumeration
dUnits.Add(da, enumValue)
Next
cbo.DisplayMember = "Key" 'display the the common name
cbo.ValueMember = "Value" 'use the enumeration as the value
cbo.DataSource = New BindingSource(dUnits, Nothing)
When I load up my form that works well. Now the user can choose to select a default unit to display. So then I try
Dim defUnits As eUnits = eUnits.Feet
Dim idx As Integer = cbo.Items.IndexOf(defUnits) 'doesnt work, returns a -1
cbo.SelectedIndex = idx
I have been doing some research for some time and am fairly sure that this has to do with the ComboBox storing Values as a string and in reality I'm searching for an enumeration which is an integer. Don't know if I have that right or not. Anyway, I just cant seem to get the default item selected. Is there another approach I can try?
First of all you have a collection of integers and you're searching for the enum value. For that, try one of the following:
Store the enum value in the dictionary instead of a string:
Dim dUnits As New Dictionary(Of String, eUnits)
Keep the integers in the Dictionary but use the integer value of the enum when searching the ComboBox:
Dim idx As Integer = cbo.Items.IndexOf(CInt(defUnits))
But this is not going to work yet. You are data-bound to a Dictionary, which means the items in cbo.Items are not of the enum type, but of the type of the elements in the Dictionary (KeyValuePair(Of String, eUnits) assuming #1 above).
The easiest solution is just to set the SelectedValue property of the combo box instead of the SelectedIndex. Assuming you used option #1 above, this would be:
cbo.SelectedValue = defUnits
If you used option #2 instead, you'll have to convert this to an integer first:
cbo.SelectedValue = CInt(defUnits)