Binding to interface typed properties

你说的曾经没有我的故事 提交于 2020-01-14 12:37:22

问题


I just got bit by yet another binding oddity in WPF. Consider the following class and its IStupid typed property called MyStupid:

public struct DumbClass
{
    public IStupid MyStupid { get { return new IsStupid(); } }
}
public interface IStupid{}
public class IsStupid : IStupid{}

Now consider the following binding to a ListBox:

var items = new List<DumbClass>(new []{new DumbClass(), new DumbClass(), new DumbClass()});
OptListBox.ItemsSource = items;

There is nothing special about the xaml:

<ListBox Name="OptOccurances" Height="238" HorizontalAlignment="Left" Margin="130,34,0,0" VerticalAlignment="Top" Width="229" >
</ListBox>

As expected, the output of the listbox is 3 rows of "MyProject.DumbClass".

However if I set DisplayMemberPath="MyStupid" (or create an ItemTemplate, binding 'MyStupid' directly to a TextBlock in the template), I get 3 empty rows instead, when I expected it to say MyProject.IsStupid. Why is the databinding engine unable to call the default ToString() implementation and display the class name. Is there a workaround for a interface typed property? At the very least, is there a reason why no binding error is thrown?


回答1:


I can reproduce this issue. It looks like WPF bug.

Here is the workaround you can use: Instead of DisplayMemberPath, you can use Item's DataTemplate with StringFormat parameter, which will forcefully convert property value to string:

    <ListBox x:Name="OptOccurances" Height="238" HorizontalAlignment="Left" Margin="130,34,0,0" VerticalAlignment="Top" Width="229" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Path=MyStupid, StringFormat='{}{0}' }"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Generally you can use WPF Trace Settings to figure out such kind of problems:

But in this case as I see no binding errors happen.

Additionally you can use WPF Visualizer for Visual Studio 2012, which allows you to investigate tree right from the debug Watch:

Using the following code you can get TextBlock with its binding:

    private void btn_Click_1(object sender, RoutedEventArgs e)
    {
        var listBoxItem = OptOccurances.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
        var item = OptOccurances.Items[1] as DumbClass;
        var tbk =  VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(listBoxItem, 0),0),0) as TextBlock;
        var binding = BindingOperations.GetBinding(tbk, TextBlock.TextProperty);
        var be = BindingOperations.GetBindingExpression(tbk, TextBlock.TextProperty);
        var vs = DependencyPropertyHelper.GetValueSource(tbk, TextBlock.TextProperty);
        var val = tbk.GetValue(TextBlock.TextProperty);
    }

And it shows that Binding status is actually active and the object mapped is correct. Obviously internals of Binding (PropertyPathWorker) works differently for getting the value in case type of property



来源:https://stackoverflow.com/questions/16309863/binding-to-interface-typed-properties

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!