将附加属性绑定到IEnumerable

时间:2011-05-10 20:54:49

标签: c# wpf binding crystal-reports attached-properties

我在C#中使用新的WPF Viewer for Crystal Reports。当我使用MVVM时,我真的想要绑定要显示的数据源而不是在加载的事件中执行此操作。因此,我想为源实现附加属性 - 但绑定不起作用,甚至不调用Getter方法。关于绑定附加属性的其他帖子也没有帮助,我不确定我在做什么不同。有人可以帮忙吗?这是附加属性的简化代码:

public static class CrystalReportsAttached {
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.RegisterAttached(
            "Source",
            typeof(IEnumerable),
            typeof(CrystalReportsAttached),
            new UIPropertyMetadata(new ObservableList<Participant>() as IEnumerable, SourceChanged));

    public static void SetSource(DependencyObject target, IEnumerable value) {
        target.SetValue(SourceProperty, value);
    }

    public static IEnumerable GetSource(DependencyObject target) {
        return (IEnumerable)target.GetValue(SourceProperty);
    }

    private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        CrystalReportsViewer reportViewer = d as CrystalReportsViewer;
        if (reportViewer != null) {
            MyCrystalReport report = new MyCrystalReport();
            report.SetDataSource(d.GetValue(SourceProperty) as IEnumerable);
            reportViewer.ViewerCore.ReportSource = report;
        }
    }
}

其中MyCrystalReport是我的rpt报告文件的包装器。

如果我现在这样绑定到源,它就不起作用了:

<my:CrystalReportsViewer prop:CrystalReportsAttached.Source="{Binding MyList, Mode=OneWay}"/>

我尝试以同样的方式绑定DataGrid s ItemsSource,这样就可以了,所以路径名称或smth似乎没有错误。

非常感谢任何帮助。非常感谢!

3 个答案:

答案 0 :(得分:2)

使用依赖项属性,您可以确定的是,当属性发生更改时,将调用属性更改的回调,并且实际更改基础属性如果调用了getter。这可能看起来很奇怪但是你的getter和setter只是访问那个底层属性,所以如果XAML解析器调用target.GetValue(SourceProperty)它就会得到正确的东西,而不会调用你的getter。

真正的问题是您的属性是否更改了回调被调用?

答案 1 :(得分:1)

要接收对集合的更改,源集合必须实现INotifyCollectionChanged。

您可以使用ObservableCollection,在线查找自定义通知集合,或使用您编写的实现内部集合和INotifyCollectionChanged接口的类包装现有集合。

如果初始绑定失败,请检查您是否已将DataContext(设置为View-Model),VM上的属性名称正确以及该属性具有公共getter。

编辑:

这部分错了:

new UIPropertyMetadata(new ObservableList<Participant>() as IEnumerable, SourceChanged));

您正在将相同的列表实例设置为所有控件的默认值。 改为在构造函数中设置默认值(在DP注册行中放置null)。

答案 2 :(得分:0)

我终于找到了问题所在:

似乎CrystalReportViewer的DataContext由于某种原因被覆盖。因此,绑定在每个其他上下文中工作(例如在DataGrid中),但不在此处。我使用上面snoop提到的default.kramer工具找到了问题。我可以通过将绑定更改为

来解决它
<my:CrystalReportsViewer prop:CrystalReportsAttached.Source="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.Participants, Mode=OneWay}"/>

所以它确实访问DataContext的{​​{1}}(通常应该与特定控件的UserControl相同,但不适用于CrystalReportsViewer)并且它现在正在运行

感谢大家的帮助!