将范围变量传递给有关宏Excel中多重依赖关系的公式

时间:2015-08-08 04:05:22

标签: excel excel-vba excel-formula excel-2010 excel-2007 vba

以下是我的excel的代码

虽然通过宏创建多个依赖项,但我在

上遇到错误
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="=indirect("A" & i)"

仍然试图弄清楚如何将范围值传递到公式部分

Sub listing()

Dim cellv As Range

For i = 3 To 10000

Set cella = Sheet1.Range("A" & i)
    With cella.Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="=Main"
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = "Invalid Input"
        .InputMessage = ""
        .ErrorMessage = "Select the location only from the dropdown list."
        .ShowInput = False
        .ShowError = True
    End With

Set cellb = Sheet1.Range("B" & i)
    With cellb.Validation
        .Delete
        .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Operator:=xlBetween, Formula1:="=indirect("A" & i)"
        .IgnoreBlank = True
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = "Invalid Input"
        .InputMessage = ""
        .ErrorMessage = "Select the location only from the dropdown list."
        .ShowInput = False
        .ShowError = True
    End With

Next

End Sub

2 个答案:

答案 0 :(得分:0)

如果我的理解是正确的,你有以下几点:

  1. 名为Main的定义名称,其中包含已定义名称或范围列表
  2. 这是您想要实现的目标:

    1. 指向已定义名称A的列Main中的数据验证,以便用户从其包含的已定义名称中进行选择。
    2. B中的数据验证,指向在A列中相邻单元格中选择的已定义名称
    3. 现在,您在评论的回答中提到1000 cells,但您的代码已For i = 3 To 10000

      然而,想到的问题很少:

      此工作簿是否可以同时使用1000个定义的名称?

      您的用户是否会手动从其他1000个已定义名称中选择1000个项目?

      这个清单的用途是什么?

      还要记住(正如@JoeMalpass今天提醒我的那样)

        

      使用INDIRECT非常适合小型数据集,它可以使事情成为现实   在较大的床单上有点迟钝,因为它是一个易变的功能   需要在工作簿中的任何更改时重新计算(甚至   对使用或者没有影响的单元格所做的更改   由间接函数引用。)

      在您的情况下,您计划在至少1000个单元格中使用INDIRECT函数。我不是在试图挑战你的解决方案,但是我想,既然你正在使用VBA,那么应该有其他更实用的方法来满足你的需求。 在这方面,我将以分开的答案为您提供VBA解决方案

      基于以上内容,让我们继续您的代码。您的代码有两个错误:

      1. 在B列的数据验证的“Formula1”中,INDIRECT公式的串联需要是数据类型Variant,因此将其更改为:

        Formula1:="=INDIRECT(" & CVar("A" & i) & ")"

      2. 第二个错误是尝试手动创建此数据验证时触发的同一错误:

      3.   

        Source目前正在评估错误。

        enter image description here

        图。 1

        这基本上意味着数据验证指向名为“” (空白)的不存在的定义名称。 手动执行此操作后,您可以选择继续并创建数据验证,并在用户使用有效的定义名称更新“源”单元格后最终符合所需目的。但是,VB中的此错误不允许创建数据验证。

        可以通过为列A中的每个源单元格临时分配一个已知名称(即Main)来修复此问题,并在创建列B中的数据验证后将其清除

        以下是修订后的代码 还添加了过程Process_IniEnd以使代码运行得更快

        Option Explicit
        
        Sub DataValidation_Indirect()
        Const kRow As Integer = 1000
        Dim CllA As Range, CllB As Range
        Dim i As Integer
        
            Process_IniEnd 1
        
            Rem Clear Target Cells in Columns A & B
            ThisWorkbook.Sheets(1).Range(Cells(3, 1), Cells(kRow, 2)).Clear  'Replace [ThisWorkbook.Sheets(1)] as required
        
            For i = 3 To kRow
        
                Rem Set Cell A in Columns A
                Set CllA = ThisWorkbook.Sheets(1).Range("A" & i)    'Replace [ThisWorkbook.Sheets(1)] as required
        
                Rem Set Validation in Cell A
                With CllA.Validation
                    .Delete
                    .Add Type:=xlValidateList, _
                        AlertStyle:=xlValidAlertStop, _
                        Operator:=xlBetween, _
                        Formula1:="=Main"
                    .IgnoreBlank = True
                    .InCellDropdown = True
                    .InputTitle = ""
                    .ErrorTitle = "Invalid Input"
                    .InputMessage = ""
                    .ErrorMessage = "Select the location only from the dropdown list."
                    .ShowInput = False
                    .ShowError = True
                End With
        
                Rem Enter Temporary Name in Cell A
                CllA.Value = "Main"
        
                Rem Set Cell B in Columns B
                Set CllB = ThisWorkbook.Sheets(1).Range("B" & i)    'Replace [ThisWorkbook.Sheets(1)] as required
        
                Rem Set Validation in Cell B
                With CllB.Validation
                    .Delete
                    .Add Type:=xlValidateList, _
                        AlertStyle:=xlValidAlertStop, _
                        Operator:=xlBetween, _
                        Formula1:="=INDIRECT(" & CVar("A" & i) & ")"
                    .IgnoreBlank = True
                    .InCellDropdown = True
                    .InputTitle = ""
                    .ErrorTitle = "Invalid Input"
                    .InputMessage = ""
                    .ErrorMessage = "Select the location only from the dropdown list."
                    .ShowInput = False
                    .ShowError = True
                End With
        
                Rem Clear Temporary Name in Cell A
                CllA.ClearContents
        
            Next
        
            Process_IniEnd 0
        
        End Sub
        
        
        Sub Process_IniEnd(blIni As Boolean)
            Select Case blIni
            Case True
                With Application
                    .Calculation = xlManual
                    .EnableEvents = False
                    .DisplayAlerts = False
                    .ScreenUpdating = False
                End With
        
            Case False
                With Application
                    .EnableEvents = True
                    .DisplayAlerts = True
                    .ScreenUpdating = True
                    .Calculation = xlAutomatic
                End With
            End Select
        End Sub
        

答案 1 :(得分:0)

如果我的理解是正确的,你有以下几点:

  1. 名为Main的已定义名称,其中包含已定义名称或范围列表
  2. 这是您想要实现的目标:

    1. 指向已定义名称“A”的列Main中的数据验证,以便用户从其包含的已定义名称中进行选择
    2. B中的数据验证,指向在A列中相邻单元格中选择的已定义名称
    3. 基于上述情况,我建议当用户在Worksheet_Change

      中选择定义名称时,使用B事件在列A中创建数据验证

      此解决方案需要:

      1. 在列A
      2. 中创建数据验证的过程
      3. 通过B事件传递的更改验证范围,在列Worksheet_Change中创建数据验证的过程
      4. 将以下代码粘贴到工作表的VB代码中。 (要激活工作表的VB代码,请右键单击工作表的选项卡,然后选择“查看代码”,参见图1)

        enter image description here 图1

        Option Explicit
        
        Private Sub Worksheet_Change(ByVal RngSrc As Range)
            WshEvn_DataValidation RngSrc
        End Sub
        

        然后将以下代码粘贴到同一工作簿中的VB模块

        Option Explicit
        
        Const kRow As Integer = 1000
        
        
        Sub DataValidation_Main()
        Dim CllA As Range
        Dim i As Integer
        
            Debug.Print "Ini: "; Now
            Process_IniEnd 1
        
            Rem Clear Target Cells in Columns A & B
            ThisWorkbook.Sheets(1).Range(Cells(3, 1), Cells(kRow, 2)).Clear  'Replace [ThisWorkbook.Sheets(1)] as required
        
            For i = 3 To kRow
                Rem Set Cell A in Columns A
                Set CllA = ThisWorkbook.Sheets(1).Range("A" & i)    'Replace [ThisWorkbook.Sheets(1)] as required
        
                Rem Set Validation in Cell A
                With CllA.Validation
                    .Delete
                    .Add Type:=xlValidateList, _
                        AlertStyle:=xlValidAlertStop, _
                        Operator:=xlBetween, _
                        Formula1:="=Main"
                    .IgnoreBlank = True
                    .InCellDropdown = True
                    .InputTitle = ""
                    .ErrorTitle = "Invalid Input"
                    .InputMessage = ""
                    .ErrorMessage = "Select the location only from the dropdown list."
                    .ShowInput = False
                    .ShowError = True
                End With
        
            Next
        
            Process_IniEnd 0
            Debug.Print "End: "; Now
        
        End Sub
        
        
        Sub WshEvn_DataValidation(ByVal RngSrc As Range)
        Dim RngTrg As Range
        Dim rCll As Range
        
            Debug.Print "Ini: "; Now
            Process_IniEnd 1
        
                Rem Validate Source Range & Set Target Range
                Set RngTrg = Application.Intersect(RngSrc, RngSrc.Worksheet.Range(Cells(3, 1), Cells(kRow, 1)))
                If Not (RngTrg Is Nothing) Then
                    For Each rCll In RngTrg.Cells
        
                        Rem Set Validation in Column B
                        With rCll.Offset(0, 1).Validation
                            .Delete
                            On Error Resume Next
                            .Add Type:=xlValidateList, _
                                AlertStyle:=xlValidAlertStop, _
                                Operator:=xlBetween, _
                                Formula1:="=" & rCll.Value2
                            If Err.Number <> 0 Then GoTo NEXT_Cll
                            .IgnoreBlank = True
                            .InCellDropdown = True
                            .InputTitle = ""
                            .ErrorTitle = "Invalid Input"
                            .InputMessage = ""
                            .ErrorMessage = "Select the location only from the dropdown list."
                            .ShowInput = False
                            .ShowError = True
                        End With
        NEXT_Cll:
            Next: End If
        
            Process_IniEnd 0
            Debug.Print "End: "; Now
        
        End Sub
        
        Sub Process_IniEnd(blIni As Boolean)
            Select Case blIni
            Case True
                With Application
                    .Calculation = xlManual
                    .EnableEvents = False
                    .DisplayAlerts = False
                    .ScreenUpdating = False
                End With
        
            Case False
                With Application
                    .EnableEvents = True
                    .DisplayAlerts = True
                    .ScreenUpdating = True
                    .Calculation = xlAutomatic
                End With
            End Select
        End Sub