|
Monday, August 03, 2009 - 3:31 PM
Sharing and VBA don't mix. At least with Excel '02/'03, sharing causes VBA to simply malfunction in ways that cannot or should not be coded around. Rather, I recommend you share your data in a separate shared workbook and keep your VBA in an unshared UI. This approach allows you to take advantage of Excel's built-in features for reconciling changes by mutliple users, without comprimising your VBA or otherwise affecting your UI. Multiple users can either have separate copies of the UI or use separate instances of it. I haven't had a chance to generalize this code yet, but you can get the gist of it from this post as it is now.
Private Sub RestoreOtherData() Dim subN&: subN = SubStart(NoEvents:=Events) On Error Resume Next Dim i&, ColumnNames, iName, ws, tempStr$, tempInt& ColumnNames = Array(Col1, Col2, Col3, Col4, Col5, Col6) With sT1Temp For Each iName In ColumnNames tempInt = cMatch(CStr(iName), .Name) If (Application.CountA(.Columns(tempInt)) > 1) Then tempStr = ColumnLetter(tempInt) tempStr = tempStr & "2:" & tempStr & Application.CountA(.Columns(1)) Call DistributeWSChanges(.Range(tempStr), .Name, VBACall) End If Next End With 'JUST CHANGED 'clear data for new T1 breaks With wsDS(1) '.Select 'not necessary bc dnoe by showt1breaks ShowT1Breaks (False) For Each iName In ColumnNames tempInt = cMatch(CStr(iName), .Name) .Range(Cells(2, tempInt), Cells(.UsedRange.Rows.Count, tempInt)).ClearContents Next End With
SubEnd (subN) End Sub
'Public Sub RefreshOtherData() ' Dim subN&: subN = SubStart(NoEvents:=Events) ''restore data stored temporarily in sT1Temp 'On Error Resume Next ' ' If Not WindowIsOpen(WBODFileName) Then PopGVs ' ' 'get data from shared wb ' With wbOD ' Windows(.Name).Visible = 1: .Activate: .Save 'refresh shared wb ' End With ' ActiveSheet.UsedRange.Copy ' ThisWorkbook.Activate ' With sT1Temp ' .Visible = 1 ' Application.Goto sT1Temp.[A1] ' Selection.PasteSpecial Paste:=xlPasteValues ' Windows(wbOD.Name).Visible = 0 ' .Visible = 0 ' End With ' ' Dim i&, ColumnNames, iName, tempStr$ '' ColumnNames = Array(Col1, Col2, Col3, Col4, Col5, Col6) Region) 'FirstDate, ' ColumnNames = DistributedCols ' With sT1Temp ' For Each iName In ColumnNames ' If (Application.CountA(.Columns(1)) > 1) Then ' tempStr = ColumnLetter(cMatch(CStr(iName), .Name)) ' tempStr = tempStr & "2:" & tempStr & Application.CountA(.Columns(1)) ' Call DistributeWSChanges(.Range(tempStr), .Name, VBACall) ' End If ' Next ' End With ' ' SubEnd (subN) 'End Sub
Public Sub DistributeWSChanges(ByVal Target As Range, inName$, Optional CalledByVBA As Boolean) With Application 'SubStart would be too slow If Not CalledByVBA Then .EnableEvents = 0: .ScreenUpdating = 0: ShowTaskPane (Show) End With On Error Resume Next 'only works when one column is changed at a time, but there is a test for that before this is called 'not calling PopEventGVs until change has been identified 'If (Target.Columns.Count > 1) Then GoTo ExitNow 'this isn't necessary bc test was already performed With Sheets(inName) Dim ColName$: ColName = .Cells(1, Target.Column) If Not fInArray(ColName, DistributedCols) Then GoTo ExitNow 'change was in another column so nothing to distribute End With If Not wsGVTest Then PopEventGVs Dim ws, tempVar, tempValue, sStatusBar$: sStatusBar = Application.StatusBar If (Target.Rows.Count = 1) Then 'only one change to distribute Application.StatusBar = "Distributing change to other sheets..." With Sheets(inName) For Each ws In aWSOut If (ws.Name <> .Name) Then tempVar = Application.Match(.Cells(Target.Row, 1), ws.Columns(1), 0) If IsNumeric(tempVar) Then If (tempVar > 1) Then ws.Cells(tempVar, cMatch(ColName, ws.Name)) = Target End If Next End With Else 'number of changes unknown (this would generally be triggered when user clears data, but could also be called if user pastes into multiple cells at once) If CalledByVBA Then If (inName = sT1Temp.Name) Then Application.StatusBar = "Refreshing user-inputted data..." Else Application.StatusBar = "Restoring user-inputted data..." End If Else Application.StatusBar = "Distributing mutliple changes to other sheets..." End If Dim s As Byte, i& 'get relevant column number for each ws in aWSOut Dim ColOut&(): ReDim ColOut(UBound(aWSOut)) For s = 1 To UBound(aWSOut) If (aWSOut(s).Name <> inName) Then ColOut(s) = cMatch(ColName, aWSOut(s).Name) End If Next 'distribute data With Sheets(inName) For s = 1 To UBound(aWSOut) If (aWSOut(s).Name <> inName) Then For i = 2 To Application.CountA(.Columns(1)) tempValue = .Cells(i, Target.Column) If Not IsEmpty(tempValue) Then tempVar = Application.Match(.Cells(i, 1), aWSOut(s).Columns(1), 0) If IsNumeric(tempVar) Then If (tempVar > 1) Then 'just in case With aWSOut(s).Cells(tempVar, ColOut(s)) .Value = tempValue .WrapText = False End With End If End If End If Next End If Next End With End If Application.StatusBar = sStatusBar ExitNow: With Application If Not CalledByVBA Then .EnableEvents = 1: .ScreenUpdating = 1: ShowTaskPane (Hide) End With End Sub
Private Sub SaveOtherDataToSharingFile() On Error Resume Next Dim subN&: subN = SubStart(NoWarnings:=Warnings) 'save other user-inputted data to sharing file
If Not WindowIsOpen(WBODFileName) Then PopGVs Windows(wbOD.Name).Visible = 1 wbOD.Activate Cells.Clear sT1Temp.Cells.Copy Cells(1, 1).Select Selection.PasteSpecial Paste:=xlPasteValues With wbOD .ExclusiveAccess: .Save 'clear old data by turning sharing off .SaveAs .Path & "\" & .Name, accessmode:=xlShared 'restore sharing End With Windows(wbOD.Name).Visible = 0
SubEnd (subN) End Sub
Goes in Worksheet Module: Public Sub StoreWSChanges(ByVal Target As Range, inName$) On Error Resume Next With Application 'SubStart would be too slow .EnableEvents = 0: .ScreenUpdating = 0: ShowTaskPane (Show) End With
If Not WindowIsOpen(WBODFileName) Then PopGVs With Sheets(inName) Dim ColName$: ColName = .Cells(1, Target.Column) If Not fInArray(ColName, DistributedCols) Then GoTo ExitNow 'change was in another column so nothing to distribute End With
Dim tempVar, tempValue, sStatusBar$: sStatusBar = Application.StatusBar If (Target.Rows.Count = 1) Then 'only one change to store 'store data in shared otherdata.xls Application.StatusBar = "Storing change..." tempVar = Application.Match(Sheets(inName).Cells(Target.Row, 1), wsOD.Columns(1), 0) If IsNumeric(tempVar) Then If (tempVar > 1) Then wsOD.Cells(tempVar, Application.Match(ColName, wsOD.Rows(1), 0)) = Target Else 'number of changes unknown (this would generally be triggered when user clears data, but could also be called if user pastes into multiple cells at once) 'store data in shared otherdata.xls Dim i&, ColOut&: ColOut = Application.Match(ColName, wsOD.Rows(1), 0) 'get relevant column number for shared wb Application.StatusBar = "Storing mutliple changes..." With Sheets(inName) For i = 2 To Application.CountA(.Columns(1)) tempValue = .Cells(i, Target.Column) If Not IsEmpty(tempValue) Then tempVar = Application.Match(.Cells(i, 1), wsOD.Columns(1), 0) If IsNumeric(tempVar) Then If (tempVar > 1) Then 'just in case With wsOD.Cells(tempVar, ColOut) .Value = tempValue: .WrapText = False End With End If End If End If Next End With End If Application.StatusBar = sStatusBar
ExitNow: With Application .EnableEvents = 1: .ScreenUpdating = 1: ShowTaskPane (Hide) End With End Sub
Goes in Worksheet Object(s): Private Sub Worksheet_Change(ByVal Target As Range) If (Target.Columns.Count = 1) Then Call StoreWSChanges(Target, Me.Name) End Sub
|