Windows 表单数据绑定
Windows Forms data binding
所以,我的问题是关于 windows 表单数据绑定背后的确切方法。
我写了一段简单的代码,其中我创建了一个视图、一个 IViewModel 接口和一个 ViewModel。
interface IVM
{
}
和
public class Vm : IVM
{
int number;
public int Number
{
get
{
return this.number;
}
set
{
this.number = value;
}
}
}
表格如下:
public partial class Form1 : Form
{
private IVM vm;
public Form1()
{
InitializeComponent();
this.vm = new Vm();
this.iVMBindingSource.DataSource = this.vm;
}
}
相关的设计器部分是:
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.iVMBindingSource, "Number", true));
...
this.iVMBindingSource.DataSource = typeof(WindowsFormsApplication1.IVM);
可以清楚的看到IViewModel接口没有发布一个Number属性,但是具体的ViewModelclass有一个Number属性.
虽然在设计时我不能使用设计器绑定 属性(因为 IVM 没有 Number 属性),我可以手动将 "iVMBindingSource - Number" 写入文本框的测试 属性, 绑定它。
我的问题是,绑定究竟是如何工作的?为什么我在尝试访问 IVM 不存在的编号 属性 时没有收到运行时错误?
(我测试过,它实际上正确地改变了 VM 的 Number 属性)
它使用某种反射吗? "magic" 绑定字符串如何工作?
感谢您的回答!
Jup 这是通过反射完成的。我刚刚检查了代码,绑定是由 Binding
class 完成的。有一种名为 CheckBindings
的方法可确保您要绑定的 属性 可用。它基本上是这样工作的:
if (this.control != null && this.propertyName.Length > 0)
{
// ...certain checks...
// get PropertyDescriptorCollection (all properties)
for (int index = 0; index < descriptorCollection.Count; ++index)
{
// select the descriptor for the requested property
}
// validation
// setup binding
}
如 Ike 所述,您可以在此处找到源代码:
http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Binding.cs,3fb776d540d0e8ac
MSDN 参考:https://msdn.microsoft.com/en-us/library/system.windows.forms.binding(v=vs.110).aspx
正如 derape 已经提到的,Binding
使用反射。它必须使用反射,因为它无法了解您正在使用的 class 的任何信息。评估将在运行时完成。由于您的具体类型 Vm
得到指定的 属性 Number
,反射将 return 它并且 Binding
class 得到满足。只要 属性 名称有效,绑定就非常灵活。
另一方面,当您使用设计器时,它无法知道您将使用哪种具体类型。因此它只允许您使用公共基础 IVM
的属性。如果您手动输入字符串,将跳过设计时评估并将输入传递给绑定构造函数。
如果您想使用设计器支持,只需使用具体类型,或者如果您不知道具体类型但需要 属性 Number
,只需创建一个新接口并从 IMV
.
派生
所以,我的问题是关于 windows 表单数据绑定背后的确切方法。
我写了一段简单的代码,其中我创建了一个视图、一个 IViewModel 接口和一个 ViewModel。
interface IVM
{
}
和
public class Vm : IVM
{
int number;
public int Number
{
get
{
return this.number;
}
set
{
this.number = value;
}
}
}
表格如下:
public partial class Form1 : Form
{
private IVM vm;
public Form1()
{
InitializeComponent();
this.vm = new Vm();
this.iVMBindingSource.DataSource = this.vm;
}
}
相关的设计器部分是:
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.iVMBindingSource, "Number", true));
...
this.iVMBindingSource.DataSource = typeof(WindowsFormsApplication1.IVM);
可以清楚的看到IViewModel接口没有发布一个Number属性,但是具体的ViewModelclass有一个Number属性.
虽然在设计时我不能使用设计器绑定 属性(因为 IVM 没有 Number 属性),我可以手动将 "iVMBindingSource - Number" 写入文本框的测试 属性, 绑定它。
我的问题是,绑定究竟是如何工作的?为什么我在尝试访问 IVM 不存在的编号 属性 时没有收到运行时错误? (我测试过,它实际上正确地改变了 VM 的 Number 属性)
它使用某种反射吗? "magic" 绑定字符串如何工作?
感谢您的回答!
Jup 这是通过反射完成的。我刚刚检查了代码,绑定是由 Binding
class 完成的。有一种名为 CheckBindings
的方法可确保您要绑定的 属性 可用。它基本上是这样工作的:
if (this.control != null && this.propertyName.Length > 0)
{
// ...certain checks...
// get PropertyDescriptorCollection (all properties)
for (int index = 0; index < descriptorCollection.Count; ++index)
{
// select the descriptor for the requested property
}
// validation
// setup binding
}
如 Ike 所述,您可以在此处找到源代码: http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Binding.cs,3fb776d540d0e8ac
MSDN 参考:https://msdn.microsoft.com/en-us/library/system.windows.forms.binding(v=vs.110).aspx
正如 derape 已经提到的,Binding
使用反射。它必须使用反射,因为它无法了解您正在使用的 class 的任何信息。评估将在运行时完成。由于您的具体类型 Vm
得到指定的 属性 Number
,反射将 return 它并且 Binding
class 得到满足。只要 属性 名称有效,绑定就非常灵活。
另一方面,当您使用设计器时,它无法知道您将使用哪种具体类型。因此它只允许您使用公共基础 IVM
的属性。如果您手动输入字符串,将跳过设计时评估并将输入传递给绑定构造函数。
如果您想使用设计器支持,只需使用具体类型,或者如果您不知道具体类型但需要 属性 Number
,只需创建一个新接口并从 IMV
.