Проблема с вызовом процедуры из Workbook_SheetChange

Я создал книгу с несколькими листами, требующими многочисленных двусторонних связанных ячеек на разных листах в одной книге. Итак, если я отредактирую ячейку B5 на листе A, она автоматически обновит ячейку J2 на листе B с тем же значением. И наоборот, если я обновлю ячейку J2 на листе B, она автоматически обновит ячейку B5 на листе A. Чтобы реализовать двустороннюю связь, я включил следующий код в ThisWorkbook:

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Sh.Name = "Smith,Joe" Then
        If Not Application.Intersect(Target, Range("B4")) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = "SomeProject" Then
                Sheets("Smith,Joe").Range("B4") = Target
            Else
                Sheets("SomeProject").Range("B10") = Target
            End If
            Application.EnableEvents = True
        End If
    End If
    If Sh.Name = "SomeProject" Then
        If Not Application.Intersect(Target, Range("B10")) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = "Smith,Joe" Then
                Sheets("SomeProject").Range("B10") = Target
            Else
                Sheets("Smith,Joe").Range("B4") = Target
            End If
            Application.EnableEvents = True
        End If
    End If
    If Sh.Name = "Smith,Joe" Then
        If Not Application.Intersect(Target, Range("C4")) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = "SomeProject" Then
                Sheets("Smith,Joe").Range("C4") = Target
            Else
                Sheets("SomeProject").Range("D10") = Target
            End If
            Application.EnableEvents = True
        End If
    End If
    If Sh.Name = "SomeProject" Then
        If Not Application.Intersect(Target, Range("D10")) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = "Smith,Joe" Then
                Sheets("SomeProject").Range("D10") = Target
            Else
                Sheets("Smith,Joe").Range("C4") = Target
            End If
            Application.EnableEvents = True
        End If
    End IF
    'This continues with for many different people/projects
End Sub

Это работало без проблем, пока процедура не натолкнулась на ограничение в 64 КБ (узнал об этом на форуме). Чтобы обойти ограничение, я создал несколько отдельных процедур, вызываемых из основного процесса, но ячейки больше не обновляются автоматически. После бесчисленных ошибок и посещений множества форумов я пришел к выводу, что WorkSheet_Change в ThisWorkbook вызывает управляющий процесс в модуле, и все ссылки на рабочие листы и ячейки передаются в качестве переменных. Он по-прежнему больше не обновляет ячейки ни на одном листе. В настоящее время я получаю ошибку времени выполнения 91 (переменная объекта или переменная блока не установлена), когда я прохожу код модуля в подразделе ChangeLogic.

Код ThisWorkbook:

Option Explicit

Public Sh As Object
Public Target As Range
Public ResourceSheet As Object
Public ProjectSheet As Object
Public ResourceCell As String
Public ProjectCell As String

Private Sub Worksheet_Change(ByVal Sh As Object, ByVal Target As Range)

   Run "Main"

End Sub

Код в "Основном" модуле:

Sub Main()

    Call JoeMain

End Sub

Sub JoeMain()

    Set ResourceSheet = Sheets("Smith,Joe")
    Set ProjectSheet = Sheets("SomeProject")

    Call Joe1
    Call ChangeLogic(Sh, Target, ResourceSheet, ProjectSheet, ResourceCell, ProjectCell)

    Call Joe2
    Call ChangeLogic(Sh, Target, ResourceSheet, ProjectSheet, ResourceCell, ProjectCell)

    'Continues on for all cases involing Joe Smith.  I haven't gotten to iterating through project names as of yet

End Sub

Sub Joe1()

    ResourceCell = "B4"
    ProjectCell = "B10"

End Sub

Sub Joe2()

    ResourceCell = "C4"
    ProjectCell = "D10"

End Sub

Sub ChangeLogic(Sh, Target, ResourceSheet, ProjectSheet, ResourceCell, ProjectCell)
    If Sh.Name = ResourceSheet.Name Then
        If Not Application.Intersect(Target, Range(ResourceCell)) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = ProjectSheet.Name Then
                Sheets(ResourceSheet.Name).Range(ResourceCell) = Target
            Else
                Sheets(ProjectSheet.Name).Range(ProjectCell) = Target
            End If
            Application.EnableEvents = True
        End If
    End If
    If Sh.Name = ProjectSheet.Name Then
        If Not Application.Intersect(Target, Range(ProjectCell)) Is Nothing Then
            Application.EnableEvents = False
            If Target.Parent.Name = ResourceSheet.Name Then
            Sheets(ProjectSheet.Name).Range(ProjectCell) = Target
            Else
                Sheets(ResourceSheet.Name).Range(ResourceCell) = Target
            End If
            Application.EnableEvents = True
        End If
    End If
End Sub

В этот момент мои цвета новичка показывают, и я выше головы. Любые предложения о том, что я делаю неправильно и как я могу заставить это работать?

Спасибо.


person Ovalstar    schedule 08.11.2013    source источник
comment
Что вы хотите, чтобы он делал, и что он делает вместо этого?   -  person Sam    schedule 08.11.2013
comment
Привет Сэм. Извините за неясность в посте. Я пытаюсь создать двусторонние ссылки между ячейками на разных листах в одной книге. Итак, если я отредактирую ячейку B5 на листе A, она автоматически обновит ячейку J2 на листе B с тем же значением. И наоборот, если я обновлю ячейку J2 на листе B, она автоматически обновит ячейку B5 на листе A. Я добавлю это в пост. Спасибо   -  person Ovalstar    schedule 08.11.2013
comment
Что касается того, что он делает ... он не обновляется ни на одном листе, как только я начал вызывать процесс из процесса. Я внес несколько изменений в код, основанный на различных проблемах. В настоящее время я получаю ошибку времени выполнения 91 (переменная объекта или переменная блока не установлена), когда я прохожу код модуля в подразделе ChangeLogic.   -  person Ovalstar    schedule 08.11.2013
comment
Birds View: POINT ONE В Sub ChangeLogic(Sh, Target, ResourceSheet, ProjectSheet, ResourceCell, ProjectCell) объявите ResourceSheet As Worksheet и аналогичным образом объявите другие объекты/переменные. POINT TWO код находится в основном модуле. Как он поймет, что такое Target или что такое Sh? Я вижу, вы установили другие объекты/переменные, но как насчет этих двух? POINT THREE И как вам удалось достичь лимита в 64 КБ? Я вижу много ненужного Application.EnableEvents = False/True Я уверен, что есть и другие ненужные фрагменты кода.   -  person Siddharth Rout    schedule 08.11.2013
comment
CONTD FROM ABOVE... Ваш внутренний 5-строчный IF/ENDIF можно заменить на 2-строчный. Ваш основной IF/Endif может использовать ESLEIF. Это гарантирует, что вам не нужны дополнительные ENDIFS. В качестве альтернативы вы можете использовать SELECT CASE   -  person Siddharth Rout    schedule 08.11.2013
comment
Привет Сиддхарт. Только что попробовал... получил ошибку компиляции: повторяющееся объявление в текущей области. Предполагая, что это произошло потому, что я объявил их общедоступными в ThisWorkbook. Я удалил публичные объявления и получил ту же ошибку msg. Какие-нибудь мысли?   -  person Ovalstar    schedule 08.11.2013
comment
Привет Сиддхарт. Для пунктов 1 и 2. Я объявил все переменные общедоступными в ThisWorksheet. Я переместил объявления в ChangeLogic, но теперь получаю сообщение об ошибке компиляции: повторяющееся объявление в текущей области. Что касается пункта 3, я не включил все экземпляры проекта/человека/рабочего листа/ячейки, которые будут использоваться для краткости. Спасибо   -  person Ovalstar    schedule 08.11.2013
comment
Почему вы проверяете имя листа? Затем, как только вы узнаете имя листа, проверьте, является ли оно чем-то другим? Вот почему вы тратите столько строк   -  person user2140261    schedule 08.11.2013
comment
Я могу неправильно понять проблему. Но зачем вам это нужно делать в коде, вы не можете обновить соответствующие ячейки, просто связав их с формулой?   -  person Sam    schedule 09.11.2013
comment
Я не могу, потому что любую ячейку можно обновить вручную. Это обновление перезапишет формулу в ячейке. Что я пытаюсь сделать: в Worksheet1 обновление ячейки A1 автоматически обновляет ячейку B3 в Worksheet2. И наоборот, в Worksheet2 обновление ячейки B3 автоматически обновляет ячейку A1 в Worksheet1.   -  person Ovalstar    schedule 11.11.2013


Ответы (1)


Я устал печатать комментарии, так что я мог бы также напечатать здесь и сделать более понятным то, что я говорю.

Я не уверен, как вы достигли предела 64 КБ. Как упоминалось в комментариях выше, вы можете написать свой код более структурированным/компактным. В настоящее время ваш код состоит из 44 строк, исключая Sub/End Sub/Comments. Тот же код можно записать в 24 строк.

Так что это прямая экономия 20 строк!!!.

Представьте, насколько уменьшится ваш окончательный код, когда вы удалите все ненужные Application.EnableEvents/IF-ENDIF.

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    On Error GoTo Whoa

    Application.EnableEvents = False

    Select Case Sh.Name
    Case "Smith,Joe"
        If Not Application.Intersect(Target, Range("B4")) Is Nothing Then _
        If Target.Parent.Name = "SomeProject" Then Sheets("Smith,Joe").Range("B4") = Target Else _
        Sheets("SomeProject").Range("B10") = Target

        If Not Application.Intersect(Target, Range("C4")) Is Nothing Then _
        If Target.Parent.Name = "SomeProject" Then Sheets("Smith,Joe").Range("C4") = Target Else _
        Sheets("SomeProject").Range("D10") = Target
    Case "SomeProject"
        If Not Application.Intersect(Target, Range("B10")) Is Nothing Then _
        If Target.Parent.Name = "Smith,Joe" Then Sheets("SomeProject").Range("B10") = Target Else _
        Sheets("Smith,Joe").Range("B4") = Target

        If Not Application.Intersect(Target, Range("D10")) Is Nothing Then _
        If Target.Parent.Name = "Smith,Joe" Then Sheets("SomeProject").Range("D10") = Target Else _
        Sheets("Smith,Joe").Range("C4") = Target

        'This continues with for many different people/projects
    End Select
LetsContinue:
    Application.EnableEvents = True
    Exit Sub
Whoa:
    MsgBox Err.Description
    Resume LetsContinue
End Sub
person Siddharth Rout    schedule 08.11.2013
comment
По сути, это то, что я сделал в своем исходном примере кода (хотя и не так эффективно, как ваш пример). Проблема в том, что у меня слишком много дел (8 рабочих листов проекта * 20 рабочих листов * 12 ячеек), из-за чего я столкнулся с ограничением в 64 КБ. Спасибо - person Ovalstar; 08.11.2013
comment
Обновите страницу. Если есть 8 рабочих листов, то у вас не может быть более 8 дел ;) Вам нужно сгруппировать их, как я сделал выше... - person Siddharth Rout; 08.11.2013
comment
Родительским именем диапазона является рабочий лист. Какова цель тестирования, если лист SomeProject ПОСЛЕ уже получает истинное утверждение о том, что дело Smith,Joe - person user2140261; 08.11.2013
comment
@ user2140261: Верно, но я пока не вникаю в это. На самом деле весь If Target.Parent.Name = "SomeProject" Then Sheets("Smith,Joe").Range("B4") = Target Else _ Sheets("SomeProject").Range("B10") = Target не имеет смысла, но это не имеет значения. Я демонстрирую, как сжать код, чтобы он не достигал предела в 64 КБ. - person Siddharth Rout; 08.11.2013
comment
Привет Сиддхарт. Я ценю ваше время в написании примера выше. Я прошел и заменил свой код на ваш, и, хотя я смог пройти больше дел, чем раньше, я все еще достиг предела в 64 КБ. Дело в том, что у меня просто слишком много дел для одного проца. Любые предложения по исходной проблеме правильного разделения дел на модуль, который можно вызывать из Workbook_SheetChange в ThisWorkbook? Спасибо еще раз. - person Ovalstar; 08.11.2013
comment
@Ovalstar: Конечно, я могу предложить вам альтернативу, но перед этим вы можете объяснить мне, почему у вас больше 8 дел? Поскольку у вас 8 листов, у вас не может быть больше 8 дел? Или Могу я увидеть вашу рабочую тетрадь? Если да, можете ли вы поделиться им на wikisend.com и поделиться ссылкой здесь - person Siddharth Rout; 08.11.2013
comment
Рабочая тетрадь предназначена для управления ресурсами. У каждого ресурса (человека) есть рабочий лист со списком всех проектов и соответствующей ячейкой для каждого месяца года (20 ресурсов * 8 проектов * 12 месяцев = 1920 случаев). И наоборот, у каждого проекта есть рабочий лист, который включает каждый ресурс с соответствующей ячейкой для каждого месяца года (еще 1920 случаев). - person Ovalstar; 09.11.2013
comment
Я думаю, что либо я не понимаю вашу точку зрения, либо вы не понимаете мою точку зрения :) Сколько там листов? - person Siddharth Rout; 09.11.2013
comment
Есть 8 листов проекта и 20 листов ресурсов. На каждом листе ресурсов перечислены все проекты по вертикальной оси и каждый месяц года по горизонтальной оси. Каждый лист проекта перечисляет каждый ресурс по вертикальной оси и каждый месяц по горизонтальной оси. Каждая ячейка в этих сетках представляет случай, который необходимо учитывать в процедуре. Их слишком много, чтобы избежать превышения лимита в 64 КБ. Поэтому я ищу правильный способ разбить случаи в модуле и вызвать их событие Workbook_SheetChange в ThisWorkbook. Это возможно или есть ограничения? - person Ovalstar; 11.11.2013