IntroductionGetting StartedAll PostsNotesAbout The Author
Sharing Data Without Sharing A Workbook
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

<< Navigate to Monday, August 03, 2009 Add New Comment
No records found        
Add New Comment
Your name   
Subject   
Content   
*Required fields

January, 2009
February, 2009
March, 2009
April, 2009
May, 2009
June, 2009
July, 2009
August, 2009
September, 2009
October, 2009
November, 2009
December, 2009
IntroductionGetting StartedAll PostsNotesAbout The Author