试图做两种方式绑定 INotifyPropertyChanged null
Trying to do two way binding INotifyPropertyChanged null
应该发生的是我的复选框会由于计时器的原因来回闪烁。变量改变了,但形式没有。双方都检查了 dataMember 的名称。
Class 这意味着类似于此处的 INotifyPropertyChanged 实现:
Implementing INotifyPropertyChanged - does a better way exist?
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Notice
{
public class Notifier : INotifyPropertyChanged
{
//used to prevent infinite loops
private bool controllerChanged;
public event PropertyChangedEventHandler PropertyChanged;
public Notifier()
{
controllerChanged = false;
}
public bool SetField<T>(ref T field, T value, string propertyName)
{
if (!controllerChanged)
{
controllerChanged = true;
if (EqualityComparer<T>.Default.Equals(field, value))
{
controllerChanged = false;
return false;
}
field = value;
OnPropertyChanged(propertyName);
controllerChanged = false;
return true;
}
return false;
}
protected virtual void OnPropertyChanged(string property)
{
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(property));
}
}
}
}
Class变量,仅举一个例子
using System;
using Notice;
namespace Vars
{
public class Checks
{
private bool checkbox;
Notifier note = new Notifier();
public Checks()
{
checkbox = true;
}
public bool Checkbox
{
get { return checkbox; }
//set { WindowsFormsApp1.Program.note.SetField(ref checkbox, value, "Checkbox"); }
set { note.SetField(ref checkbox, value, "Checkbox"); }
}
}
}
大部分表格代码:
public Form1()
{
InitializeComponent();
//If you bind it using properties for the item in the form, don't need this line
checkBox1.DataBindings.Add("Checked", WindowsFormsApp1.Program.Ch, "Checkbox", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
WindowsFormsApp1.Program.Ch.Checkbox = !WindowsFormsApp1.Program.Ch.Checkbox;
Console.WriteLine(WindowsFormsApp1.Program.Ch.Checkbox);
}
private void timer1_Tick(object sender, EventArgs e)
{
WindowsFormsApp1.Program.Ch.Checkbox = !WindowsFormsApp1.Program.Ch.Checkbox;
Console.WriteLine(WindowsFormsApp1.Program.Ch.Checkbox);
}
虽然短语 "prefer composition over inheritance" 经常出现,但您在这里做得太过分了。
INotifyPropertyChanged
接口依赖于 sender
事件是 属性 本身存在的同一对象。在您的实现中,您已将事件委托给一个根本没有暴露给 public 的对象,即使 XAML 可以从该对象接收通知,但该对象不是 属性存在。
你应该:
- 使
Checks
继承Notifier
class而不是组合一个
- 使
SetField()
方法 protected
而不是 public
,并直接从 属性 setter 调用它,而不是通过中间实例共 Notifier
就其价值而言,通常不需要您添加到规范实现中的 controllerChanged
功能。不会发生递归,因为当设置的值与当前值相同时不会发出通知。如果您遇到 运行 递归的情况,则您可能在做其他不正确的事情,例如尝试切换值以响应通知。在这种情况下,使递归短路可避免堆栈溢出,但会隐藏导致它的代码中的真正错误。
我建议也删除 controllerChanged
功能。如果您在没有它的情况下遇到代码问题,post 一个新问题,请确保您包含一个可靠地重现堆栈溢出的良好 [mcve],解释您已经尝试过什么来修复它,以及什么具体来说,您需要帮助。
应该发生的是我的复选框会由于计时器的原因来回闪烁。变量改变了,但形式没有。双方都检查了 dataMember 的名称。
Class 这意味着类似于此处的 INotifyPropertyChanged 实现: Implementing INotifyPropertyChanged - does a better way exist?
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace Notice
{
public class Notifier : INotifyPropertyChanged
{
//used to prevent infinite loops
private bool controllerChanged;
public event PropertyChangedEventHandler PropertyChanged;
public Notifier()
{
controllerChanged = false;
}
public bool SetField<T>(ref T field, T value, string propertyName)
{
if (!controllerChanged)
{
controllerChanged = true;
if (EqualityComparer<T>.Default.Equals(field, value))
{
controllerChanged = false;
return false;
}
field = value;
OnPropertyChanged(propertyName);
controllerChanged = false;
return true;
}
return false;
}
protected virtual void OnPropertyChanged(string property)
{
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(property));
}
}
}
}
Class变量,仅举一个例子
using System;
using Notice;
namespace Vars
{
public class Checks
{
private bool checkbox;
Notifier note = new Notifier();
public Checks()
{
checkbox = true;
}
public bool Checkbox
{
get { return checkbox; }
//set { WindowsFormsApp1.Program.note.SetField(ref checkbox, value, "Checkbox"); }
set { note.SetField(ref checkbox, value, "Checkbox"); }
}
}
}
大部分表格代码:
public Form1()
{
InitializeComponent();
//If you bind it using properties for the item in the form, don't need this line
checkBox1.DataBindings.Add("Checked", WindowsFormsApp1.Program.Ch, "Checkbox", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
WindowsFormsApp1.Program.Ch.Checkbox = !WindowsFormsApp1.Program.Ch.Checkbox;
Console.WriteLine(WindowsFormsApp1.Program.Ch.Checkbox);
}
private void timer1_Tick(object sender, EventArgs e)
{
WindowsFormsApp1.Program.Ch.Checkbox = !WindowsFormsApp1.Program.Ch.Checkbox;
Console.WriteLine(WindowsFormsApp1.Program.Ch.Checkbox);
}
虽然短语 "prefer composition over inheritance" 经常出现,但您在这里做得太过分了。
INotifyPropertyChanged
接口依赖于 sender
事件是 属性 本身存在的同一对象。在您的实现中,您已将事件委托给一个根本没有暴露给 public 的对象,即使 XAML 可以从该对象接收通知,但该对象不是 属性存在。
你应该:
- 使
Checks
继承Notifier
class而不是组合一个 - 使
SetField()
方法protected
而不是public
,并直接从 属性 setter 调用它,而不是通过中间实例共Notifier
就其价值而言,通常不需要您添加到规范实现中的 controllerChanged
功能。不会发生递归,因为当设置的值与当前值相同时不会发出通知。如果您遇到 运行 递归的情况,则您可能在做其他不正确的事情,例如尝试切换值以响应通知。在这种情况下,使递归短路可避免堆栈溢出,但会隐藏导致它的代码中的真正错误。
我建议也删除 controllerChanged
功能。如果您在没有它的情况下遇到代码问题,post 一个新问题,请确保您包含一个可靠地重现堆栈溢出的良好 [mcve],解释您已经尝试过什么来修复它,以及什么具体来说,您需要帮助。