Недавно я работал над range.Validation.type = xlValidateList и хотел запретить вставку, вырезание и запрет на ввод неправильных символов в ячейку, содержащую раскрывающийся список (и позволяя вводить символы, соответствующие записи в списке, и отображать эта запись).
Работая над последним, что было не в порядке (вырезая раскрывающийся список и вставляя его в другую ячейку, уже содержащую раскрывающийся список), я обнаружил ЛЕГКИЙ способ запрета вставки и вырезания для списков проверки данных, который разрешить дальнейшую обработку в зависимости от того, что было введено,
следующий код должен быть в модуле рабочего листа. Он не позволяет пользователю уничтожить проверку данных в ячейках, поэтому использование Application.Undo для возврата в состояние перед вставкой или вырезкой больше не требуется.
Я не знаю, имеет ли это значение, но я Защищенный лист и разблокированные ячейки, которые пользователь может изменить.
Private Function HasValidation(ByVal rng As Range) As Boolean
' See: https://superuser.com/questions/870926/restrict-paste-into-dropdown-cells-in-excel
' Returns True if every cell in Range r uses Data Validation
On Error Resume Next
Dim rngType: rngType = rng.Validation.Type
HasValidation = (Err.number = 0)
End Function
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' Switch DragAndDrop on/off on a range containing DataValidation
Dim modeCutCopy: modeCutCopy = Application.CutCopyMode
Dim usesValidation: usesValidation = HasValidation(Target)
If ((usesValidation = True) And (modeCutCopy <> 0)) Then Application.CutCopyMode = False ' MUST reset to avoid copying / cutting xlValidateList into another xlValidateList
' Turn DragAnddDrop on/off depending on if a cell uses Validation or not
If (usesValidation = Application.CellDragAndDrop) Then Application.CellDragAndDrop = (Not usesValidation)
GoTo SKIP
' Don't allow DragAndDrop if Target intersects with specified ranges
Dim myRange As Range
Set myRange = Worksheets("Evenementen").Range("Oordeel", "Waardering")
Dim rngIntersect As Range
Set rngIntersect = Application.Intersect(Target, myRange)
Application.CellDragAndDrop = (rngIntersect Is Nothing)
'' CheckInputValidationList(Target) ' Sophisticated testing and actions depending on the selection made
'' CheckInputValidationList(Target, myRange) ' Sophisticated testing and actions depending on the selection made for specific ranges
SKIP:
Debug.Print "SelectionChange " & Target.Address & " usesValidation=" & usesValidation & " cellDragAndDrop=" & Application.CellDragAndDrop
End Sub
В этом случае есть два именованных диапазона, содержащих (разные) списки проверки данных. Как только пользователь щелкнет ячейку, будет выполнена проверка, использует ли эта ячейка проверку данных. В этом случае вырезание и вставка будут отключены, и CutCopyMode будет очищаться до тех пор, пока пользователь не выберет другую ячейку.
Важно, чтобы получить текущий CutCopyMode ДО того, как будет выполнен любой VBA-код, который что-то изменит, так как VBA автоматически изменится CutCopyMode из xlCut или xlCopy в 0, когда что-то меняется. Это начальное состояние требуется, чтобы избежать вставки раскрывающегося списка поверх другого.
Подпрограмма Worksheet_SelectionChange содержит код SKIPPED, который выполняет нечто подобное, если пользователь обращается к ячейке в одном из двух диапазонов. Он также содержит (превращенный в комментарий) код для выполнения дополнительных действий, когда пользователь выбирает ячейку. Этот код также может быть помещен в worksheet_Change