为什么WPF支持绑定到一个对象的属性,但不是字段?

我有一个WCF服务,通过像这样的结构传递状态更新:

[DataContract] public struct StatusInfo { [DataMember] public int Total; [DataMember] public string Authority; } ... public StatusInfo GetStatus() { ... } 

我在ViewModel中公开一个属性,像这样:

 public class ServiceViewModel : ViewModel { public StatusInfo CurrentStatus { get{ return _currentStatus; } set { _currentStatus = value; OnPropertyChanged( () => CurrentStatus ); } } } 

和XAML一样:

 <TextBox Text="{Binding CurrentStatus.Total}" /> 

当我运行应用程序,我看到输出窗口中的错误,指示无法findTotal属性。 我检查了两次,并且正确input了。 我想到的是,这些错误特别表明“财产”无法find。 所以将一个属性添加到结构使其工作得很好。 但是这对我来说似乎很奇怪,WPF不能处理单向绑定到字段。 在语法上,你在代码中访问它们是相同的,只需要为StatusInfo结构创build一个自定义视图模型就显得很愚蠢。 我错过了关于WPF绑定的东西吗? 你可以绑定到一个字段或属性绑定的唯一方法?

绑定通常不适用于字段。 大多数绑定部分基于ComponentModel PropertyDescriptor模型,默认情况下,该模型对属性起作用。 这使得通知,validation等(没有任何与字段一起工作)。

由于更多的原因,我可以进入公共领域是一个坏主意。 他们应该是属性,事实。 同样,可变结构是一个非常糟糕的主意。 同样重要的是,它可以防止意外的数据丢失(通常与可变结构相关)。 这应该是一个类:

 [DataContract] public class StatusInfo { [DataMember] public int Total {get;set;} [DataMember] public string Authority {get;set;} } 

现在它会按照你的想法行事。 如果你想让它成为一个不可变的结构,那就没问题了(但是数据绑定当然是单向的):

 [DataContract] public struct StatusInfo { [DataMember] public int Total {get;private set;} [DataMember] public string Authority {get;private set;} public StatusInfo(int total, string authority) : this() { Total = total; Authority = authority; } } 

但是,我首先会问,为什么这是一个结构。 用.NET语言编写结构是非常罕见的 。 请记住,WCF“mex”代理层将在消费者中将其创build为类(除非使用程序集共享)。


回答“为什么使用结构”回复(“未知(谷歌)”):

如果这是对我的问题的答复,这在许多方面都是错误的。 首先, 作为variables的值types通常在堆栈上分配(第一个)。 如果它们被推入堆中(例如在一个数组/列表中),那么类的开销就不会有太大的差别 – 一小部分的对象头加一个引用。 结构应该总是很小 。 有多个领域的东西会过大,会杀死你的堆栈或只是由于blitting造成缓慢。 此外,结构应该是不变的 – 除非你真的知道你在做什么。

几乎所有代表对象的东西都应该是不可变的。

如果你正在访问一个数据库,相比于进程外,可能通过networking,struct vs class的速度是一个非问题。 即使速度稍微慢一些,相对于正确的处理方式来说,这意味着什么也没有,即把对象当作对象。

作为超过1M个对象的一些指标:

 struct/field: 50ms class/property: 229ms 

基于以下(速度差异在对象分配,而不是字段与属性)。 所以慢5倍左右,但还是非常快 。 既然这不会成为你的瓶颈,不要过早地优化这个!

 using System; using System.Collections.Generic; using System.Diagnostics; struct MyStruct { public int Id; public string Name; public DateTime DateOfBirth; public string Comment; } class MyClass { public int Id { get; set; } public string Name { get; set; } public DateTime DateOfBirth { get; set; } public string Comment { get; set; } } static class Program { static void Main() { DateTime dob = DateTime.Today; const int SIZE = 1000000; Stopwatch watch = Stopwatch.StartNew(); List<MyStruct> s = new List<MyStruct>(SIZE); for (int i = 0; i < SIZE; i++) { s.Add(new MyStruct { Comment = "abc", DateOfBirth = dob, Id = 123, Name = "def" }); } watch.Stop(); Console.WriteLine("struct/field: " + watch.ElapsedMilliseconds + "ms"); watch = Stopwatch.StartNew(); List<MyClass> c = new List<MyClass>(SIZE); for (int i = 0; i < SIZE; i++) { c.Add(new MyClass { Comment = "abc", DateOfBirth = dob, Id = 123, Name = "def" }); } watch.Stop(); Console.WriteLine("class/property: " + watch.ElapsedMilliseconds + "ms"); Console.ReadLine(); } } 

我只能猜测他们为什么只支持属性:也许是因为它似乎是.NET框架中的一个通用约定,从来不暴露可变字段( 可能是为了保证二进制兼容性 ),并且他们以某种方式期望所有程序员遵循相同的约定。

另外,虽然字段和属性是用相同的语法来访问的,但是数据绑定使用了reflection,并且(所以我听说)reflection必须以不同的方式访问字段,而不是访问属性。