8


2

ユーザーがbindingsourceを使用してデータを変更したかどうかを確認する方法は?

`List`にバインドされたbindingsourceにバインドされたDataGridViewがあります。 ユーザーは、テキストボックスなどを含むフォームに移動する行をクリックします。 テキストボックスは次のようにデータバインドされます:

if (txtID.DataBindings.Count == 0)
    txtID.DataBindings.Add("Text", bindingSource, "Title");

ユーザーが閉じるボタンをクリックしたときにユーザーがコントロールのデータを変更したかどうかを検出できるようにしたいので、「未保存の作業があります。 保存しますか?」

バインディングソースでこれを検出するにはどうすればよいですか?

  • UPDATE:*リスト内のアイテムに変更をプッシュする `bindingSource.EndEdit()`を実行できることを確認しました。 私のアイテムでは、DirtyがMessageboxをスローするかどうかを言うことができますが、情報を保存するために「いいえ」をクリックすると、CancelEditは機能しません。

11 Answer


7


リスト内のオブジェクトがhttp://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx [INotifyPropertyChanged]イベントをサポートし、` List`をhttp://に置き換える場合msdn.microsoft.com/en-us/library/ms132679.aspx [BindingList] http://msdn.microsoft.com/en-us/library/ms132742.aspx [` ListChanged`]イベントに登録できますBindingListを使用して、ユーザーが行った変更について通知を受けます。


2


より簡単な方法は、BindingSourceのListChangedイベントをサブスクライブし、イベントタイプに基づいてIsDirtyフラグを設定することです。

categoryBindingSource.ListChanged +=
new System.ComponentModel.ListChangedEventHandler(categoryBindingSource_ListChanged);

イベントメソッドでIsDirty = trueを設定します…​

void customerAccountBindingSource_ListChanged(object sender, system.ComponentModel.ListChangedEventArgs e)
{
    if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemChanged)
        _isDirty = true;
}

ここで注意すべきことは、変更された値が元の値と同じ場合は検出できないことです。 そのレベルの精度が必要な場合は、「Memberwise.Clone」を追加で使用できます。


1


DataSetにバインドされている場合は、幸運です。http://msdn.microsoft.com/en-us/library/system.data.dataset.haschanges.aspx [HasChanges]プロパティがあります。 データセットでGetChangesを呼び出すことにより、実際の変更を取得できます。 これは、変更されたすべての行のコピーを含む新しいデータセットを返します


1


別のことを試した後、私はこのコードの一部になりました:

private MyClass currentItem = null;
private bool itemDirty = false; // can be used for "do you want to save?"

private void bindingSource_CurrentChanged(object sender, EventArgs e)
{
    var handler = new PropertyChangedEventHandler((s, e2) => itemDirty = true);

    var crnt = currentItem as INotifyPropertyChanged;
    if(crnt != null) crnt.PropertyChanged -= handler;

    currentItem = (MyClass)bindingSource.Current;

    crnt = currentItem as INotifyPropertyChanged;
    if(crnt != null) crnt.PropertyChanged += handler;

    itemDirty = false;
}

Windows Formのインスタンスフィールドに多くの状態情報を保存しますが、私にとってはうまくいきます。 しかし、 CurrentChanged`と CurrentItemChanged`をいじっても助けにはなりませんでした。


1


この機能を作成しました。 あなたはのように使用することができます:

if (changedOrNew(myBindingSource)){
    // Do something!
}

public bool changedOrNew(BindingSource bs){
    EntityObject obj = (EntityObject)bs.Current;
    if (obj==null)
        return false;
    return (obj.EntityState == EntityState.Detached ||
            obj.EntityState == EntityState.Added ||
            obj.EntityState == EntityState.Modified);
}


1


次のように、かなり単純なメカニズムを設定しました。

  1. コントロールをバインドした後、バインドされたすべてを見つけるメソッドを実行します コントロールをその値にマップする* Dictionary *(適切な値を取得する小さなメソッドがあります)で、現在の値をコントロールして保存します(_DataSource_から値を取得するために_ReadValue()_を実行します)私が持っているコントロールの種類ごとに)。

  2. また、それぞれに変更イベントハンドラーを追加します(ここでも、特定の イベントはコントロールのタイプによって決定されますが、それらはすべて同じハンドラーを指します)

  3. 変更ハンドラは、* Dictionary に対して現在の値をチェックします 値。 異なる場合は、それに応じて動作します(私の場合は、 Cancel ボタンの Close *ボタンを切り替えます)。 同じである場合、他のすべてのバインドされたコントロールをチェックし、何も違いがなければ、*キャンセル*を*閉じる*に戻します。元の値を再入力した場合でも、変更が元に戻されたことを認識することも、このメソッドの優れた機能です。

  4. 離れる前に、保存する変更がある場合は、

    • WinForms *が何らかの変更を伝播することができなかった場合に備えて、コントロールを再度バインドして_WriteValue()_を実行します。

誰かが興味を持っているなら、私はソースを共有できます。


1


あなたのバインディングソースがデータテーブルを使用している場合、これを行うことができます:

    public bool HasChanges()
    {
        bool Result = false;

        myBindingSource.EndEdit();
        Result = ((DataTable)myBindingSource.DataSource).GetChanges(DataRowState.Modified) != null;


        return Result;
    }


0


更新された質問から、Memberwise.Cloneを使用してBeginEditでオブジェクトの現在のバージョンを保存し、CancelEditで現在のバージョンに復元する必要があることがわかりました。


0


私がいつもしていることは、コントロールの個々の「変更された」イベントをキャプチャすることです。 以下の例では、この例でtabcontrolを使用しました。 Try / Catchは、あらゆる種類の例外に対処する必要がないための汚い解決策です;-)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    '
    ' some code
    '
    BindingNavigatorSaveItem.Enabled = False
    For Each tabctl As Control In Me.TabControl1.Controls
        For Each ctl As Control In tabctl.Controls
            Try
                If ctl.GetType Is GetType(TextBox) Then
                    AddHandler DirectCast(ctl, TextBox).TextChanged, AddressOf GenDataChanged
                ElseIf ctl.GetType Is GetType(NumericUpDown) Then
                    AddHandler DirectCast(ctl, NumericUpDown).ValueChanged, AddressOf GenDataChanged
                ElseIf ctl.GetType Is GetType(ComboBox) Then
                    AddHandler DirectCast(ctl, ComboBox).SelectedValueChanged, AddressOf GenDataChanged
                ElseIf ctl.GetType Is GetType(CheckBox) Then
                    AddHandler DirectCast(ctl, CheckBox).CheckStateChanged, AddressOf GenDataChanged
                End If
            Catch ex As Exception
            End Try
        Next
    Next
End Sub

Private Sub GenDataChanged(sender As System.Object, e As System.EventArgs)
    BindingNavigatorSaveItem.Enabled = True
End Sub


0


質問されたときに利用可能かどうかはわかりませんが、grid_CurrentCellDirtyStateChangedを使用します。出来事