3

私はここで知恵の限界に来ており、それほど複雑であってはならないことをしようとして 1 日を失いました。

Sybase クエリから返された Recordset があります。このレコードセットは、Excel でピボットテーブルを作成するために使用されました。ここまでは順調ですね。ピボットテーブルの値を変更したいので、新しい値を使用してレコードセット内の特定のレコードを更新します。RS で問題なく更新を行うことができ、値は次回反復するときに RS に保存されます。

問題は、値がピボット テーブルに反映されないことです。私が試してみました:

  • pivotTable.Refresh();
    • COMException: PivotTable クラスの RefreshTable メソッドが失敗しました
  • pivotTable.PivotCache().Refresh();
    • ComException: HRESULT からの例外: 0x800A03EC
  • pivotTable.Update();
    • 例外ではありませんが、変更はピボット テーブルに反映されません。

また、レコードセットのクローンを作成し、そこからまったく新しいピボット テーブルを作成しようとしましたが、Recordsetデータが含まれていますが、PivotCache.RecordCount0 です

コード:

var app = ExcelAppHelper.GetExcelApp();
if (app.ActiveCell == null || app.ActiveCell.PivotTable == null)
    return;

PivotTable pivotTable = app.ActiveCell.PivotTable;
var rs = (Recordset)pivotTable.PivotCache().Recordset;
rs.MoveFirst();

s_lastSelectedPivotTree = new PivotFilterTree();
RecalculateSelectedValues(vmMain);

while (!rs.EOF)
{
    if (s_lastSelectedPivotTree.Contains(rs.Fields))
    {
        foreach (var dataFieldName in s_lastSelectedDataFields)
        {
            // update the values in the RS
            rs.Fields[dataFieldName].Value = newValue;
        }

        // commit the modifications into the RS
        rs.Update(Type.Missing, Type.Missing);
    }
    rs.MoveNext();
}
rs.MoveFirst();

// here is the magic line that will show me the updated pivot table
pivotTable.Update();

誰でもこれを行う方法を知っていますか? レコードセットを変更してからピボット テーブルを「更新」し、レコードセットに基づいてピボット テーブルを再計算します。

ありがとうショーン

4

1 に答える 1

3

さて、私はそれを解決しました。Recordsetが によって「消費」されると、必要なだけ変更できるように見えPivotTableますが、Excel では更新されません。データが含まれているにもかかわらず、Recordset更新するとデータが空にPivotTableなり、データが失われます。

回避策は?に渡す前にのディープ コピー (機能しRecordset.Clone()ません) を作成し、その中の値を変更するたびに、「クリーンな」コピーを変更し、新しいコピーを作成して、そのコピーを に渡します。それを消費する。次に、をリフレッシュします。RecordsetPivotTablePivotTablePivotTable

        var newRS = RecordsetDeepCopy(oldRS);

        newRS.MoveFirst();
        oldRS.MoveFirst();
        while (!newRS.EOF)
        {
            if (s_lastSelectedPivotTree.Contains(newRS.Fields))
            {
                // set the new value in the selected data fields
                foreach (var dataFieldName in s_lastSelectedDataFields)
                {
                    oldRS.Fields[dataFieldName].Value = val;
                    newRS.Fields[dataFieldName].Value = val;
                }

                newRS.Update(Type.Missing, Type.Missing);
                oldRS.Update(Type.Missing, Type.Missing);
            }
            newRS.MoveNext();
            oldRS.MoveNext();
        }

        newRS.MoveFirst();
        oldRS.MoveFirst();

        pivotCache.Recordset = newRS;
        pivotCache.Refresh();

そして、レコードセットのディープ コピー メソッド (Web 上の C# で見つけるのは簡単ではありません...)

private static Recordset RecordsetDeepCopy(Recordset src)
{
    var clone = new Recordset();
    int count = src.Fields.Count;
    var names = new object[count];
    int i = 0;

    foreach (ADODB.Field field in src.Fields)
    {
        names[i++] = field.Name;
        var attr = (FieldAttributeEnum)field.Attributes;
        clone.Fields._Append(field.Name, field.Type, field.DefinedSize, attr);
    }

    clone.Open(Missing.Value, Missing.Value, CursorTypeEnum.adOpenUnspecified, LockTypeEnum.adLockUnspecified, 0);

    src.MoveFirst();

    while (!src.EOF)
    {
        var values = new object[count];
        i = 0;
        foreach (ADODB.Field field in src.Fields)
        {
            values[i++] = field.Value;
        }

        clone.AddNew(names, values);
        src.MoveNext();
    }

    clone.Update(Missing.Value, Missing.Value);
    return clone;
}

うまくいけば、これで他の人の頭痛の種が減ります...

ショーン

于 2012-10-12T12:47:56.683 に答える