0

I'm trying to create a custom control that has a header and a footer and body. The idea is that the body of the report is a custom stack panel control that will allow the user to indicate page orientation and grouping. I created a dependency property on the custom UC to accept an IList of the custom stack panel. What I am trying to do is bind to one of the stack panels in the list. But for some reason the binding is not working.

The ReportPage:

public class ReportPage : StackPanel
{
    //Nothing right now but will eventually include controls for page orientation and size (8.5x11, 11x17, etc.)
}

The UserControl code behind:

public partial class Report : UserControl, INotifyPropertyChanged
{
    public Report()
    {
        ReportPages = new List<ReportPage>();
    }

    public static readonly DependencyProperty =
        DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report));

    public IList ReportPages
    {
        get => (IList)GetValue(ReportPagesProperty);
        set
        {
            SetValue(ReportPagesProperty, value);
            ActivePage = value[0];
            OnPropertyChanged(nameof(ActivePage));
        }
    }

    private ReportPage _activePage;
    public ReportPage ActivePage
    {
         get => _activePage;
         set
         {
             _activePage = value;
             OnPropertyChanged(nameof(ActivePage));
         }
    {
}

The UserControl xaml:

<Grid>
    <!--Some xaml for the header and footer.-->
    <ContentControl Content="{Binding ActivePage, RelativeSource={RelativeSource, FindAncestor, AncestorType=local:Report}}"/>
</Grid>

Here is how I am consuming the custom control. This should, in my mind at least, make three "pages" which I can toggle between using a button control that I didn't share.

<reportEngine:Report>
    <reportEngine:Report.ReportPages>

        <reportEngine:ReportPage>
            <TextBlock>This is Page 1</TextBlock>
        </reportEngine:ReportPage>

        <reportEngine:ReportPage>
            <TextBlock>This is Page 2</TextBlock>
        </reportEngine:ReportPage>

        <reportEngine:ReportPage>
            <TextBlock>This is Page 3</TextBlock>
        </reportEngine:ReportPage>

    </reportEngine:Report.ReportPages>
</reportEngine:Report>

Any Ideas why the binding isn't working?

jwlford
  • 58
  • 8

1 Answers1

0

So I at least found a quick work around. I utilized the Collection Changed Event handler pattern from this answer and modified it for static dependency properties. Then, to get the values from the collection bound to the dependency property I create a static instance of the Report object in the constructor and use that to pass various values back to the object from the collection. Something like this:

public partial class Report : UserControl, INotifyPropertyChanged
{
    private static Report _thisReport;

    public Report()
    {
        InitializeComponent();
        ReportPages = new ObservableCollection<ReportPage>();
        _thisReport = this;
    }

    public static readonly DependencyProperty ReportPagesProperty =
        DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report), new FrameworkPropertyMetadata(ReportPagesChanged));

    public IList ReportPages
    {
        get => (IList)GetValue(ReportPagesProperty);
        set
        {
            SetValue(ReportPagesProperty, value);
            //Update some other properties associated with the control (Total Page Numbers, etc.)
        }
    }

    private static void ReportPagesChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
    {
        var newColl = (INotifyCollectionChanged)eventArgs.NewValue;
        if (newColl != null)
            newColl.CollectionChanged += ReportPages_CollectionChanged;

        var oldColl = (INotifyCollectionChanged)eventArgs.OldValue;
        if (oldColl != null)
            oldColl.CollectionChanged -= ReportPages_CollectionChanged;
    }

    private static void ReportPages_CollectionChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
    {
        var newPages = (IList<ReportPage>) sender;

        //Updates properties of the Report control.
        _thisReport.ActivePage = newPages[0];
        _thisReport.TotalPageNumber = newPages.Count;

    }
}

Whether this is "correct" or not I couldn't say, but it works. If someone has a better answer I will change the answer.

jwlford
  • 58
  • 8