为什么更改控件值后绑定项不更新?
Why bind item is not updated after control value is changed?
我很难绑定属性。我可能在这里遗漏了一些东西。问题是,在我与 UI 进行另一次交互之前,我的对象属性不会被界面控件更改更新,比如按下一个空的虚拟按钮。这真的很奇怪。我在这里缺少什么?如何使绑定 属性 在控制检查更改时更新?
样本:
- 创建一个空表单,添加一个复选框和一个按钮。
- 将复选框绑定到 IsOnSale 汽车 属性。
- 添加控制台写入行以查看 IsOnSale 属性 何时更改。
- 构建并单击复选框,IsOnSale 不会更改(无控制台消息),直到单击另一个按钮或其他内容。
点击虚拟按钮,IsOnSale 属性 将被更改!什么!??
private Car car;
public Form1()
{
InitializeComponent();
car = new Car();
car.IsOnSale = false;
checkBox1.DataBindings.Add("Checked", car, "IsOnSale");
}
//U dont need this for the test..
private void btnPrintStatus_Click(object sender, EventArgs e)
{
string s = car.ToString();
Console.WriteLine(s);
}
Car 只是一个实现了 INotifyPropertyChanged 的 class。此外,每次发出 属性 更改请求时,它都会在控制台上打印(仅用于调试)。如您所见,如果您构建示例,仅在单击虚拟按钮后才会发出更改请求...
internal class Car : INotifyPropertyChanged, INotifyPropertyChanging
{
private string name;
public string Name
{
get { return name; }
set
{
string propName = GetName(new { Name });
UpdateField(ref name, value, propName, null);
}
}
private bool isOnSale;
public bool IsOnSale
{
get { return isOnSale; }
set
{
string propName = GetName(new { IsOnSale });
UpdateField(ref isOnSale, value, propName, null);
}
}
public override string ToString()
{
return string.Format("Car Name: {0}. IsOnSale: {1}", Name, IsOnSale);
}
#region INotifyPropertyChanged, INotifyPropertyChanging
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
public static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
protected bool UpdateField<T>(ref T field, T newValue, string propertyName, Action action = null)
{
bool needChange = !EqualityComparer<T>.Default.Equals(field, newValue);
Console.WriteLine("Try to UpdateField {0}. Need update? {1}", propertyName, needChange);
if (needChange)
{
OnPropertyChanging(propertyName);
field = newValue;
if (action != null)
action();
OnPropertyChanged(propertyName);
}
return needChange;
}
protected void OnPropertyChanging(string propertyName)
{
PropertyChangingEventHandler handler = PropertyChanging;
if (handler != null)
handler(this, new PropertyChangingEventArgs(propertyName));
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
编辑 - 解决方法
我已经找到了解决办法,但它闻起来……
我正在使用 BackgroundWorker 来 "get out" 更改事件,然后单击虚拟按钮。
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
//Wont work, need to get out of this event.
//btnDummy.PerformClick();
//Using another thread to get out of this event:
RunAsyncBindFixer();
}
private void RunAsyncBindFixer()
{
var workerBindFixer = new BackgroundWorker();
workerBindFixer.DoWork += WorkerBindFixer_DoWork;
workerBindFixer.RunWorkerCompleted += WorkerBindFixer_RunWorkerCompleted;
Console.WriteLine("Starting RunAsyncBindFixer");
workerBindFixer.RunWorkerAsync();
}
void WorkerBindFixer_DoWork(object sender, DoWorkEventArgs e)
{
//Aparently we need nothing here.
//Thread.Sleep(0);
}
void WorkerBindFixer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("RunAsyncBindFixer RunWorkerCompleted");
btnDummy.PerformClick();
//Checked change on a dummy checkbox wont work also
//ckbDummy.Checked = !ckbDummy.Checked;
Console.WriteLine("Dummy action applied");
}
数据绑定默认为在验证绑定控件时写入值,这通常发生在控件失去焦点时(例如在您的示例中按下按钮时)
如果控件支持,您可以强制数据绑定使用控件的 onpropertychanged(在本例中 CheckedChanged
,复选框控件支持)
checkBox1.DataBindings.Add("Checked", car, "IsOnSale", true, DataSourceUpdateMode.OnPropertyChanged);
我很难绑定属性。我可能在这里遗漏了一些东西。问题是,在我与 UI 进行另一次交互之前,我的对象属性不会被界面控件更改更新,比如按下一个空的虚拟按钮。这真的很奇怪。我在这里缺少什么?如何使绑定 属性 在控制检查更改时更新?
样本:
- 创建一个空表单,添加一个复选框和一个按钮。
- 将复选框绑定到 IsOnSale 汽车 属性。
- 添加控制台写入行以查看 IsOnSale 属性 何时更改。
- 构建并单击复选框,IsOnSale 不会更改(无控制台消息),直到单击另一个按钮或其他内容。
点击虚拟按钮,IsOnSale 属性 将被更改!什么!??
private Car car; public Form1() { InitializeComponent(); car = new Car(); car.IsOnSale = false; checkBox1.DataBindings.Add("Checked", car, "IsOnSale"); } //U dont need this for the test.. private void btnPrintStatus_Click(object sender, EventArgs e) { string s = car.ToString(); Console.WriteLine(s); }
Car 只是一个实现了 INotifyPropertyChanged 的 class。此外,每次发出 属性 更改请求时,它都会在控制台上打印(仅用于调试)。如您所见,如果您构建示例,仅在单击虚拟按钮后才会发出更改请求...
internal class Car : INotifyPropertyChanged, INotifyPropertyChanging
{
private string name;
public string Name
{
get { return name; }
set
{
string propName = GetName(new { Name });
UpdateField(ref name, value, propName, null);
}
}
private bool isOnSale;
public bool IsOnSale
{
get { return isOnSale; }
set
{
string propName = GetName(new { IsOnSale });
UpdateField(ref isOnSale, value, propName, null);
}
}
public override string ToString()
{
return string.Format("Car Name: {0}. IsOnSale: {1}", Name, IsOnSale);
}
#region INotifyPropertyChanged, INotifyPropertyChanging
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
public static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
protected bool UpdateField<T>(ref T field, T newValue, string propertyName, Action action = null)
{
bool needChange = !EqualityComparer<T>.Default.Equals(field, newValue);
Console.WriteLine("Try to UpdateField {0}. Need update? {1}", propertyName, needChange);
if (needChange)
{
OnPropertyChanging(propertyName);
field = newValue;
if (action != null)
action();
OnPropertyChanged(propertyName);
}
return needChange;
}
protected void OnPropertyChanging(string propertyName)
{
PropertyChangingEventHandler handler = PropertyChanging;
if (handler != null)
handler(this, new PropertyChangingEventArgs(propertyName));
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
编辑 - 解决方法
我已经找到了解决办法,但它闻起来…… 我正在使用 BackgroundWorker 来 "get out" 更改事件,然后单击虚拟按钮。
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
//Wont work, need to get out of this event.
//btnDummy.PerformClick();
//Using another thread to get out of this event:
RunAsyncBindFixer();
}
private void RunAsyncBindFixer()
{
var workerBindFixer = new BackgroundWorker();
workerBindFixer.DoWork += WorkerBindFixer_DoWork;
workerBindFixer.RunWorkerCompleted += WorkerBindFixer_RunWorkerCompleted;
Console.WriteLine("Starting RunAsyncBindFixer");
workerBindFixer.RunWorkerAsync();
}
void WorkerBindFixer_DoWork(object sender, DoWorkEventArgs e)
{
//Aparently we need nothing here.
//Thread.Sleep(0);
}
void WorkerBindFixer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("RunAsyncBindFixer RunWorkerCompleted");
btnDummy.PerformClick();
//Checked change on a dummy checkbox wont work also
//ckbDummy.Checked = !ckbDummy.Checked;
Console.WriteLine("Dummy action applied");
}
数据绑定默认为在验证绑定控件时写入值,这通常发生在控件失去焦点时(例如在您的示例中按下按钮时)
如果控件支持,您可以强制数据绑定使用控件的 onpropertychanged(在本例中 CheckedChanged
,复选框控件支持)
checkBox1.DataBindings.Add("Checked", car, "IsOnSale", true, DataSourceUpdateMode.OnPropertyChanged);