How to Autofill Textboxes on a Form using a Loop? - ms-access

So I have a table that has a list of totals im trying to display on a form, I have 10 totals I need to get from the totals table and display in 10 textboxes on the form.
The 10 textboxes are "A1, A2, A3..." and its using DLookup to find the ID field number.
It seems like its a syntax issue with Me.TEXTX & X1.Value though I'm not sure how else I can type it.
Hope this makes sense. Thanks!
Private Sub UPDATETOTALS()
Dim FORMX As String
FORMX = "GRID"
Dim TEXTX As String
TEXTX = "A"
Dim TABLENAMEx As String, FINDFIELDx As String, GETFIELDx As String
TABLENAMEx = "GRID_TOTALS"
FINDFIELDx = "[ID]="
GETFIELDx = "TODAY"
Dim X1 As Integer
For X1 = 1 To 10
Me.TEXTX & X1.Value = DLookup(GETFIELDx, TABLENAMEx, FINDFIELDx & X1)
Next X1
End Sub

You cannot access an object reference directly using a concatenated string, as such reference is not of string data type.
Instead, you will need to access the object from the relevant collection (in this case, the Controls collection), by supplying the name of the object (as a string) to the Item method of that collection.
Since the Item method is the default method for a collection, the item name can immediately follow the collection as an argument.
For example:
For X1 = 1 To 10
Me.Controls(TEXTX & X1).Value = DLookup(GETFIELDx, TABLENAMEx, FINDFIELDx & X1)
Next X1

Related

Access For Loop Hide Objects

I'm trying to hide/unhide around 30 objects on my form when the user selects certain values from a dropdown menu. I tried the loop below, however I receive the following error: 'Object doesn't support this property or method.' I have this code running on the 'AfterUpdate' of the dropdown menu object.
Dim VisibleVisitFields() As String
Dim VisibleVisitFieldlist As String
Dim varVisibleVisit As Variant
VisibleVisitFieldlist = "VisitDate_Event,VisitTime_Event,VisitSite_Event,VisitStaff_Event,VisitMeet_Event"
VisibleVisitFields = Split(VisibleVisitFieldlist, ",")
If (EventType = 3) Then
For Each varVisibleVisit In VisibleVisitFields
[Forms]![subFRM_TBL_Event-All in One].Controls(varVisibleVisit).visible = True
Exit For
Next
Else
If (EventType <> 3) Then
For Each varVisibleVisit In VisibleVisitFields
[Forms]![subFRM_TBL_Event-All in One].Controls(varVisibleVisit).visible = False
Exit For
Next
End If
End If
Which line triggers the error? Suspect it is reference to the subform that is flawed. Never seen code like that to loop through an array. Suggest naming subform container different from the object it holds, such as ctrEvent. What is EventType - a textbox/field on the form? Consider code:
Dim aryFields As Variant
Dim x As Integer
aryFields = Split("VisitDate_Event,VisitTime_Event,VisitSite_Event,VisitStaff_Event,VisitMeet_Event", ",")
For x = 0 To UBound(aryFields)
Me.ctrEvent.Form.Controls(aryFields(x)).Visible = Me.EventType = 3
Next
Alternative methods not using array:
Set control Tag property then code loops through all controls on form and sets visibility for those that have particular value in Tag.
Dim ctrl As Control
For Each ctrl in Me.ctrEvent.Form.Controls
If ctrl.Tag = "something" Then ctrl.Visibility = Me.EventType = 3
Next
Another is to give controls similar names, like: Visit1, Visit2, etc. Then code:
Dim x As Integer
For x = 1 to 30
Me.ctrEvent.Form.Controls("Visit" & x).Visible = Me.EventType = 3
Next
Advise no spaces or punctuation/special characters (underscore only exception) in naming convention.
You are trying to iterate over an array of strings.
Dim VisibleVisitFields() As String
You need to declare the array to contain variants (which can still contain strings)
Dim VisibleVisitFields() As Variant

Array in an Enumeration

I am wondering if it is possible to have a dynamic enumeration.
Explanation: I have a function to add errors to an error log in ms access. The categories in my Enum variable are all in a table. If I use the function and enum as depicted below, it works just fine. The problem is however, that there is a possibility that the categories will change with time.
Enum category
Category1 = 1
Category2 = 2
etc... = n
End Enum
Public Function AddError(Current_order_ID As Long, Optional Error_Category As category)
'Add the error to the log
End Function
I have noticed that using DLookups and recordsets and actually everything in general will not work. While compiling, it throws an 'Invalid inside Enum'. Consulting MSDN gives me the following information: You tried to specify a string or some other invalid type as the value of an Enum member. The constant expression used to specify an Enum member must evaluate to type Long or another Enum type.
This tells me that an enum can hold only long types, hence the numbers, but also other Enum types.
What I am looking for: Is there some workaround, or method, to loop through a recordset or query and pass the values on to an array, and dynamically assign these values to an enumeration. Or perhaps it can be done by changing the source code/vba text itself?
Note: I know that there are a lot of other ways to add my errors to a log and I am able to do so, but for know I am just wondering if this is even possible to do.
I am looking forward to your reactions.
The Recordset loops through a table containing the Enum types. Basically this is editing a modules VBA code.
Public Function CreateEnum()
Dim db As Database
Dim rs As Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("MYENUMS", dbOpenSnapshot)
Dim m As Module
Dim s As String
Set m = Modules("myEnumsModule")
s = "Option Compare Database"
s = s & vbNewLine & "Option Explicit"
s = s & vbNewLine
s = s & vbNewLine & "Public Enum MyEnums"
With rs
Do Until .EOF
s = s & vbNewLine & vbTab & .Fields("MYENUM") & " = " & rs.Fields("MYENUM_ID")
.MoveNext
Loop
End With
s = s & vbNewLine & "End Enum"
Call m.DeleteLines(1, m.CountOfLines)
Call m.AddFromString(s)
End Function
While an Enum type cannot be changed at runtime, a variable of that type can actually store any Long value.
Enum category
Category1 = 1
Category2 = 2
End Enum
Sub error(err As category)
Debug.Print err
End Sub
Sub test()
Dim category3 As Long: category3 = 3
Call error(category3) ' prints "3"
End Sub
But no, you cannot declare or update an Enum at runtime, nor convert an array to an Enum.

VB.Net "mask" combo box text as another text

So I have a combobox which contains table names from a MySql database they are automatically listed using show tables query upon form load.
Is there anyway to show something else in the combobox but the text value still being the original table name?
It isn't impossible. Here is a trivial example:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' This would be whatever you are pulling from the database. For the purpose of this example, it is just mock data.
Dim dataFromDatabase As IEnumerable(Of String) = {"1st table from db", "2nd table from db", "etc."}
' What you actually want to display in the combobox. It should be in the same order as above and have the same number of items. Items must be unique.
Dim valuesToDisplayInComboBox As IEnumerable(Of String) = {"1st item", "2nd item", "3rd item"}
' This is what ties the two together. You would probably want this to be larger in scope than this example.
Dim dataCollection As New Dictionary(Of String, String)
For i As Integer = 0 To dataFromDatabase.Count - 1 Step 1
dataCollection.Add(valuesToDisplayInComboBox(i), dataFromDatabase(i))
Next
ComboBox1.DataSource = valuesToDisplayInComboBox
End Sub
End Class
Now you have a Dictionary that links the 2 together, so whenever the user selects something in the combobox, you would go to the Dictionary and look up the corresponding table name.
Class Element
Public ItemName as String = ""
Public ItemData As Object = Nothing
' Object allows it to be reusable beyond this use
Public Sub New(iName as String, iData As Object)
ItemName = iName
ItemData = iData
End Sub
Public overrides Function ToString As String
Return ItemName
End sub
End Class
....
For each s as string in listoftablesfromdatabase
' dont know how you are getting your list,
' but here is one way to alias them
Dim El as Element
Select Case s
Case "tbl_event_birthdays_september"
El = New Element("September Birthdays", s)
case ...
case ...
End Select
ComboBox1.Items.Add(el)
Next s
The class will automatically use the friendly name you gave it. To get the real selected item name:
realName = ComboBox1.SelectedItem.ItemData.Tostring
might not need the .ToString This is not a lot different than Douglas Barbin's idea, it still associates 2 strings, it just doesnt use a dictionary. Alternatively, you could store the Elements in a List(of Element) or Dictionary and bind it to the datasource as Douglas showed.
If the user comes back to the Combo over and over, then do use a List or Dictionary, but not temporary - build it once and use it over and over.

grab linq to sql record by primarykey without knowing its type

how can i grab a record (and eventually delete it) using linq2sql without knowing the type at compile time?
so far i've got
Sub Delete(ByVal RecordType As String, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(MyAssembly, RecordType).Unwrap
Dim tbl = GetTable(dummy.GetType)
tbl.DeleteOnSubmit(dummy)
End Sub
but of course the dummy is not an actual record, its just a dummy
i don't want to use direct sql (or executecommand) as there's business logic going on at deletion in the datacontext partial class
can this be done somehow?
thank you very much!
EDIT
in response to striplinwarior, i edited my code to:
Sub Delete(ByVal RecordType As ObjectType, ByVal ID As Integer)
Dim dummy = Activator.CreateInstance(ObjectType.Account.GetType.Assembly.FullName, RecordType.ToString).Unwrap
SetObjProperty(dummy, PrimaryKeyField(RecordType), ID)
Dim tbl = GetTable(dummy.GetType)
tbl.Attach(dummy)
tbl.DeleteOnSubmit(dummy)
SubmitChanges()
End Sub
this does fire off the deletion code correclty, but also seems to try to add the record first to the db, as i get a sqlexception that some "not null" fields are empty, which i guess is true about the dummy record, as the only thing this has is the primarykey, else is all empty. so i tried the other code u posted (something i anyways always wanted to have) and that works excellent!
hers my current code:
Function LoadRecord(ByVal RecordType As String, ByVal RecordID As Integer) As Object
Dim dummy = Activator.CreateInstance(AssemblyName, RecordType).Unwrap
Dim rowType = dummy.GetType
Dim eParam = Expression.Parameter(rowType, "e")
Dim idm = rowType.GetProperty(PrimaryKeyField(RecordType))
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idm), Expression.Constant(RecordID)), eParam)
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim tbl = GetTable(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})
Return obj
End Function
Sub Delete(ByVal RecordType As String, ByVal RecordID As Integer)
Dim obj = LoadRecord(RecordType, RecordID)
Dim tbl = GetTable(obj.GetType)
tbl.DeleteOnSubmit(obj)
SubmitChanges()
End Sub
Thank You
The only way I can think of is to use the model information from your database mapping to figure out which member represents the primary key:
Dim primaryKey = (From t In db.Mapping.GetTables() _
Where t.RowType.Type = tableType _
Let keyMember = (From dm In t.RowType.DataMembers where dm.IsPrimaryKey).FirstOrDefault() _
Select keyMember.Member.Name).First()
(I'm using LinqPad here: I assume typical LINQ to SQL models have this mapping information available.)
Then use reflection to set the value of that key member on the dummy item you've created. After that, you need to attach the dummy to the table before trying to delete it, passing false as a second parameter to tell LINQ to SQL that you don't actually want to update the object using its current values, but that it should track changes from here on.
tbl.Attach(dummy, false)
tbl.DeleteOnSubmit(dummy)
db.SubmitChanges()
Does that make sense?
Edit
When you're only deleting an object, you don't necessarily have to get the record from the database. If you set the ID value of the object and then attach it to the context (as shown above), LINQ to SQL will treat it as if it were retrieved from the database. At that point, calling DeleteOnSubmit should tell the context to construct a DELETE statement in SQL based on that object's primary key value.
However, if you need to retrieve the object for some purpose other than deletion, you'll need to construct an expression to represent the query for that object. So, for example, if you were writing the query manually, you would say something like:
Dim obj = tbl.First(Function(e) e.Id = ID)
So to dynamically build the lambda expression inside the parentheses, you might do something like this:
Dim eParam = Expression.Parameter(rowType, "e")
Dim lambda = Expression.Lambda(Expression.Equal(Expression.MakeMemberAccess(eParam, idMember), Expression.Constant(ID)), eParam)
Then you would need to use reflection to invoke the generic First method:
Dim firstMethod = GetType(Queryable).GetMethods().[Single](Function(m) m.Name = "Single" AndAlso m.GetParameters().Count() = 2).MakeGenericMethod(rowType)
Dim obj = firstMethod.Invoke(Nothing, New Object() {tbl, lambda})

Retrieve Value Using Key From a Collection in Access 2000

I know this is a simple question but it's aggravating me. If I have a key/value pair in a collection but I can't seem to get the value out using the key. I can get the key using the value but not vice versa. Is there some magical way to accomplish this?
For example:
Dim CycleList As Collection
Dim Value as String
Set CycleList = New Collection
CycleList.Add 1, "Some Value"
Value = CycleList(1)
I've also tried CycleList.Item(1) and it's the same result, Value = 1.
The reason is that you are telling VBA to add an integer 1 with an alternate key of Some Value to the collection. When you call CycleList(1), you are asking for the Item with an index of 1 which happens to be the value 1. The second parameter Some Value represents an alternate key you can use to find the item you want. Here's an example to illustrate:
Public Sub Foo()
Dim bar As Collection
Set bar = New Collection
bar.Add 1, "Blah"
bar.Add "Foobar"
bar.Add 99
Debug.Print "bar(""Blah""): " & bar("Blah")
Debug.Print "bar(1): " & bar(1)
Debug.Print "bar(2): " & bar(2)
Debug.Print "bar(3): " & bar(3)
End Sub
Results when calling Foo in the debug window:
bar("Blah"): 1
bar(1): 1
bar(2): Foobar
bar(3): 99
Note that in the first Debug.Print, I ask for the value by key but in the others, I'm asking for the value by index.