绑定属性声明为接口vs类类型时,WPF绑定行为是否不同?

Jay*_*Jay 8 .net c# data-binding wpf xaml

这开始于我认为与我的实现有关的奇怪行为,我ToString()问了这个问题:当ToString()有一个协作对象时,为什么WPF数据绑定不显示文本?

事实证明这与合作者无关,并且具有可重复性.

当我绑定Label.ContentDataContext声明为接口类型的属性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; 
    }
}
Run Code Online (Sandbox Code Playgroud)
public class Bar
{
    public IFoo foo 
    { 
        get { return new Foo {foo_part1 = "first", foo_part2 = "second"}; } 
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 将Window1的XAML设置为:

    <Window x:Class="WpfApplication1.Window1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="Window1" Height="300" Width="300">
         <StackPanel>
            <Label Content="{Binding foo, Mode=Default}"/>
            <TextBlock Text="{Binding foo, Mode=Default}"/>
        </StackPanel>
    </Window>
    
    Run Code Online (Sandbox Code Playgroud)
  • 在Window1.xaml.cs中:

public partial class Window1 : Window  
{  
    public Window1()  
    {  
        InitializeComponent();  
        DataContext = new Bar();  
    }  
}
Run Code Online (Sandbox Code Playgroud)

当您运行此应用程序时,您将只看到一次文本(在顶部,在标签中).如果您将类的foo属性类型更改BarFoo(而不是IFoo)并再次运行该应用程序,您将在两个控件中看到该文本.

小智 8

我知道这个线程已经老了,但我找到了解决这个问题的方法.在绑定上使用StringFormat属性:

<Window x:Class="WpfApplication1.Window1"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="Window1" Height="300" Width="300">
     <StackPanel>
        <Label Content="{Binding foo, Mode=Default}"/>
        <TextBlock Text="{Binding foo, Mode=Default, StringFormat={}{0}}"/>
    </StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)


bit*_*onk 3

是的你是对的。显然该ContentControl.Content属性的实现方式与该TextBlock.Text属性不同。当然,一个明显的区别是,ContentControl实际上会生成一个TextBlock为不是 aVisual且没有 . 的内容对象生成一个实例DataTemplate。事实TextBlock并非如此。它将自行渲染文本。在这两种情况下,字符串都由以下方式确定

  1. IValueConverter如果存在于绑定中)
  2. TypeConverter
  3. object.ToString()

看来该算法仅在步骤 3 上有所不同TextBlockContentControl正如您所展示的,。虽然ContentControl实际上解析了接口背后的对象,但它却TextBlock没有。有趣的。

我想这是你必须忍受的事情。您现在有多种选择:

  • 在您的界面上公开一个字符串属性并绑定到该属性
  • 将数据对象公开为具体类而不是接口
  • 用一个ContentControl代替 aTextBlock
  • 提供一个IValueConverter并在绑定中使用它
  • 提供一个TypeConverter为您的界面
  • 做点别的事(可能还有更多)