EPPlus Excel Data Validation List - Empty strings not showing after export - vb.net

Good Day,
I am struggling to show empty string value in the data validation list that gets exported to the excel file. I have an array of values that I get from different Lookup tables (one for each valid column). Often some of these lookups will have an empty string value. I can see during debugging that the Empty value does appear in the Results view of the Validation list. But when the excel gets generated, the empty value disappears from the validation list. I followed advise to ensure the empty value appears on top (https://www.thespreadsheetguru.com/blog/blank-value-data-validation-list-excel) but still no luck. Would appreciate any advise here. (Note: we need to have the option to select empty "" string value from the list in exported excel.)
Dim oList_Validation = ws.DataValidations.AddListValidation(strCOlName & "3:" & strCOlName & ValToRow.ToString)
oList_Validation.ShowErrorMessage = True
oList_Validation.ErrorStyle = OfficeOpenXml.DataValidation.ExcelDataValidationWarningStyle.warning
oList_Validation.ErrorTitle = "Error Occurred!!"
oList_Validation.[Error] = "Please select a valid Codelist from drop-down..." & vbCrLf & "Click Cancel to re-set original value."
oList_Validation.ShowInputMessage = True
oList_Validation.Prompt = "Please select a Codelist from the drop-down list..."
oList_Validation.PromptTitle = "Custom Validation List"
Dim oCLMembers = CodeListInfo.ToArray()
Dim oNullCLItem = oCLMembers.Any(Function(a) a.Name.Equals(""))
'Code to add empty string as first value in List
If oNullCLItem = True Then
oList_Validation.Formula.Values.Add("")
End If
For Each CLChild In oCLMembers
oList_Validation.Formula.Values.Add(CLChild.Name)
Next
oList_Validation.AllowBlank = True

Related

How to get Selection.Text to read displaytext of Macro field code

I'm having some trouble figuring this out, and would really appreciate some help. I'm trying to write a macro that uses the selection.text property as a Case text-expression. When the macro is clicked in Microsoft Word, the selected text is automatically set to the DisplayText. This method worked great for the formatting via Selection.Font.Color for a quick and dirty formatting toggling macro, but it doesn't work for the actual text.
When debugging with MsgBox, it is showing a box (Eg: □ ) as the value.
For example,
Word Field Code:
{ MACROBUTTON Macro_name DisplayText }
VBA Code run when highlighting "DisplayText" in Word:
Sub Macro_name()
Dim Str As String
Str = Selection.Text
MsgBox Str
Select Case Str
Case "DisplayText"
MsgBox "A was selected"
Case "B"
MsgBox "B was selected"
End Select
End Sub
What is output is a Message Box that only shows □
When I run this macro with some regular text selected, it works just fine.
My question is this: Is there a way to have the macro read the displaytext part of the field code for use in the macro?
You can read the field code, directly, instead of the selection (or the Field.Result which also doesn't give the text).
It's not quite clear how this macro is to be used throughout the document, so the code sample below provides two variations.
Both check whether the selection contains fields and if so, whether the (first) field is a MacroButton field. The field code is then tested.
In the variation that's commented out (the simpler one) the code then simply checks whether the MacroButton display text is present in the field code. If it is, that text is assigned to the string variable being tested by the Select statement.
If this is insufficient because the display text is "unknown" (more than one MacroButton field, perhaps) then it's necessary to locate the part of the field code that contains the display text. In this case, the function InstrRev locates the end point of the combined field name and macro name, plus the intervening spaces, in the entire field code, searching from the end of the string. After that, the Mid function extracts the display text and assigns it to the string variable tested by the Select statement.
In both variations, if the selection does not contain a MacroButton field then the selected test is assigned to the string variable for the Select statement.
(Note that for my tests I needed to use Case Else in the Select statement. You probably want to change that back to Case "B"...)
Sub Display_Field_DisplayText()
Dim Str As String, strDisplayText As String
Dim textLoc As Long
Dim strFieldText As String, strMacroName As String
Dim strFieldName As String, strFieldCode As String
strDisplayText = "text to display"
If Selection.Fields.Count > 0 Then
If Selection.Fields(1).Type = wdFieldMacroButton Then
strFieldName = "MacroButton "
strMacroName = "Display_Field_DisplayText "
strFieldCode = strFieldName & strMacroName
Str = Selection.Fields(1).code.text
textLoc = InStrRev(Str, strFieldCode)
strFieldText = Mid(Str, textLoc + Len(strFieldCode))
MsgBox strFieldText
Str = strFieldText
'If InStr(Selection.Fields(1).code.text, strDisplayText) > 0 Then
' Str = strDisplayText
'End If
End If
Else
Str = Selection.text
End If
Select Case Str
Case strDisplayText
MsgBox "A was selected"
Case Else
MsgBox "B was selected"
End Select
End Sub

Pasting in Data Validation IF the value exists inside the data validation list

A similar question has been asked multiple times, but I have a slightly different ask. I have used some code from superuser that restricts users from pasting values into data validation ranges:
Private Sub Worksheet_Change(ByVal Target As Range)
'Does the validation range still have validation?
If HasValidation(Range("DataValidationRange")) Then
Exit Sub
Else
Application.Undo
MsgBox "Error: You cannot paste data into these cells." & _
"Please use the drop-down to enter data instead.", vbCritical
End If
End Sub
Private Function HasValidation(r) As Boolean
'Returns True if every cell in Range r uses Data Validation
On Error Resume Next
x = r.Validation.Type
If Err.Number = 0 Then HasValidation = True Else HasValidation = False
End Function
This is great and it works, but I am wondering if it can be taken one step further. The reason users may want to paste into these fields is because they are moving data from one spreadsheet to the other. I have the validation there to ensure the spelling is correct (important for other uses). Is it possible for a user to paste something into the data validation field and it doesn't deny it, based on the code above, IF the value matches something inside the data validation list? Seems ambitious, not sure if it is possible.
Edit: The list is stored in another tab, not hardcoded into the data validation menu
If the Validation isn't Nothing and its type is xlValidateList (underlying value 3), then you can use Validation.Formula1 to get the "list".
That's the easy part.
If Formula1 doesn't start with an = sign, you're looking at a plain comma-separated list of values.
This function gets you a 1-dimensional array with all the valid values of the specified target, regardless of how the data validation list is defined:
Public Function GetValidationValues(ByVal target As Range) As Variant
Dim dataValidation As Validation
Set dataValidation = target.Validation
If dataValidation Is Nothing Then Exit Function
If dataValidation.Type <> xlValidateList Then Exit Function
Dim values As Variant
If Left$(dataValidation.Formula1, 1) <> "=" Then
'plain comma-separated list of values
values = Split(dataValidation.Formula1, ",")
Else
'validation list is a range address, or a named range
Dim rngValues As Range
Set rngValues = Application.Evaluate(dataValidation.Formula1)
If rngValues.Columns.Count > 1 Then
values = Application.Transpose(Application.Transpose(rngValues))
Else
values = Application.Transpose(rngValues)
End If
End If
GetValidationValues = values
End Function
All that's left to do is to determine whether your pasted value is in that array.

Access Combo - Filter As You Type?

I started a thread here: Access Form Combobox Partial Filter but it was a bit too specific, and now that I moved past that, I am struggling to get the behavior I want.
Here is the layout:
A form with the detail hidden. The header has an unbound combobox for filtering the form. Once there is a filter to apply, that record is set for the filter on the form, and the detail is shown. The users want to be able to type in the combo, for partial matches, instead of only being able to click the drop down and click to choose an option.
This is the rowsource of the combo:
SELECT [vw_Info_Records]![recordName] & " (" & [vw_Info_Records]![recordNo] & ")" AS frecord, vw_Info_Records.INF_RID
FROM vw_Info_Records
WHERE ((([vw_Info_Records]![recordName] & " (" & [vw_Info_Records]![recordNo] & ")") Like "*" & [Forms]![frmrecords]![cboFindrecord] & "*"))
ORDER BY [vw_Info_Records]![recordName] & " (" & [vw_Info_Records]![recordNo] & ")";
It is set to auto-expand Yes. It is not bound to anything, and limit to list is set to yes.
This is the onchange event:
Private Sub cboFindRecord_Change()
Dim MyCriteria As String
If Me.cboFindRecord.SelStart > 0 Then
Me.cboFindRecord.Dropdown
End If
End Sub
This is the after update:
Private Sub cboFindRecord_AfterUpdate()
Dim Criteria As String
Dim myfilter As String
If Me.cboFindRecord.ListIndex = -1 Then
Me.Form.Filter = ""
Me.FilterOn = False
Me.Detail.Visible = False
Else
Criteria = "[INF_RID] = " & Me.cboFindRecord.Column(1)
With Me.Form
.Filter = Criteria
.FilterOn = True
End With
Me.Detail.Visible = True
End If
End Sub
The first character that is typed in, makes the dropdown expand, and filter to any results that contain that character. Any subsequent characters, and the drop down list doesn't update the filter to re-filter based on the added characters. If I add a requery in the change, I get an error about saving the field, before I do a requery. It wants me to set that "filter" value as a value for the combo, which I wouldn't do, because it's really an in string filter. The user still needs to pick a value from whatever is left in the list, before I can filter the form to that record.
Thanks for any advice as to how to fix this!

Adding values to a combobox based on another value VBA

I am currently trying to get a combobox to add items based on another combobox value, but am coming unstuck.
The following is the code I have so far - through trial and error I have got to this stage, although this is still giving me a "1004" error relating to the last line of the code. Is there a better way of writing this to get the same result?
Private Sub ProductInfo1_Change()
Dim strName As String
Dim strNameProductAllData As String
Dim strNameProductName As String
Dim strNameProductDescription As String
strName = Replace(OrderForm1.OrderFrm3.Value, " ", "")
sheet = "strName"
strNameProductName = Replace(strName, " ", "") & "productname"
strNameProductDescription = Replace(strName, " ", "") & "productdescription"
Me.ProductInfo2 = Application.WorksheetFunction.Index(Sheets(strName).Range(strNameProductDescription), Application.WorksheetFunction.Match(ProductInfo1.Value, Sheets(strName).Range(strNameProductName), 0))
End Sub
You are assigning to the wrong object.
You are trying to set a combobox, ProductInfo equal to a range.
What you want to do is use the "RowSource" property of the combobox
For example:
Me.ProductInfo2.RowSource = "mySheet!$A$1:$A$10"
This would make the choices for the ProductInfo2 combobox the items in cells A1-A10.
It is unclear what you are trying to get with the Match/Index Worksheet functions. If the contents of the cell have a range, then just use the contents to be equal to this rowsource. So for instance, if the column that represents "strNameProductDescription" has the range "myRange" in it, then your code can simply be modified to put this into the RowSource property. If it contains some other piece of information, then you need to construct the range you are looking for so that it would be similar to the line shown above. If myRange is a range on your worksheet, then the code,
Me.ProductInfo2.RowSource = "myRange"
will work.

Multi-Select Files Into Array VB.Net

I am working on a program where I need the user to select two files from an OpenFileDialog. I don't want to hardcode the file names or paths into the program. I need the contents of these files to display into two columns in a List Box.
So far I have the following code:
OpenFileDialog.ShowDialog()
OpenFileDialog.Filter = "Text Files(.txt)|*.txt"
OpenFileDialog.Title = "Open A Text File"
OpenFileDialog.Multiselect = True
Dim FileArray(1) As String
Dim objreader As New System.IO.StreamReader(OpenFileDialog.FileName)
Dim i = 0
ListBox1.Items.Clear()
ListBox1.Items.Add("Name" & Space$(40) & "ID Number")
Do While objreader.Peek() <> -1
If OpenFileDialog.FileNames.Length = 5 Then
FileArray(0) = objreader.ReadLine & vbCr
Else
FileArray(1) = objreader.ReadLine & vbCr
End If
ListBox1.Items.Add(FileArray(0) & Space$(40) & FileArray(1))
Loop
What I think is happening is the first selected file, 'Names.txt' is being fed into FileArray(0) (because the length of the file name is 5 characters), and then being populated into the correct column in the list box.
However, as it loops a second time, the second file, 'IDNumbers.txt', is read and populated into FileArray(1) (because it fails the 'If') and is overwriting the first array in the list box.
My question is how can I load each file into its own element in my FileArray(1), so I can load them correctly into the ListBox and later manipulate the data?