Hier ist, was ich gefunden habe (alle Excel 2003)
Alle Arbeitsblätter in meiner Arbeitsmappe erfordern eine komplexe Validierung sind in Tabellenform mit ein paar Kopfzeilen mit Blatt Titel und Spaltentitel organisiert. Alle Spalten rechts von der letzten sind ausgeblendet, und alle Zeilen unterhalb einer praktischen Grenze (in meinem Fall 200 Zeilen) sind ebenfalls ausgeblendet. Ich habe folgende Module ein:
- GlobalDefs ... Aufzählungen
- CommonFunctions ... verwendete Funktionen durch alle Blätter
- Sheet_X_Functions ...Funktionen insbesondere auf ein einzelnes Blatt
- und Ereignis löst in Sheet_X selbst
Die Aufzählungen rein Zweck der Vermeidung dienen, zu codieren; Wenn ich Spalten hinzufügen oder entfernen möchte, bearbeite ich meistens die Enums, während ich im realen Code die symbolischen Namen für jede Spalte verwende. Das hört sich vielleicht etwas übertrieben an, aber ich habe gelernt, es zu lieben, als Benutzer zum dritten Mal kamen und bat mich, die Tabellenlayouts zu ändern.
' module GlobalDefs
Public Enum T_Sheet_X
NofHRows = 3 ' number of header rows
NofCols = 36 ' number of columns
MaxData = 203 ' last row validated
GroupNo = 1 ' symbolic name of 1st column
CtyCode = 2 ' ...
Country = 3
MRegion = 4
PRegion = 5
City = 6
SiteType = 7
' etc
End Enum
Zuerst beschreibe ich Code, der Ereignis ausgelöst wird.
Vorschläge in diesem Thread sollten PASTE-Aktivitäten abfangen. Nicht wirklich unterstützt von einem Event-Trigger in Excel-2003, aber letztendlich kein großes Wunder. Das Einfangen/Entnehmen der PASTE erfolgt beim Aktivieren/Deaktivieren von Ereignissen in Sheet_X. Bei Deaktivierung überprüfe ich auch den Schutzstatus. Wenn ungeschützt, bitte ich den Benutzer, einer Batch-Validierung zuzustimmen und erneut zu schützen. Single-Line-Validierung und Batch-Validierung Routinen sind dann Code-Objekte im Modul Sheet_X_Functions weiter unten beschrieben.
' object in Sheet_X
Private Sub Worksheet_Activate()
' suspend PASTE
Application.CommandBars("Edit").Controls("Paste").OnAction = "TrappedPaste" ' main menu
Application.CommandBars("Edit").Controls("Paste Special...").OnAction = "TrappedPaste" ' main menu
Application.CommandBars("Cell").Controls("Paste").OnAction = "TrappedPaste" ' context menu
Application.CommandBars("Cell").Controls("Paste Special...").OnAction = "TrappedPaste" ' context menu
Application.OnKey "^v", "TrappedPaste" ' key shortcut
End Sub
' object in Sheet_X
Private Sub Worksheet_Deactivate()
' checks protection state, performs batch validation if agreed by user, and restores normal PASTE behaviour
' writes a red reminder into cell A4 if sheet is left unvalidated/unprotected
Dim RetVal As Integer
If Not Me.ProtectContents Then
RetVal = MsgBox("Protection is currently turned off; sheet may contain inconsistent data" & vbCrLf & vbCrLf & _
"Press OK to validate sheet and protect" & vbCrLf & _
"Press CANCEL to continue at your own risk without protection and validation", vbExclamation + vbOKCancel, "Validation")
If RetVal = vbOK Then
' silent batch validation
Application.ScreenUpdating = False
Sheet_X_BatchValidate Me
Application.ScreenUpdating = True
Me.Cells(1, 4) = ""
Me.Cells(1, 4).Interior.ColorIndex = xlColorIndexNone
SetProtectionMode Me, True
Else
Me.Cells(1, 4) = "unvalidated"
Me.Cells(1, 4).Interior.ColorIndex = 3 ' red
End If
ElseIf Me.Cells(1, 4) = "unvalidated" Then
' silent batch validation ... user manually turned back protection
SetProtectionMode Me, False
Application.ScreenUpdating = False
Sheet_X_BatchValidate Me
Application.ScreenUpdating = True
Me.Cells(1, 4) = ""
Me.Cells(1, 4).Interior.ColorIndex = xlColorIndexNone
SetProtectionMode Me, True
End If
' important !! restore normal PASTE behaviour
Application.CommandBars("Edit").Controls("Paste").OnAction = ""
Application.CommandBars("Edit").Controls("Paste Special...").OnAction = ""
Application.CommandBars("Cell").Controls("Paste").OnAction = ""
Application.CommandBars("Cell").Controls("Paste Special...").OnAction = ""
Application.OnKey "^v"
End Sub
Modul Sheet_X_Functions enthält im Grunde der spezifischen Validierungsunter zu diesem Blatt. Beachten Sie die Verwendung von Enum ist hier - es ist wirklich für mich gelohnt - vor allem in der Sheet_X_ValidateRow Routine - Benutzer hat mich gezwungen, dies eine 100 Mal fühlte sich ändern;)
' module Sheet_X_Functions
Sub Sheet_X_BatchValidate(MySheet As Worksheet)
Dim VRow As Range
For Each VRow In MySheet.Rows
If VRow.Row > T_Sheet_X.NofHRows And VRow.Row <= T_Sheet_X.MaxData Then
Sheet_X_ValidateRow VRow, False ' silent validation
End If
Next
End Sub
Sub Sheet_X_ValidateRow(MyLine As Range, Verbose As Boolean)
' Verbose: TRUE .... display message boxes; FALSE .... keep quiet (for batch validations)
Dim IsValid As Boolean, Idx As Long, ProfSum As Variant
IsValid = True
If ContainsData(MyLine, T_Sheet_X.NofCols) Then
If MyLine.Cells(1, T_Sheet_X.Country) = "" Or _
MyLine.Cells(1, T_Sheet_X.City) = "" Or _
MyLine.Cells(1, T_Sheet_X.SiteType) = "" Then
If Verbose Then MsgBox "Site information incomplete", vbCritical + vbOKOnly, "Row validation"
IsValid = False
' ElseIf otherstuff
End If
' color code the validation result in 1st column
If IsValid Then
MyLine.Cells(1, 1).Interior.ColorIndex = xlColorIndexNone
Else
MyLine.Cells(1, 1).Interior.ColorIndex = 3 'red
End If
Else
' empty lines will resolve to valid, remove all color marks
MyLine.Cells(1, 1).EntireRow.Interior.ColorIndex = xlColorIndexNone
End If
End Sub
unterstützt Subs/Funktionen im Modul CommonFunctions, die aus aufgerufen werden Der obige Code
' module CommonFunctions
Sub TrappedPaste()
If ActiveSheet.ProtectContents Then
' as long as sheet is protected, we don't paste at all
MsgBox "Sheet is protected, all Paste/PasteSpecial functions are disabled." & vbCrLf & _
"At your own risk you may unprotect the sheet." & vbCrLf & _
"When unprotected, all Paste operations will implicitely be done as PasteSpecial/Values", _
vbOKOnly, "Paste"
Else
' silently do a PasteSpecial/Values
On Error Resume Next ' trap error due to empty buffer or other peculiar situations
Selection.PasteSpecial xlPasteValues
On Error GoTo 0
End If
End Sub
' module CommonFunctions
Sub SetProtectionMode(MySheet As Worksheet, ProtectionMode As Boolean)
' care for consistent protection
If ProtectionMode Then
MySheet.Protect DrawingObjects:=True, Contents:=True, _
AllowSorting:=True, AllowFiltering:=True
Else
MySheet.Unprotect
End If
End Sub
' module CommonFunctions
Function ContainsData(MyLine As Range, NOfCol As Integer) As Boolean
' returns TRUE if any field between 1 and NOfCol is not empty
Dim Idx As Integer
ContainsData = False
For Idx = 1 To NOfCol
If MyLine.Cells(1, Idx) <> "" Then
ContainsData = True
Exit For
End If
Next Idx
End Function
Eine wichtige Sache ist die Selection_Change. Wenn das Blatt geschützt ist, möchten wir die Zeile validieren, die der Benutzer gerade verlassen hat. Daher müssen wir die Zeilennummer, von der wir gekommen sind, verfolgen, da sich der TARGET-Parameter auf die NEUE Auswahl bezieht.
Wenn ungeschützt, könnte der Benutzer in die Kopfzeilen springen und herumspielen (obwohl es Zellensperren gibt, aber ....), also lassen wir ihn nicht den Cursor dort platzieren.
' objects in Sheet_X
Dim Sheet_X_CurLine As Long
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' trap initial move to sheet
If Sheet_X_CurLine = 0 Then Sheet_X_CurLine = Target.Row
' don't let them select any header row
If Target.Row <= T_Sheet_X.NofHRows Then
Me.Cells(T_Sheet_X.NofHRows + 1, Target.Column).Select
Sheet_X_CurLine = T_Sheet_X.NofHRows + 1
Exit Sub
End If
If Me.ProtectContents And Target.Row <> Sheet_X_CurLine Then
' if row is changing while protected
' validate old row
Application.ScreenUpdating = False
SetProtectionMode Me, False
Sheet_X_ValidateRow Me.Rows(Sheet_X_CurLine), True ' verbose validation
SetProtectionMode Me, True
Application.ScreenUpdating = True
End If
' in any case make the new row current
Sheet_X_CurLine = Target.Row
End Sub
Es gibt einen Worksheet_Change Code als auch in Sheet_X, wo ich dynamisch Werte in die Drop-Down-Listen der Felder der aktuellen Zeile auf der Eingabe von anderen Zellen auf Basis laden. Da diese sehr spezifisch ist, stelle ich nur den Rahmen hier, Important vorübergehend Ereignisverarbeitung auszusetzen rekursive Aufrufe zu ändern Trigger
Private Sub Worksheet_Change(ByVal Target As Range)
Dim IsProtected As Boolean
' capture current status
IsProtected = Me.ProtectContents
If Target.Row > T_FR.NofHRows And IsProtected Then ' don't trigger anything in header rows or when protection is turned off
SetProtectionMode Me, False ' because the trigger will change depending fields
Application.EnableEvents = False ' suspend event processing to prevent recursive calls
Select Case Target.Column
Case T_Sheet_X.CtyCode
' load cities applicable for country code entered
' Case T_Sheet_X. ... other stuff
End Select
Application.EnableEvents = True ' continue event processing
SetProtectionMode Me, True
End If
End Sub
das ist es zu vermeiden .... hoffe, dieser Beitrag sehr nützlich für einige von Ihnen ist Jungs
Viel Glück MikeD
wow. interessant. +1, um sich durch dieses Validierungsminenfeld zu kämpfen. zusätzliche Anerkennung. –
geehrt fühlen ... hoffe, Sie können die oben genannten selbst verwenden – MikeD