我有一个DataGridView绑定到绑定到List<T>
的绑定源。用户单击转到带有文本框等的表单的行。文本框的数据绑定如下:
if (txtID.DataBindings.Count == 0)
txtID.DataBindings.Add("Text", bindingSource, "Title");
我希望能够检测用户在单击关闭按钮时是否修改了控件中的任何数据,因此我可以提示他们说“您有未保存的工作。是否要保存?”< / p>
如何在绑定源上检测到这一点?
更新:我已经知道我可以bindingSource.EndEdit()
将更改推送到列表中的项目。在我的项目中,我可以说,如果Dirty抛出一个Messagebox但是如果他们点击“No”来保存信息,则CancelEdit不起作用。
答案 0 :(得分:7)
如果List中的对象支持INotifyPropertyChanged
事件,并且您将List<T>
替换为BindingList<T>
,则可以订阅BindingList的ListChanged
事件以获取通知关于用户所做的任何更改。
答案 1 :(得分: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
。
答案 2 :(得分:1)
如果你绑定了一个DataSet,那么你很幸运:它有一个HasChanges属性。您可以通过在数据集上调用GetChanges来获取实际更改。这将返回一个包含所有已更改行的副本的新数据集
答案 3 :(得分: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窗体的实例字段中保存了大量的状态信息,但它对我来说很好。但是,与CurrentChanged
和CurrentItemChanged
混在一起并没有帮助我。
答案 4 :(得分: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);
}
答案 5 :(得分:1)
我建立了一个相当简单的机制,如下所示:
如果有人有兴趣,我可以分享来源。
答案 6 :(得分:1)
如果您的bindingsource使用数据表,您可以这样做:
public bool HasChanges()
{
bool Result = false;
myBindingSource.EndEdit();
Result = ((DataTable)myBindingSource.DataSource).GetChanges(DataRowState.Modified) != null;
return Result;
}
答案 7 :(得分:0)
根据我更新的问题,我发现我必须使用Memberwise.Clone在BeginEdit存储对象的当前版本,然后在CancelEdit中将其恢复为当前版本。
答案 8 :(得分: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
答案 9 :(得分:0)
我不确定问题被问到时是否可用但是我使用了grid_CurrentCellDirtyStateChanged;事件
答案 10 :(得分:0)
我知道这是一个老帖子,但这里是一个带有IsDirtyFlag的扩展BindingSource - 你可以根据自己的意愿调整它 - 我在几年前从网上的某个地方提取了这个代码 - 做了一些非常小的改动我觉得它最初是在VB中 - 我转换为C#..
using System.ComponentModel.Design;
using System.Windows.Forms;
using System.ComponentModel;
using System.Data;
using System;
public class BindingSourceExIsDirty : System.Windows.Forms.BindingSource, INotifyPropertyChanged
{
#region "DECLARATIONS AND PROPERTIES"
private string _displayMember;
private DataTable _dataTable;
private DataSet _dataSet;
private BindingSource _parentBindingSource;
private System.Windows.Forms.Form _form;
private System.Windows.Forms.Control _usercontrol;
private bool _isCurrentDirtyFlag = false;
public bool IsCurrentDirty {
get { return _isCurrentDirtyFlag; }
set {
if (_isCurrentDirtyFlag != value) {
_isCurrentDirtyFlag = value;
this.OnPropertyChanged(value.ToString());
//call the event when flag is set
if (value == true) {
OnCurrentIsDirty(new EventArgs());
}
}
}
}
private string _objectSource;
public string ObjectSource {
get { return _objectSource; }
set {
_objectSource = value;
this.OnPropertyChanged(value);
}
}
private bool _autoSaveFlag;
public bool AutoSave {
get { return _autoSaveFlag; }
set {
_autoSaveFlag = value;
this.OnPropertyChanged(value.ToString());
}
}
#endregion
#region "EVENTS"
//Current Is Dirty Event
public event CurrentIsDirtyEventHandler CurrentIsDirty;
// Delegate declaration.
public delegate void CurrentIsDirtyEventHandler(object sender, EventArgs e);
protected virtual void OnCurrentIsDirty(EventArgs e)
{
if (CurrentIsDirty != null) {
CurrentIsDirty(this, e);
}
}
//PropertyChanged Event
// public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
#endregion
#region "METHODS"
private void _BindingComplete(System.Object sender, System.Windows.Forms.BindingCompleteEventArgs e)
{
if (e.BindingCompleteContext == BindingCompleteContext.DataSourceUpdate) {
if (e.BindingCompleteState == BindingCompleteState.Success & !e.Binding.Control.BindingContext.IsReadOnly) {
//Make sure the data source value is refreshed (fixes problem mousing off control)
e.Binding.ReadValue();
//if not focused then not a user edit.
if (!e.Binding.Control.Focused)
return;
//check for the lookup type of combobox that changes position instead of value
if (e.Binding.Control as ComboBox != null) {
//if the combo box has the same data member table as the binding source, ignore it
if (((ComboBox)e.Binding.Control).DataSource != null) {
if (((ComboBox)e.Binding.Control).DataSource as BindingSource != null) {
if (((BindingSource)((ComboBox)e.Binding.Control).DataSource).DataMember == (this.DataMember)) {
return;
}
}
}
}
IsCurrentDirty = true;
//set the dirty flag because data was changed
}
}
}
private void _DataSourceChanged(System.Object sender, System.EventArgs e)
{
_parentBindingSource = null;
if (this.DataSource == null) {
_dataSet = null;
} else {
//get a reference to the dataset
BindingSource bsTest = this;
Type dsType = bsTest.DataSource.GetType();
//try to cast the data source as a binding source
while ((bsTest.DataSource as BindingSource != null)) {
//set the parent binding source reference
if (_parentBindingSource == null)
_parentBindingSource = bsTest;
//if cast was successful, walk up the chain until dataset is reached
bsTest = (BindingSource)bsTest.DataSource;
}
//since it is no longer a binding source, it must be a dataset or something else
if (bsTest.DataSource as DataSet == null) {
//Cast as dataset did not work
if (dsType.IsClass == false) {
throw new ApplicationException("Invalid Binding Source ");
} else {
_dataSet = null;
}
} else {
_dataSet = (DataSet)bsTest.DataSource;
}
//is there a data member - find the datatable
if (!string.IsNullOrEmpty(this.DataMember)) {
_DataMemberChanged(sender, e);
}
//CType(value.GetService(GetType(IDesignerHost)), IDesignerHost)
if (_form == null)
GetFormInstance();
if (_usercontrol == null)
GetUserControlInstance();
}
}
private void _DataMemberChanged(System.Object sender, System.EventArgs e)
{
if (string.IsNullOrEmpty(this.DataMember) | _dataSet == null) {
_dataTable = null;
} else {
//check to see if the Data Member is the name of a table in the dataset
if (_dataSet.Tables(this.DataMember) == null) {
//it must be a relationship instead of a table
System.Data.DataRelation rel = _dataSet.Relations(this.DataMember);
if ((rel != null)) {
_dataTable = rel.ChildTable;
} else {
throw new ApplicationException("Invalid Data Member");
}
} else {
_dataTable = _dataSet.Tables(this.DataMember);
}
}
}
public override System.ComponentModel.ISite Site {
get { return base.Site; }
set {
//runs at design time to initiate ContainerControl
base.Site = value;
if (value == null)
return;
// Requests an IDesignerHost service using Component.Site.GetService()
IDesignerHost service = (IDesignerHost)value.GetService(typeof(IDesignerHost));
if (service == null)
return;
if ((service.RootComponent as Form != null)) {
_form = (Form)service.RootComponent;
} else if ((service.RootComponent as UserControl != null)) {
_usercontrol = (UserControl)service.RootComponent;
}
}
}
public System.Windows.Forms.Form GetFormInstance()
{
if (_form == null & this.CurrencyManager.Bindings.Count > 0) {
_form = this.CurrencyManager.Bindings[0].Control.FindForm();
}
return _form;
}
/// <summary>
/// Returns the First Instance of the specified User Control
/// </summary>
/// <returns>System.Windows.Forms.Control</returns>
public System.Windows.Forms.Control GetUserControlInstance()
{
if (_usercontrol == null & this.CurrencyManager.Bindings.Count > 0) {
System.Windows.Forms.Control[] _uControls = null;
_uControls = this.CurrencyManager.Bindings[0].Control.FindForm().Controls.Find(this.Site.Name.ToString(), true);
_usercontrol = _uControls[0];
}
return _usercontrol;
}
public BindingSourceExIsDirty()
{
DataMemberChanged += _DataMemberChanged;
DataSourceChanged += _DataSourceChanged;
BindingComplete += _BindingComplete;
}
// PositionChanged
private override void _PositionChanged(object sender, EventArgs e)
{
if (IsCurrentDirty) {
// IsAutoSavingEvent
if (AutoSave | MessageBox.Show(_msg, "Confirm Save", MessageBoxButtons.YesNo) == DialogResult.Yes) {
try {
//cast table as ITableUpdate to get the Update method
// CType(_dataTable, ITableUpdate).Update()
} catch (Exception ex) {
MessageBox.Show(ex, "Position Changed Error");
// - needs to raise an event
}
} else {
this.CancelEdit();
_dataTable.RejectChanges();
}
IsCurrentDirty = false;
}
base(e);
}
#endregion
}
答案 11 :(得分:0)
首先确保您设置了DataSourceUpdateMode.OnPropertyChanged
txrFirstName.DataBindings.Add("Text", bindingSource1, "FirstName", false,DataSourceUpdateMode.OnPropertyChanged);
然后将此代码添加到您的movenext click事件中
if (((DataRowView)bindingSource1.Current).IsNew)
{
MessageBox.Show("Current Row IsNew");
}
if (((DataRowView)bindingSource1.CurrencyManager.Current).Row.HasVersion(DataRowVersion.Proposed))
{
MessageBox.Show("Current Row Modified");
DialogResult dialogResult = MessageBox.Show("Current Row Modified", "Some Title", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
//do something
((DataRowView)bindingSource1.CurrencyManager.Current).Row.AcceptChanges();
}
else if (dialogResult == DialogResult.No)
{
//do something else
((DataRowView)bindingSource1.CurrencyManager.Current).Row.RejectChanges();
}
}
else {
bindingSource1.MoveNext();
}