I am trying to automatically fill the salutation in my mails depending on the recipient.
To start this routine I use the event MailItem_PropertyChange which is gives back the name of the changed property.
At any change of the "To" field the event handler fires three times.
The first time it gives back the name "To".
The second time it gives back the name "CC".
The third time it gives back the name "BCC".
This means, no matter which one of the three values I change, my routine always acts as if I changed the To value.
Private Sub objMail_PropertyChange(ByVal Name As String)
If Name = "To" Then
objMail.htmlBody = "Hallo Zusammen" & objMail.htmlBody
End If
End Sub
Yes, because 3 properties (potentially) change.
Related
I have been having a quite annoying issue on my access project.
It is an Access 2007 - 2016 file.
My database has two queries that I intend to use to filter data to feed combo-boxes.
On one of my forms I have done that with success. The first list is fed from a table, and the succeeding ones are fed by filtering their respective table based on the previous list selection.
Here is a screenshot of my form that worked out.
And here is part of the code that goes with it:
Private Sub frm01ListSetor_Click()
DoCmd.Requery (qry01_frm01ListArea)
Me![frm01ListArea] = Null
DoCmd.Requery (qry02_frm01ListEquip)
Me![frm01ListEquip] = Null
Me![frm01TextID] = Null
End Sub
Private Sub frm01ListArea_Click()
DoCmd.Requery (qry02_frm01ListEquip)
Me![frm01ListEquip] = Null
Me![frm01TextID] = Null
End Sub
Here are the queries that goes along with the code above:
qry01_frm01ListArea
SELECT tblAreas.ID_Area, tblAreas.NomeArea
FROM tblAreas
WHERE (((tblAreas.SetorArea)=[Forms]![frm01_AddEquip]![frm01ListSetor]));
qry02_frm01ListEquip
SELECT tblEquipamentos.ID_Equipamento, tblEquipamentos.NomeEquipamento
FROM tblEquipamentos
WHERE (((tblEquipamentos.SetorEquipamento)=[Forms]![frm01_AddEquip]![frm01ListSetor]) AND ((tblEquipamentos.AreaEquipamento)=[Forms]![frm01_AddEquip]![frm01ListArea]))
ORDER BY tblEquipamentos.ID_Equipamento;
The code above works just fine. It filters data to previous selection accordingly and it also clears the data and selection of the "righter" lists every time another value is selected on the "lefter" ones.
So that was a form I created to help me out on populating my equipment database.
Let us get to the problematic twin now:
I created another form for Maintenance Orders of these equipment.
This one must be more user friendly since other people will use it. Therefore I used Combo-boxes for value selection instead of List Boxes. I say this before hand because it is the only thing I could notice that differs the new form from the one above.
Here I have this:
Screenshot of troubled form
After the expanded Combo-box on image 2 is selected I should run the following code:
Private Sub frm02SetorOM_Click()
DoCmd.Requery (qry04_frm02CBArea)
Me![frm02AreaOM] = Null
DoCmd.Requery (qry05_frm02CBEquip)
Me![frm02EquipamentoOM] = Null
End Sub
Private Sub frm02AreaOM_Change()
DoCmd.Requery (qry05_frm02CBEquip)
Me![frm02EquipamentoOM] = Null
End Sub
It is basically the very same thing I have done on the first form but with different variables.
But I get a "Run-time error 3021: No current record" every time I select a value on my "Setor" field.
The crash happens at the "DoCmd.Requery (qry04_frm02CBArea)" line.
Here is the query for this form's Area field (qry04_frm02CBArea):
SELECT tblAreas.ID_Area, tblAreas.NomeArea
FROM tblAreas
WHERE (((tblAreas.SetorArea)=[Forms]![frm02_SubmitOM]![frm02SetorOM]));
But the thing that is confusing me the most is that when I click "End" on the Run-time error dialog box, my Area combo-box - that was empty before - even with the error gets the proper options like if it actually "requeried".
How can I fix this issue?
Thank you in advance.
Btw, this is my first Access project so please consider that on the response.
I could not find an answer to my specific question, but I am also relatively new to VBA, so maybe I just didn't look for the right terminology.
What I have, is a form that contains a bunch of comboboxes. These are arranged in rows and columns like so:
cboThingOne1 cboThingTwo1 cboThingThree1
cboThingOne2 cboThingTwo2 cboThingThree2
... ... ...
cboThingOne15 cboThingTwo15 cboThingThree15
I have set cboThingOne to show a selection of items (e.g. department1, department2, department3,...) from an SQL database.
cboThingTwo and cboThingThree are also set to a certain Rowsource (containing things like Apple, Bananas and Cherries).
What I would like to happen is, as soon as I change the value in cboThingOne1 to department3, to fill all of cboThingOne checkboxes with the same value.
This is working. I am using the AfterUpdate event of each cbo, to call a function, which iterates over all items in Me.Controls, checks their name + 1 (in this case cboThingOne2) and sets the value of this control to department3.
Private Sub fun_fill_cbo_with_value(FieldName As String, FieldValue As String)
Dim i as Integer
'This function returns the name without number
my_fieldname = Striptext(FieldName)
'gets me the number of the field I am working with (i.e. cboThingOne1 --> 1)
i = Int(Replace(FieldName, my_fieldname, ""))
i = i+1
cbo_name = my_fieldname + CStr(i)
For Each my_control In Me.Controls
If my_control.Name = my_fieldname Then
my_control.Value = FieldValue
End If
Next my_control
End Sub
When the value for cboThingOne2 is changed, I expected the AfterUpdate event of this cbo to be triggered, which apparently does not happen.
In this AfterUpdate event the Rowsource for cboThingTwo2 should be updated.
Private Sub cboThingOne2_AfterUpdate()
'To update the cbo in the row below
Call fun_fill_cbo_with_value(cboThingOne2.Name, cbo_ThingOne2.value)
Me.cboThingTwo2.RowSource = "somedifferentqueryhere"
Me.cboThingThree2.Rowsource = "yetanotherquery"
What I expected, was that updating the value in fun_fill_cbo_with_value would update the value of the cbo + 1 (which works) and also triggers the AfterUpdate event (which does not happen).
Furthermore, because I am calling fun_fill_cbo_with_value in the AfterUpdate event, I expected the column to fill to the end, rather than just the cbo below (as it does right now).
I can fill the entire column of cbos, by adding an additional loop in fun_fill_cbo_with_value which just goes from 1 to 15.
That still does not help me with updating the rowsource of cboThingTwo and cboThingThree.
I hope you can help and if you need more information, I am glad to provide it.
I expected the AfterUpdate event of this cbo to be triggered, which
apparently does not happen.
It is triggered by a user action only.
Call the AfterUpdate event function itself from your code (bad practice); or (allows for better organised code) let the AfterUpdate event call a separate function which your other code can call as well.
I got a Database, where I apply to a name a Main and Subgroup.
When I enter a MainGroup f.e. Granades, just subgroup elements like "attack-granades" etc. should be shown.
In genereal it works by writing in this into the MainGroup-Combobox at my Form.
Private Sub MunHauptgruppeRef_AfterUpdate()
Me.MunUntergruppeRef.Requery
Me.MunUntergruppeRef.RowSource = " SELECT UnterGrpNR, UnterGrpName FROM tbl_UnterGruppen WHERE UnterHauptGruppenNr = " & MunHauptgruppeRef.Value & " ORDER BY UnterGrpName ASC"
The Problem is, if I load the datas in my form again, it just shows the related Number to the "Sub-Combobox data" 1( f.e. 35 for Attack-Grenade ) , but not the Name itself. After I reselect the entry in my Main-Combobox(Grenade), it shows the right sub-data which was saved. 2
Tried Requery on Form_Load or Requery of the Combo-Boxes itself. nothing helped so far.
Made some Video3
You need to add the code from Private Sub MunHauptgruppeRef_AfterUpdate() to your Form_Current event, this will refresh your combo box row source to the current value of your MunHauptgruppeRef combobox as you cycle through your records. Also you need to call the Me.MunUntergruppeRef.Requery after you've set the Me.MunUntergruppeRef.RowSource.
You can also add a check when your in a New Record, for the code not to run on the Current Event. See here https://learn.microsoft.com/en-us/office/vba/api/access.form.newrecord
I have a lookup listbox which is programmed to allow the user to find a specific record/help topic from the list and view it. Now when the list box is used the where clause locks in the record and the first, previous, next, last buttons freeze up and you cannot use them to go to a record. Is there a way to free up the functionality of the buttons to navigate through the records along with the where clause to select.
Here is the code that operates the listbox selections:
Private Sub List35_AfterUpdate()
Dim myTopic As String
myTopic = "Select * from FormsHelpTable where ([ID] = " & Me.List35 & ")"
Me.Form.RecordSource = myTopic
Me.Comment.Requery
End Sub
I believe since the where clause locks in the selection in the box it does not allow navigation from other controls to interfere. What might be a way around this?
You get the runtime error:
You can't go to specified record.
It appears not to be reading the other record in the source table named Help once it updates using the listbox.
Instead of changing the recordset (this is the 'pool' of records which the form could display), you just need to go to the record the user selects from the listbox.
Method 1 (probably the easiest way if your listbox is in the same order as the records of your form)
Use this code:
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
End Sub
You need to ensure that:
The recordset of the form is ordered the same as the listbox. So, for example, you could order both by ID, or by Title.
Note that the +1 comes from the fact that the ListIndex starts at 0, whereas the record indexes start at 1.
Method 2
Ensure each record's Title is unique (set No Duplicates on this field).
Change your listbox to return the Title of the record, rather than it's ID.
Then use this:
Private Sub lstSelect_AfterUpdate()
Me.Title.SetFocus
DoCmd.FindRecord Me.lstSelect
Me.lstSelect.SetFocus
End Sub
Things to note:
It works by searching the field with focus for the string specified. That's why we have to SetFocus on the Title textbox on our form.
We could use ID instead, (which would mean we could have duplicate titles if we wanted), but then we would have to have an ID control on the form to SetFocus to. You can't hide this control either, because it needs to have focus whilst using FindRecord.
Update: Method 1 with reverse-selection
Add an Event Procedure in the Form_Current event, with this code. Then update the code in the lstSelect_AfterUpdate procedure as shown after.
Private Sub Form_Current()
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Note that, depending on how your lstSelect is set up, it may be Column(1, Form.CurrentRecord - 1) instead. Read on for details!
Private Sub lstSelect_AfterUpdate()
DoCmd.GoToRecord acDataForm, "HelpForm", acGoTo, Me.lstSelect.ListIndex + 1
Me.lstSelect = Me.lstSelect.Column(0, Form.CurrentRecord - 1)
End Sub
Explanation of new lines:
The Form_Current event fires every time we go to a new record. We need to look at the index of the record (ie. the position of it in the recordset), which we get by using Form.CurrentRecord. We then want to make the listbox select that record. However, we can't use me.lstSelect.ListIndex as before, because that is a read-only property (we can access it to read it, but we can't set it).
Therefore, we use me.lstSelect.Column(colNum,rowNum) instead, where we specify a column number and a row number. If your listbox has two columns (eg. ID and Title), we want to choose the second column. The index starts at 0, so we would use a value of 1. If, like my lstSelect, you only have one column (Title) then we use 0. Note: it doesn't matter if a column is hidden (ie. has width 0). It still 'counts'.
The row number is Form.CurrentRecord - 1. Remember that the forms recordset index starts at 1, but the index of our listbox starts at 0; hence the - 1.
So why do we need a duplicate of this new row in the AfterUpdate event? Try and comment it out to see what happens if we don't put it in. It's has to do with the Form_Current event firing after we use the listbox.
I fixed this issue with a union clause in the SQL lookup code. The UNION ALL clause and the following union on the table used in the other part had allowed all the records to be used.
I have an application in WinForms where I have many controls. These controls represents settings of application and user can save this settings by clicking on a button.
I am trying to resolve a problem with NumericUpDown (I will call it Num) control: Lets say that Num has these properties:
Minimum: 10
Maximum: 60
Step: 1
If a user want to change value, there are two ways how to do that: clicking on arrows (right side of the Num) or manually typing value directly to Num. First way is OK but most most of users are using second way and there is a little problem.
If a user type some value out of the interval for example 1, it is OK because he could continue in typing with 5 so final value is 51 and this is inside the interval. But if he stop typing after value 1, it means he type value out of the interval (1). If he click somewhere out of the Num, value (which is out of the interval) is automatically changed to the closest allowed value (in case of 1, value will be changed to 10).
But he probably will not notice this automatic change so I want to handle it somehow and inform him that he put there invalid value. But this situation is not handled by any event of Num (there is no way how to find out this invalid value he put there - if I try to read value inside ValueChanged event, it reads automatically changed value, not the invalid one).
I know I can add TextChanged event, but there is a problem that if he type some invalid value (5), it can be changed to valid value (by adding 1 so it makes 15).
Do you have any ideas how to resolve this issue? I know this is stupid but this doesn't depend on me, I have to do this and I don't know how.
use Lost Focus and instead of setting the minimum at design stage check it with an If statement.
Private Sub Num_LostFocus(sender As Object, e As System.EventArgs) Handles Num.LostFocus
If Num.Value < 10 Then MsgBox("Number is incorrect")
End Sub
alternatively you can probably create a custom control where you can override the event that changes the value to the minimum but i have never tried.
So this is my solution:
I handle TextChanged event and inside this method I assign text to its tag:
Private Sub NUDTextChanged()
Integer.TryParse(NUD.Text, NUD.Tag)
End Sub
And then:
Private Sub NUD_LostFocus() Handles NUD.LostFocus
If NUD.Tag < NUD.Minimum Or NUD.Tag > NUD.Maximum Then
' show message
End If
End Sub
Handling Validating event is useless for me because automatic change to allowed value is before validating and this automatic change fires TextChange event so after validating I have new value instead invalid one.
LostFocus is before automatic change so I can easily control if the value is valid or not.