Подытоги Excel 2010, VBA и ListObjects не обновляются при изменении таблицы

Итак, имея эту структуру (начиная с A1-Show snippet > run):

table {
  border-color: #BBB;
  border-width: 0px 0px 1px 1px;
  border-style: dotted;
}
body {
  font: 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif;
  color: #333;
}
td {
  border-color: #BBB;
  border-width: 1px 1px 0px 0px;
  border-style: dotted;
  padding: 3px;
}
<table>
  <tbody>
    <tr>
      <th></th>
      <th>A</th>
      <th>B</th>
      <th>C</th>
      <th>D</th>
    </tr>
    <tr>
      <td>1</td>
      <td>Title 1</td>
      <td>Title 2</td>
      <td>Title 3</td>
      <td>Title 4</td>
    </tr>
    <tr>
      <td>2</td>
      <td>GH</td>
      <td>1</td>
      <td>434</td>
      <td>4</td>
    </tr>
    <tr>
      <td>3</td>
      <td>TH</td>
      <td>3</td>
      <td>435</td>
      <td>5</td>
    </tr>
    <tr>
      <td>4</td>
      <td>TH</td>
      <td>4</td>
      <td>4</td>
      <td>6</td>
    </tr>
    <tr>
      <td>5</td>
      <td>LH</td>
      <td>2</td>
      <td>0</td>
      <td>3</td>
    </tr>
    <tr>
      <td>6</td>
      <td>EH</td>
      <td>2</td>
      <td>5</td>
      <td>36</td>
    </tr>
  </tbody>
</table>

Я написал код для преобразования этого диапазона (A1: D6) в ListObject, добавил 4 новых столбца и промежуточные итоги:

Function test()

    Dim objLO As ListObject

    Set objLO = ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A:$D"), , xlYes)
    objLO.Name = "Recap"
    objLO.TableStyle = "TableStyleMedium2"

    objLO.ListColumns.Add (objLO.ListColumns.Count + 1)
    objLO.HeaderRowRange(objLO.ListColumns.Count) = "Tot1"
    objLO.ListColumns.Add (objLO.ListColumns.Count + 1)
    objLO.HeaderRowRange(objLO.ListColumns.Count) = "Tot2"
    objLO.ListColumns.Add (objLO.ListColumns.Count + 1)
    objLO.HeaderRowRange(objLO.ListColumns.Count) = "Tot3"
    objLO.ListColumns.Add (objLO.ListColumns.Count + 1)
    objLO.HeaderRowRange(objLO.ListColumns.Count) = "Tot4"

    objLO.ShowTotals = True

    objLO.ListColumns("Tot1").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot2").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot3").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot4").TotalsCalculation = xlTotalsCalculationSum

End Function

теперь, если вы идете на любую ячейку новых столбцов и пишете некоторые цифры, странно, что общее (подытог) не обновляется; но если вы сохраните файл и снова откроете его, он будет работать, и итоги будут обновляться. Кто я? не хватает?

Я уже пробовал перемещать ShowTotals после TotalCalculation, но поведение остается прежним.

если мы теперь перестроим лист с нуля и добавим этот фрагмент кода для промежуточных итогов для столбцов b, c и d после применения стиля в предыдущем коде:

objLO.ListColumns("b").TotalsCalculation = xlTotalsCalculationSum
objLO.ListColumns("c").TotalsCalculation = xlTotalsCalculationSum
objLO.ListColumns("d").TotalsCalculation = xlTotalsCalculationSum  

Я заметил, что промежуточные итоги для b, c и d работают, но не для Tot1, Tot2 и т. д.

кажется, что единственным обходным путем является создание необработанной таблицы до добавление ListObject со ссылками для его создания. Кто-нибудь знает лучшее решение?

спасибо заранее :)

2 ответов


в таблицах Excel есть выдающаяся ошибка, и есть некоторые тонкости, которые необходимо устранить, чтобы получить требуемый результат.

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

есть 2 способа заставить Excel вычислить итоги:

  1. вы можете переключить состояние расчета родительского листа:

    objLO.Parent.EnableCalculation = False
    objLO.Parent.EnableCalculation = True
    
  2. или, вы можете заменить = в итоговых формулах:

    objLO.TotalsRowRange.Replace "=", "="
    

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

лучшее решение...

ключ к решению кроется в том, что подытоги are динамически вычисляется для столбцов, которые существовал когда ListObject был преобразован из диапазона в ListObject.

вы можете использовать эти знания и убедиться, что вместо добавления столбцов в конец/справа от ListObject вы вставляете их перед существующим столбцом. Но поскольку вы в конечном итоге хотите, чтобы новые столбцы были правильными, этот подход потребует использования фиктивного столбца в исходном диапазоне, а затем всех новых столбцов вставляются до фиктивный столбец и, наконец, фиктивный столбец можно удалить.

посмотреть этот измененный код, с комментариями:

Function test()

    Dim objLO As ListObject

    'Expand the selection to grab an additional Dummy column
    Set objLO = ActiveSheet.ListObjects.Add(xlSrcRange, Range("$A:$E"), , xlYes)
    objLO.Name = "Recap"
    objLO.TableStyle = "TableStyleMedium2"

    'Insert all of the new columns BEFORE the Dummy column
    objLO.ListColumns.Add (objLO.ListColumns.Count)
    objLO.HeaderRowRange(objLO.ListColumns.Count - 1) = "Tot1"
    objLO.ListColumns.Add (objLO.ListColumns.Count)
    objLO.HeaderRowRange(objLO.ListColumns.Count - 1) = "Tot2"
    objLO.ListColumns.Add (objLO.ListColumns.Count)
    objLO.HeaderRowRange(objLO.ListColumns.Count - 1) = "Tot3"
    objLO.ListColumns.Add (objLO.ListColumns.Count)
    objLO.HeaderRowRange(objLO.ListColumns.Count - 1) = "Tot4"

    'Must show totals BEFORE applying totals, otherwise the last column defaults to Count (even if we override it)
    objLO.ShowTotals = True

    objLO.ListColumns("Tot1").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot2").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot3").TotalsCalculation = xlTotalsCalculationSum
    objLO.ListColumns("Tot4").TotalsCalculation = xlTotalsCalculationSum

    'Remove the extra dummy column
    objLO.ListColumns(objLO.ListColumns.Count).Delete

    'Now toggle the ShowTotals to force the ListObject to recognise the new column totals
    objLO.ShowTotals = False
    objLO.ShowTotals = True

End Function

вы ничего не упускаете. Эта проблема кажется ошибкой, которую Microsoft еще не исправила.

единственное, что вы можете попробовать сейчас, это сохранить/закрыть/открыть книгу по коду.