Excel data validation missing after re-opening file - vsto

I am adding some data validation on the fly using the following:
var cell = sheet.Range["A2", "A1048576"];
cell.Validation.Add(
XlDVType.xlValidateList,
XlDVAlertStyle.xlValidAlertStop,
XlFormatConditionOperator.xlBetween,
"ABC,DEF,123");
This works grand and you will see the ABC,DEF and 123 in the datavalidation dropdown for the column. The issue is after re-opening the sheet later the data validation is gone. An error is shown
Click yes then you are presented with:
Click close and your sheet is displayed with all the data already entered but the data validation is gone entirely.
How do I add the validation so it persists and survives save and re-open?

This happens if the string exceeds 255 chars (in the above example "ABC,DEF,123"). The better solution (if appliable) is to create the list using a reference and not a collection of strings.

Related

ActiveX Combobox value not setting to linkedcell on another sheet on workbook_open

We have created a workbook which use ActiveX objects and macros to perform multiple actions (calculations, changing values in cells, forcing mandatory fields before save, colour changes, lock and unlock, etc). There are 3 sheets:
Lists - where we set the values for comboboxes, run mandatory checks against cells and comboboxes, etc. this is VeryHidden to the user
Form - this is where the user will enter their data. it contains all of the ActiveX objects
Import - this is a formatted sheet which we can import to our database with expected formatting on values (i.e. "inches" instead of "in.H2O#60F", days converted to hours). this sheet is VeryHidden.
This workbook can be downloaded blank from our website and imported back into the database successfully.
What we want to do is download a pre-populated version where "Form" shows data from the database. To do this we are populating the Import sheet with the values (as they are already linked to the comboboxes we need to populate). i.e. ComboA on "Form" is linked to cell A4 on "Import".
We expected the comboboxes with linked cells to the update when we downloaded and opened the pre-populated workbook. When it did not we tried:
Sheets("Import").EnableCalculation = False
Sheets("Import").EnableCalculation = True
Application.Calculate
to force the row to "recalculate" and therefore trigger the linked cell to work as when we manually went into one of the linked cells and pressed enter (or F9) the associated combobox updated.
This was partially successful in that is populated around 1/3 of the comboboxes but not all of them. There does not seem to be an order or data type causing the issue (some Y/N update, others do not. comboboxes A-D will update, then E-G will not, then H will).
We tried Application.CalculateFull as well as:
setting the linkedcells to Dirty
only applying .Calculate to the range on the worksheet
only applying .Calculate to the row on the worksheet (as it is all in one row)
We can manually force each combobox to populate with it's linked cell however given the number of comboboxes and the fact there will be more workbooks like this to build this is not an ideal solution.
We know it is hitting the workbook_Open() event as we put in some MsgBox items and the couple custom populations we do (converting degF to F then pushing to combobox) and that is working fine.
If we open the download, save it (skipping the mandatory fields before save), then reopen it everything populates/selects correctly (which is all the more frustrating).
Any thoughts on why the downloaded version is not acting as expected would be much appreciated.
given the other posts I have seen and the follow up information requested I though more was better. there is a code snippet there - and we found a solution to the issue. needed to add Application.Calculation = xlCalculationAutomatic to the open event before the code provided above. thanks anyways

Trouble with Copying VBA Code

I've been working on an independent project for a client of mine. They wanted to produce a button that, upon the user-click, it would open up a user-form and have a variety of macro-related options to choose from: a drop-down list, checkbox, option select button, etc.
I created a test formula and submitted it to the client; they enjoyed it thoroughly and decided to sent me a file to 'copy & paste' my original code within their excel file.
Problem is; because I'm a tad bit inexperienced with VBA I've run into a problem where once I click the button - the user form doesn't show up.
Below is a Dropbox link of the original file I created and it's original code; as well as the file that I am trying to copy.
Any help would be all welcome and appreciated.
Link to dropbox: https://www.dropbox.com/sh/l1t37lz8uritrua/AAAdWPGvw0GDZ6hW4SwmbBdRa?dl=0
OriginalProject.xlsm has a form named honor_roll_form which contains 100 lines of code.
CopyOfOriginal.xlsm has a form named UserForm1 which contains no useful code.
I do not believe there is any method of directly copying user forms from one workbook to another. Instead
Within VB Editor of OriginalProject.xlsm, select honor_roll_form.
Click File then Export File and save the form on your desktop or where ever you like.
You will now have two files on your desktop; one with an extension of frm and one with an extension of frx.
Within VB Editor of CopyOfOriginal.xlsm, click File then Import file.
Import honor_roll_form.frm
When I try clicking button "Honor Roll", I get "Method or data member not found" for project1Box. I will investigate after dinner (18:57 here) unless you tell me you already know why I am getting this error.
Extra comments in response to request from OP
It is late here but I have started looking down sub execute_button_Click within the second CopyOfOriginal.xlsm. I will comment on what I see even if it is not directly relevant to the non-execution of the macro.
If you open the VB Editor and look on the left you will see the Project Explorer. Near the top you will see:
Microsoft Excel Objects
Sheet1 (Sheet1)
I have always found this confusing. The first “Sheet1” is Excel’s Id for the worksheet and cannot be changed. The second “Sheet1” is the default name for the worksheet which can be changed. You can write Sheet1.Range("A1") or Worksheets("Sheet1").Range("A1"). That is: you can reference a worksheet by its Id or its name. You have named a variable of type Worksheet as Sheet1. Using Excel’s names as variable names can lead to bizarre errors so it is important to avoid doing anything like this.
It is better to always use meaningful names. At the moment, you know what Sheet1 means but if you come back to this macro in six or twelve months will you remember. I would use a variable as you have but I would name it WshtCis208 or WshtVBAProg or something similar.
Set ID = Range(Sheet1.Cells(2, 1), Sheet1.Cells(52, 1)) could be written as:
With WshtCis208
Set ID = Range(.Cells(2, 1), .Cells(52, 1))
End With
Using With statements produces faster code and, almost always, code that it easier to read.
“52” is the current bottom row for this table. Will you amend the macro for them every time they add or remove a student? There are several techniques for finding the last row, none of which is perfect in every situation. The technique that is the most convenient most of the time is:
Const ColCis208Id as Long = 1
Const ColCis208MidTermExam as Long = 5
Dim RowCis208Last as Long
RowCis208Last = .Cells(.Rows.Count, ColCis208Id).End(xlUp).Row
At the moment, column 1 is the Id column. It is perhaps unlikely that the Id column will move but it is very likely that some of the others columns will move when some new column is identified as useful. Do you want to scan the code trying to decide which 5s refer to the MidtermExam column when a Project3 column is added?
Constants allow you to name literals that might change. It makes your code easier to read and saves so much pain when a value changes.
.Rows.Count gives the number of rows in a worksheet for the current version of Excel so .Cells(.Rows.Count, ColCis208Id) identifies the bottom cell of column 1. End(xlUp).Row says go up until you hit a cell with a value and returns its row number. It is the VBA equivalent of Ctrl+Up.
The next statement subjectCount = … fails because projectBox does not exist on the form. You have changed the captions but not the names.
As far as I can see the form fails to execute because you have started updating it but have not finished.

Openpyxl update Data Validation

I want to create a drop down list in a excel sheet, and be able to update it when I load this sheet. When I change the items in my DataValidation list, and add it to the sheet, the list doesn't change.
Is there a way to update my list or just delete it?
wb = openpyxl.load_workbook(path)
ws_meteo = wb.active
dv = DataValidation(type="list", formula1=Formule, allow_blank=True)
dv.add_cell(ws_meteo['A10'])
ws_meteo.add_data_validation(dv)
wb.save(path)
Being five years late. I think I've encountered the same issue you did.
I have a excel file which needs unique data validation list for individual cells based on an external web service. This works fine when there is no data validation present in the cell. However if a data validation list is present, it appends another data validation list to the cell. On opening the file in Excel, It appears to select the first data validation list it encounters, thus the dropdown list never changes.
I solved it by removing any existing data validation for that cell before adding the new one. I used the following code.
def removeExistingCellDataValidation(worksheet, cell):
toRemove = []
# Append all validation rules for cell to be removed.
for validation in worksheet.data_validations.dataValidation:
if validation.__contains__(cell):
toRemove.append(validation)
# Process all data validation rules set for removal.
for rmValidation in toRemove:
worksheet.data_validations.dataValidation.remove(rmValidation)
After clearing the existing data validation I add the new data validation list as usual, the same way you do in your code snippet.

Excel VBA: Get the right date into a cell using DatePicker

I have a UserForm with a DatePicker control in it.
It works fine, except when copying the selected date to the spreadsheet.
This is the code:
Range("A1").Value = UserForm1.DTPicker1.Value
Which returns:
00:00:00
In cell A1, no matter what date has been selected.
You cell formatting might be set to Time instead of Date.
Try changing that to see if it works.
Also, make formatting 'General' AFTER this step, to see if anything has been pasted in "A1".
You should need an intermediate variable to get it, like below:
t = Me.DTPicker1.Value
ws.Range("A1") = t
Make sure that the command to transfer the data is located in the same form or page of a multipage form as the DTPicker itself.
For some reason it wont work when the two are separated and will display a zero in the target cell. That zero is the "time" part of the date which has been switched off. Although the "Date" part refuses to transfer over, for some reason the time does, and so that zero time is read in the cell as time zero which is mid-day.
So in summary:
Keep the DTPicker and transfer control on the same page and that should solve the problem.
The code is pretty simple. It's
Sheet1.Range("AA9") = Me.DTPicker1.Value

Google Apps Script on Form Submit Time Formatting Glitch/Fix

Background:
How: I suspect that this is a glitch within Google Form (submission process)/Spreadsheet, but may be part of the Date conversion utility of the Spreadsheet interface (and is an intended feature).
When entering a format in a text box in Google Forms, there is some sort of communication error between the Form submit and Response Spreadsheet, or pre-processing of the Form's data before it is sent to the spreadsheet. The glitch only seems to happen for data in a text field of the format ##:## TEXT where TEXT contains no '.' characters. For example: 4:15 pm will reproduce the glitch, but 4:15 p.m and 4:15 p.m. will not.
Result: An apostrophe character is added to the beginning of the string when it is put into the Spreadsheet (i.e. '4:15 pm) which throws off several sub-systems I have in place that use that time data. Here are two screenshots (sorry for the bad sizing on the second):
I'm 99% certain that the glitch is caused by the ##: combination.
Temporary Fix?: The real question is... how might I go about removing that pesky apostrophe before I start manipulating the time data? I know how to getValue() of a cell/Range. Assume I have the value of a cell in the following manner:
var value = myRange.getValue();
// value = '4:15 pm
How can I go about processing that value into 4:15 pm? A simple java function could be
value = value.substring(1); // Assuming "value" is a String
But in Google App Scripts for Spreadsheets, I don't know how I would do that.
Post-Script: It is necessary to post-process this data so that I don't have to lecture university faculty in the language department about inputting time format correctly in their forms.
Thanks in advance to those who can help!
How can I go about processing that value into 4:15 pm? A simple java
function could be
value = value.substring(1); // Assuming "value" is a String But in
Google App Scripts for Spreadsheets, I don't know how I would do that.
Google Apps Scripts uses Javascript which has the exact same method.
value = value.substring(1);
should return all except the first character.
More about Javascript substring at: http://www.w3schools.com/jsref/jsref_substring.asp
If you remove the ' in the spreadsheet cell the spreadsheet interface will convert this entry to a date object.
This might (or not) be an issue for you so maybe you should handle this when you read back your data for another use...
It doesn't happen when text is different (for example with P.M) simply because in this case the ' is not necessary for the spreadsheet to keep it as a string since the spreadsheet can't convert it to a date object (time value).
Artificial intelligence has its bad sides ;-)
edit :
You cant do this in an onFormSubmit triggered function using the javascript substring() you mentioned. If you're not familiar with that, here is the way to go :
To run a script when a particular action is performed:
Open or a create a new Spreadsheet.
Click the Unsaved Spreadsheet dialog box and change the name.
Choose Tools > Script Editor and write the function you want to run.
Choose Resources > Current project's triggers. You see a panel with
the message No triggers set up. Click here to add one now.
Click the link.
Under Run, select the function you want executed by the trigger.
Under Events, select From Spreadsheet.
From the next drop-down list, select On open, On edit, or On form
submit.
Click Save.
see doc here and here