绑定属性声明为接口vs类类型时,WPF绑定行为是否不同?
这开始于我认为与我的ToString()
实现相关的奇怪行为,我问了这个问题: 当ToString()有一个协作对象时,为什么WPF数据绑定不显示文本?
事实certificate它与协作者无关,并且可以重现。
当我将Label.Content
绑定到声明为接口类型的DataContext
的属性时,在运行时对象上调用ToString()
,标签显示结果。
当我将TextBlock.Text
绑定到同一属性时,永远不会调用ToString()
并且不显示任何内容。 但是 ,如果我将声明的属性更改为接口的具体实现,它将按预期工作。
这是不是设计? 如果是这样,任何想法为什么?
重现:
- 创建一个新的WPF应用程序(.NET 3.5 SP1)
- 添加以下类:
public interface IFoo { string foo_part1 { get; set; } string foo_part2 { get; set; } } public class Foo : IFoo { public string foo_part1 { get; set; } public string foo_part2 { get; set; } public override string ToString() { return foo_part1 + " - " + foo_part2; } }
public class Bar { public IFoo foo { get { return new Foo {foo_part1 = "first", foo_part2 = "second"}; } } }
-
将Window1的XAML设置为:
-
在Window1.xaml.cs中:
public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new Bar(); } }
运行此应用程序时,您将只看到一次文本(位于顶部,标签中)。 如果将Bar
类的foo
属性类型更改为Foo
(而不是IFoo
)并再次运行应用程序,则会在两个控件中看到该文本。
我知道这个线程已经老了,但我找到了解决这个问题的方法。 在绑定上使用StringFormat属性:
是的,你是对的。 显然, ContentControl.Content
属性的实现方式与TextBlock.Text
属性不同。 当然,一个明显的区别是ContentControl
实际上会为不是Visual
的内容对象生成TextBlock
实例,并且没有DataTemplate
。 TextBlock
没有。 它将自己呈现文本。 在这两种情况下,字符串都由
-
IValueConverter
(如果存在于绑定中) -
TypeConverter
(如果声明) -
object.ToString()
看起来这个算法仅在TextBlock
和ContentControl
之间的步骤3中有所不同,如图所示。 虽然ContentControl
实际上解析了接口后面的对象,但TextBlock
却没有。 有趣。
我想这是你必须要忍受的事情。 你现在有几个选择:
- 在您的界面上公开一个字符串属性并绑定到该属性
- 将数据对象公开为具体类而不是接口
- 使用
ContentControl
而不是TextBlock
- 提供
IValueConverter
并在IValueConverter
使用它 - 为您的界面提供
TypeConverter
- 做别的事(可能还有更多)