【问题标题】:Unable to set the Visible property of the PivotItem class (VBA)无法设置 PivotItem 类 (VBA) 的 Visible 属性
【发布时间】:2012-07-13 04:46:43
【问题描述】:

我正在尝试通过 VBA 操作 Excel 2007 数据透视表,因此我可以循环遍历数据透视表的类别,将所有内容设置为不可见,但将工作表另存为 pdf 并继续下一个类别。为此,我使用以下代码。

Dim pf As PivotField
Set pf = ActiveSheet.PivotTables("PivotTable1").PivotFields("NAME")

Dim pi as PivotItem
For Each pi In pf.PivotItems

    If pi.Visible = False Then
        pi.Visible = True 'Error here
    End If

    Dim pi2 As PivotItem
    For Each pi2 In pf.PivotItems
        If pi2 <> pi Then
            pi2.Visible = False
        End If
    Next pi2

    'Saving to PDF goes here
Next pi

循环似乎是第一次工作。每个类别都被取消选择,但第一个类别会输出一个漂亮的 PDF 文件。下次它进入循环时,它会在指示的行出现“无法设置 PivotItem 类的 Visible 属性”错误。我知道在数据透视表中必须至少选择一个项目,但这不是问题,因为我试图将可见性设置为 TRUE 而不是 FALSE。

我尝试通过检查它来修复它,因为您可能不允许将已经可见的 PivotItem 设置为可见,但这似乎不起作用。

任何帮助将不胜感激!

【问题讨论】:

  • 如果您注释掉创建 PDF 的部分,它是否可以正常工作?
  • 您使用的是什么版本的 Excel?

标签: vba excel pivot-table


【解决方案1】:

检查 PivotItem 的方向。如果方向为 xlHidden,我相信您无法将 Visible 设置为 True。如果是这样,那么只需先将方向更改为其他内容。

【讨论】:

    【解决方案2】:

    我知道这已经过时了,但想为那些在未来寻找解决方案的人做出贡献。

    我遇到了同样的错误,我想出的解决方案是在开始您的 pivotitem 循环之前刷新数据透视表。

    试试下面这行代码:

    ActiveSheet.PivotTables("PivotTable1").RefreshTable
    

    【讨论】:

    • 嗨 Ben,欢迎来到 Stack Overflow! +1 建设性的答案。确保将所有代码放在代码块中(在将代码输入到答案文本字段时,只需在代码前放置 4 个空格)以便于阅读。
    【解决方案3】:

    这是由于 Pivot 表使用缓存的数据透视项目而不是当前数据。确保桌子没有保留任何旧物品。为此,请右键单击您的数据透视表,单击“数据”选项卡并将“每个字段保留的项目数”设置为“无”。在 VBA 中执行此操作的代码是:

    Dim pt As PivotTable
    
    pt.PivotCache.MissingItemsLimit = xlMissingItemsNone
    

    【讨论】:

      【解决方案4】:

      可能有以下情况之一:

      • 您至少需要一个可见的 PivotItem,并且您将它们全部设置为不可见
      • PivotField 的方向 == XlPivotFieldOrientation.xlHidden (0)
      • PivotField 的 AutoSortOrder != Constants.xlManual (-4135)

      您可以在下面找到 C# 中的帮助函数示例,用于通过特定的数据透视项过滤数据透视字段:

      public static void FilterPivotItems(PivotField pf, List<string> pivotItemNames)
      {
          PivotItems pis = pf.ChildItems;
      
          // Orientation != XlPivotFieldOrientation.xlHidden and we need to filter by at least one value (as Excel implies)
          if (pf.Orientation != 0 && pivotItemNames.Count > 0)
          {
              int oldAutoSortOrder = 0;
      
              if (pf.AutoSortOrder != (int)Constants.xlManual)
              {
                  oldAutoSortOrder = pf.AutoSortOrder;
                  pf.AutoSort((int)Constants.xlManual, pf.Name);
              }
      
              int pivotItemsCount = pf.PivotItems().Count;
              List<int> pivotItemsToHide = new List<int>();
      
              for (int i = 1; i <= pivotItemsCount; i++)
              {
                  PivotItem pi = pf.PivotItems(i);
      
                  // check if current pivot item needs to be hidden (if it exists in pivotItemNames)
                  var match = pivotItemNames.FirstOrDefault(stringToCheck => stringToCheck.Equals(pi.Value));
      
                  if (match == null)
                  {
                      // hide these pivot items later because we can hit exception "Unable to set the Visible property of the PivotItem class"
                      // (this happens because all pivot items get hidden and we need to have at least one visible)
                      pivotItemsToHide.Add(i);
                  }
                  else
                  {
                      TryFilterPivotItems(pi, true, true);
                  }
              }
      
              for (int i = 0; i < pivotItemsToHide.Count; i++)
              {
                  PivotItem pi = pf.PivotItems(pivotItemsToHide[i]);
                  TryFilterPivotItems(pi, false, true);
              }
      
              if (oldAutoSortOrder != 0)
              {
                  pf.AutoSort(oldAutoSortOrder, pf.Name);
              }
      
              PivotTable pt = pf.Parent as PivotTable;
              if (pt != null)
              {
                  pt.Update();
              }
          }
      }
      
      public static void TryFilterPivotItems(PivotItem currentPI, bool filterValue, bool deferLayoutUpdate = false)
      {
          try
          {
              PivotField pf = currentPI.Parent;
              PivotTable pt = pf.Parent as PivotTable;
      
              if (currentPI.Visible != filterValue)
              {
                  if (deferLayoutUpdate == true && pt != null)
                  {
                      // just keep these three lines stick together, no if, no nothing (otherwise ManualUpdate will reset back to false)
                      pt.ManualUpdate = true;
                      currentPI.Visible = filterValue;
      
                      // this may be redundant since setting Visible property of pivot item, resets ManualUpdate to false
                      pt.ManualUpdate = false;
                  }
                  else
                  {
                      currentPI.Visible = filterValue;
                  }
              }
          }
          catch (Exception ex)
          {
      
          }
      }
      
      public static void TryFilterPivotItems(PivotField pf, string itemValue, bool filterValue, bool deferLayoutUpdate = false)
      {
          try
          {
              PivotItem currentPI = pf.PivotItems(itemValue);
              TryFilterPivotItems(currentPI, filterValue, deferLayoutUpdate);
          }
          catch (Exception ex)
          {
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        如果没有其他可见的 PivotItem,则不能使 PivotItem 不可见。

        即你不能隐藏最后一个。

        【讨论】:

        • 哇,这是我很久以来第一次发帖! ;)
        猜你喜欢
        • 1970-01-01
        • 2016-11-29
        • 2017-05-06
        • 1970-01-01
        • 1970-01-01
        • 2015-12-29
        • 2015-11-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多