在Silverlight中将ListBox绑定到接口的属性

3

我在ListBox上使用数据绑定时遇到了问题。我怀疑是因为我试图对接口进行数据绑定,而不是类。

我的C#代码:

namespace MyNamespace
{
    interface IFoo
    {
        string Bar { get; }
    }

    class Fizz
    {
        private class Buzz : IFoo
        {
            public string Bar { get { return "something"; } }
        }

        public IEnumerable<IFoo> GetFoo()
        {
            List<Buzz> items = new List<Buzz>();
            // Populate items
            return items;
        }
    }
}

当我尝试将Fizz::GetFoo()的输出与数据绑定时,它无法正常工作。 我的XAML如下:

<ListBox Name="listBox1" ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                 <TextBlock Text="Bar:" />
                 <TextBlock Text="{Binding Bar}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

当我运行它时,我看到第一个TextBlock的文本,但没有看到第二个。在输出窗口中出现类似于以下错误:
System.Windows.Data Error: 无法从'MyNamespace.Fizz+Buzz' (类型为 'System.String') 获取 'Bar' 值。BindingExpression: Path='Bar' DataItem='Buzz' (HashCode=100433959); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String').. System.MethodAccessException: 尝试访问该方法失败:MyNamespace.Fizz+Buzz.get_Bar() at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark) at System.Reflection.RuntimePropertyInfo.InternalGetValue(PropertyInfo thisProperty, Object obj, Object[] index, StacA first chance exception of type 'System.MethodAccessException' occurred in mscorlib.dll
我做错了什么还是我尝试做的事情不可能?

1
你能否发布使用GetFoo()初始化DataContext的代码? - decyclone
1
listBox1 实际上绑定了什么?你没有包含足够的代码。 - slugster
我认为可以安全地假设他正在设置 DataContext = fizz.GetFoo();。这不是问题,因为消息中清楚地表明该属性存在...但存在访问冲突。 - Brian Genisio
没有问题DataContext,所以我把它留了下来,试图让问题更简单。将类型设为public修复了这个问题。 - brantonb
这很糟糕,因为它在WP8中可以工作。而在WP7或SL版本中会出现问题。 - Sebastian Graf
2个回答

4

看起来你的整个链条中所有内容都需要是公共的(并且你的List需要是List<IFoo>而不是List<Bar>):

public interface IFoo
{
    string Bar { get; }
}

public class Fizz
{
    public class Buzz : IFoo
    {
        public string Bar { get { return "something"; } }
    }

    public IEnumerable<IFoo> GetFoo()
    {
        List<IFoo> items = new List<IFoo>();
        // Populate items
        return items;
    }
}

你碰到的问题与跨程序集的反射有关。Silverlight 代码对你的内部类和接口进行了反射(类和接口默认为 internal)。即使是 Buzz,它也需要公开,因为它仍然需要反射该私有类,但失败了。
显然,如果你不在此处使用数据绑定,则代码将正常工作。即使 Buzz 是私有的,你也可以访问 IFoo。但是,一旦引入反射,不幸的是,你必须开始公开某些东西。

这对我解决了问题,谢谢!请注意,我不必将List<Bar>的类型更改为List<IFoo>。 - brantonb

1
问题在于你的 Buzz 类是私有的,因此绑定引擎无法访问该类的成员以执行绑定操作。

1
这是一个显而易见的结论,但可能不是唯一的结论 - 也就是说,ListBox的数据上下文可能也被搞砸了。 - slugster
没错,如果我的解决方案有误,那么发帖者可以随时评论告诉我,我们一起努力找到正确的解决方案 :) - Derek Lakin
@slugster:我想是这样,但他发布的错误消息清楚地表明这是访问冲突。此外,我们知道即使DataContext被正确设置(一个公平的假设),这段代码也不会起作用,因为所有东西都需要公开——接口、外部类和内部类——才能使反射工作。 - Brian Genisio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接