Search code examples
c#wpfbindingcrystal-reportsattached-properties

Binding attached property to IEnumerable


I am using the new WPF Viewer for Crystal Reports in C#. As I am using MVVM, I would really like to bind the source of the data to be displayed instead of doing this in the loaded event. Therefore, I wanted to implement an attached property for the source - but the binding just doesn't work, the Getter method is not even called. The other posts about binding attached properties also didn't help and I am not sure what I am doing different. Can anybody help? Here is my simplified code for the attached property:

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;
        }
    }
}

where MyCrystalReport is the wrapper around my rpt report file.

If I bind to the source like this now, it's not working:

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

I tried to bind a DataGrids ItemsSource in the same way and that works, so there seems to be no mistake with the path name or smth similar.

Any help is greatly appreciated. Thanks a lot!


Solution

  • I finally figured out where the problem was:

    It seems like the CrystalReportViewer's DataContext is overridden for some reason. Therefore, the binding worked in every other context (e.g. in a DataGrid), but not here. I found out the problem by using the snoop tool mentioned by default.kramer above. I could fix it by changing the binding to

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

    so it does access the DataContext of the UserControl (which should usually be the same as the one for the specific control, but is not for CrystalReportsViewer) and it is working now.

    Thanks for everybody's help!