0

まず、問題のあるコード:

public virtual void grid_RefreshFetchData(Object sender, RefreshEventArgs e)
{
    C1DBGrid g = (C1DBGrid)sender;
    if (g.RefreshUseResult)
    {
        DataTable dtNew = FetchRawData(e.Argument);
        dt_Patch(dtNew, e.Argument);
        g.BindingSource.SuspendBinding();
        ((DataTable)g.BindingSource.DataSource).Clear();
        ((DataTable)g.BindingSource.DataSource).Merge(dtNew);
        g.BindingSource.ResumeBinding();
    }
}

表示されているのは、Windowsフォームがデータを必要としているために最終的に起動されるバックグラウンドスレッドから呼び出されているイベントハンドラーです。グリッドオブジェクト(ComponentOne TrueDBGrid)はそのフォームによって所有されており、フォームがグリッドに新しいデータを要求するように指示できるようにイベントが設定されています。この呼び出しにより、このハンドラーが生成されます。このハンドラーの目的は、基になるデータクラスにレコードを含むDataTableをフェッチし、そのテーブルをグリッドのBindingSource(同じスキーマのDataTable)とマージすることです。

私の問題:新しいデータをグリッドの(新しく空になった)BindingSource(ここでもDataTable自体)にマージするためにMerge()メソッドが呼び出されると、大量の一連の例外がスローされます。各例外インスタンスは、実際には3つの例外です。1つのSystem.Reflection.TargetInvocationExceptionと、それに続く1組のSystem.InvalidOperationExceptionsです。その結果、パフォーマンスが大幅に低下します。これを修正する必要があります。

私は何が起こっているのか理解しています。フォームでは、コントロールのTextプロパティを使用して、TextBoxコントロールをグリッドのBindingSourceにバインドしています。このバインディングは、行がBindingSourceにマージされるたびに発生します。その最後の部分は観察されていません、それは少し推測ですが、例外の膨大な量はそれが正しい仮定であることを示唆しています。それと、すべてのバインディングをコメントアウトすると、パフォーマンスが劇的に向上したという事実。

したがって、私が求めているのは、このバインディングトリガーを一時停止する方法を理解するのに役立つことです。ご覧のとおり、イベントハンドラーには、BindingSourceでサスペンドしようとする行があります。

私はすでにこれも試しました:

g.SuspendBinding();

違いはありませんでした。実際、私は方程式の両端で、フォームとスレッド更新でバインディングを一時停止しようとしましたが、常にすべての試みは無益でした。

手伝ってくれますか?

4

2 に答える 2

3

これはあなたの問題かもしれません ( MSDNから取得)。

SuspendBinding を使用すると、ResumeBinding が呼び出されるまで変更がデータ ソースにプッシュされなくなりますが、実際にはイベントの発生を防ぐことはできません。DataGridView コントロールなどの複雑なデータ バインディングを使用するコントロールは、ListChanged イベントなどの変更イベントに基づいて値を更新するため、SuspendBinding を呼び出しても、データ ソースへの変更を受信できなくなりません。このため、この SuspendBinding と ResumeBinding は、TextBox コントロールなどの単純なバインド コントロールで使用するように設計されています。または、RaiseListChangedEvents プロパティを false に設定して ListChanged イベントを抑制すれば、これらのメソッドを複雑なバインド シナリオで使用できます。

于 2012-12-20T14:56:44.277 に答える
1

価値のあることとして、ハックアプローチは非常にうまくいくようです。私はそれが本当に好きではありませんが、手動でのバインディングのフルスペクトル制御を伴わない代替アプローチも見当たりません。

Formから派生したクラスに基づいて、すべてのWindowsフォームを使用できるという贅沢があります。そこで、SuspendBinding()とResumeBinding()の2つのメソッドを作成しました。

これが私がしたことのサンプルです:

private List<KeyValuePair<String, Binding>> _savedBindings = new List<KeyValuePair<String, Binding>>();

private delegate void InvokeSuspendBinding();
public void SuspendBinding()
{
    if (InvokeRequired)
    {
        Invoke(new InvokeSuspendBinding(SuspendBinding));
        return;
    }

    foreach (DictionaryEntry entry in ChildControls)
    {
        if (entry.Value is Control && ((Control)entry.Value).DataBindings.Count > 0)
        {
            for (Int32 i = 0; i < ((Control)entry.Value).DataBindings.Count; i++)
            {
                _savedBindings.Add(new KeyValuePair<String, Binding>(entry.Key as String, ((Control)entry.Value).DataBindings[i]));
                ((Control)entry.Value).DataBindings.RemoveAt(i);
            }
        }
    }
}

private delegate void InvokeResumeBinding();
public void ResumeBinding()
{
    if (InvokeRequired)
    {
        Invoke(new InvokeResumeBinding(ResumeBinding));
        return;
    }

    foreach (DictionaryEntry entry in ChildControls)
    {
        foreach (KeyValuePair<String, Binding> kvp2 in _savedBindings)
        {
            if (kvp2.Key.Equals(entry.Key))
                ((Control)entry.Value).DataBindings.Add(kvp2.Value);
        }
    }

    _savedBindings.Clear();
}

ループで参照されるメンバーChildControlsはフォームクラスのメンバーであり、コントロール名とコントロールオブジェクトのハッシュテーブルを返す再帰ループの結果であることに注意してください。

于 2012-12-20T18:04:38.897 に答える