将附加属性绑定到 IEnumerable

本文关键字:IEnumerable 绑定 属性 | 更新日期: 2023-09-27 17:56:07

我正在使用新的 WPF 查看器在 C# 中用于水晶报表。由于我使用的是 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}"/>

我尝试以相同的方式绑定DataGridItemsSource并且有效,因此路径名或相似之处似乎没有错误。

任何帮助将不胜感激。多谢!

将附加属性绑定到 IEnumerable

使用依赖项属性,您只能确定的是,当属性更改时将调用属性更改的回调,并且如果调用 getter,则实际将更改基础属性。 这可能看起来很奇怪,但你的 getter 和 setter 只是访问该基础属性,因此,如果 XAML 分析器调用target.GetValue(SourceProperty)它会在不调用 getter 的情况下获取正确的内容。

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

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

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

如果初始绑定失败,请检查是否已设置 DataContext(到视图模型)、VM 上的属性名称是否正确以及属性是否具有公共 getter。

编辑:

这部分是错误的:

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

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

我终于找出问题出在哪里:

似乎CrystalReportViewer的数据上下文由于某种原因被覆盖了。因此,绑定在所有其他上下文中都有效(例如在DataGrid中),但在这里不行。我通过使用上面default.kramer提到的snoop工具发现了问题。我可以通过将绑定更改为

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

因此,它确实访问了UserControlDataContext(通常应该与特定控件的相同,但不适用于CrystalReportsViewer),并且它现在正在工作。

感谢大家的帮助!