Создание рабочего листа VBA для работы с книгой - PullRequest
0 голосов
/ 19 сентября 2019

Я пытаюсь поместить VBA в объект книги, а не на каждый лист, но мне не везет.Я думаю, мне нужно использовать Private Sub Workbook_SheetChange (ByVal Sh As Object, ByVal Source As Range) , но не знаю, как реализовать.У кого-нибудь есть решение, чтобы этот код работал в «ThisWorkbook» вместо размещения его на каждом листе?

enter image description here

Dim xRg As Range
Private Sub Worksheet_Change(ByVal Target As Range)
    On Error Resume Next
    If Target.Cells.Count > 1 Then Exit Sub
    If Not Intersect(Target, Range("L13:L5000")) Is Nothing Then
            If IsDate(Target.Value) And Target.Value > 0 Then
               targetRow = Target.Row
               offsetRow = Target.Offset(9, 0).Row
               Dim bIsNinthRow As Boolean
                Dim ModResult As Long
                bIsNinthRow = False
                ModResult = (targetRow - 13) Mod 9
                If ModResult = 0 Then bIsNinthRow = True
                If bIsNinthRow Then Call Mail_small_Text_Outlook(targetRow, offsetRow)
            End If
    End If

End Sub
Sub Mail_small_Text_Outlook(targetRow, offsetRow)
    Dim xOutApp As Object
    Dim xOutMail As Object
    Dim xMailBody As String
    Set xOutApp = CreateObject("Outlook.Application")
    Set xOutMail = xOutApp.CreateItem(0)
    xMailBody = "Hello" & vbNewLine & vbNewLine & _
              "This client is now Committed & Complete and ready for your attention" & vbNewLine & vbNewLine & _
              "Renew As Is?" & vbNewLine & _
              "Adding Changing Groups?"


    On Error Resume Next
    With xOutMail
        .To = ""
        .CC = ""
        .BCC = ""
        .Subject = "Committed & Complete" & "  " & ActiveCell.Offset(-4, -11).Value & "  " & ActiveCell.Offset(-4, -9).Value
        .Body = xMailBody
        .Display   'or use .Send
    End With
    On Error GoTo 0
    Set xOutMail = Nothing
    Set xOutApp = Nothing
End Sub

1 Ответ

2 голосов
/ 20 сентября 2019

@ MathieuGuindon дал очень мудрый совет в комментариях, которые я приведу здесь:

НЕ при любых обстоятельствах не вводите обработчики событий вручную.

не уверен, как реализовать - единственное отличие состоит в том, что вы получаете параметр Sh, содержащий ссылку на измененный лист..... и это бесполезно, потому что вы уже можете получить это с Target.Parent.Единственное, о чем вам нужно беспокоиться, это о неявных ссылках ActiveSheet

Используйте вашу VBA IDE (ту версию / приложение / окно, из которой вы нашли свой скриншот).Откройте код для «ThisWorkbook».В верхней части этого окна кода вы увидите два раскрывающихся списка.

При выборе «Рабочая книга» в левом раскрывающемся списке и «SheetChange» в правом раскрывающемся списке автоматически будет опубликован этот код:

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

End Sub

Как видите, Target используется, а не Source, в автоматизированном тексте.Так что большая часть вашего кода не изменилась.В качестве примечания вы можете изменить его на «Source» или «FrostyTheSnowman» (спасибо - @MathieuGuindon), а затем соответствующим образом изменить свой код, но зачем делать дополнительную работу для себя (см. Примечание 1 в конце).

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Target.Cells.Count > 1 Then Exit Sub
        If Not Intersect(Target, Target.Parent.Range("L13:L5000")) Is Nothing Then
            If IsDate(Target.Value) And Target.Value > 0 Then
                targetRow = Target.Row
                offsetRow = Target.Offset(9, 0).Row
                Dim bIsNinthRow As Boolean
                Dim ModResult As Long
                bIsNinthRow = False
                ModResult = (targetRow - 13) Mod 9
                If ModResult = 0 Then bIsNinthRow = True
                If bIsNinthRow Then Call Mail_small_Text_Outlook(targetRow, offsetRow)
            End If
    End If
End Sub

Как видно из вышесказанного, я сделал только одно небольшое изменение - это квалифицирует одно утверждение.

        If Not Intersect(Target, Target.Parent.Range("L13:L5000")) Is Nothing Then

Я мог бы также использовать объект Sh (Intersect(Target, Sh.Range("L13:L5000"))), однако, для спокойствия потребуется проверка типов.

Но

Ваш текущий дизайн имеет небольшой недостаток - и это в вашей вспомогательной функции Sub Mail_small_Text_Outlook(targetRow, offsetRow).

Вы передаете два варианта в рутину, вы не используете эти варианты (что в настоящее время является для вас благословением), и мы не можем сказать, для чего они предназначены.Важно отметить, что ваш код использует конструкцию ActiveCell - но вы не можете гарантировать, какой будет активная ячейка, когда вы вызываете код.

У вас есть кости здесь, определите точный диапазон (или еще лучше,фактическое значение), которое вы хотите использовать в Mail_small_Text_Outlook, а затем использовать его.Это делает процедуру намного более пригодной для повторного использования в более позднюю дату, чем ваша текущая конструкция, которая опирается на жестко закодированное смещение.

Sub Mail_small_Text_Outlook(ByVal dataElement1 as String, ByVal dataElement2 as String) 'Meaningful names and types required, I am guessing.
    Dim xOutApp As Object
    Dim xOutMail As Object
    Dim xMailBody As String
    Set xOutApp = CreateObject("Outlook.Application")
    Set xOutMail = xOutApp.CreateItem(0)
    xMailBody = "Hello" & vbNewLine & vbNewLine & _
              "This client is now Committed & Complete and ready for your attention" & vbNewLine & vbNewLine & _
              "Renew As Is?" & vbNewLine & _
              "Adding Changing Groups?"


    With xOutMail
        .To = ""
        .CC = ""
        .BCC = ""
        .Subject = "Committed & Complete" & "  " & dataElement1  & "  " & dataElement2
        .Body = xMailBody
        .Display   'or use .Send
    End With
    Set xOutMail = Nothing
    Set xOutApp = Nothing
End Sub

Это означает небольшое изменение в вашей подпрограмме 'Change':

Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
    If Target.Cells.Count > 1 Then Exit Sub
        If Not Intersect(Target, Target.Parent.Range("L13:L5000")) Is Nothing Then
            If IsDate(Target.Value) And Target.Value > 0 Then
                Dim data1 as string, data2 as string
                data1 = Target.Offset(-4, -11).Value
                data2 = Target.Offset(-4, -9).Value
                If (Target.Row - 13) Mod 9 = 0 Then Mail_small_Text_Outlook(data1, data2)
            End If
    End If
End Sub

Я также убрал некоторые из ненужных строк - дополнительные объявления и т. Д. Не были неправильными, но все эти дополнительные шаги можно выполнить просто в одной строке, как показано.Если для каждой девятой строки есть причина разработки, то простой однострочный комментарий может объяснить это будущему сопровождающему кода.

Стандартные комментарии

Всегда. Всегда . Всегда . Всегда .Использование Option Explicit.

Call устарело и на одном этапе было отмечено в документах VBA как устаревшее.Это ненужный беспорядок.

Будьте осторожны с использованием операторов On Error, особенно в тех частях кода, где вы можете контролировать / проверять входные данные и самостоятельно управлять ожидаемыми ошибками.Это может скрыть основные ошибки кодирования, и вы будете часами искать что-то, когда не получите правильных результатов, или, что еще хуже, вы просто примете неправильные результаты, не зная, что произошла ошибка.

Примечание1: Для обработчиков событий важно, чтобы количество и типы параметров совпадали с описанием события.Имена переменных, используемых в сигнатуре обработчика событий (например, Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)), могут быть любыми.

Примечание 2: IDE - интегрированная среда разработки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...