How to add Grouping/LiveGrouping in ItemsControl's Items?

Emon Haque 3,176 Reputation points
2021-05-28T06:19:20.53+00:00

For printing in page, I've been using ItemsControl and up until now I haven't added grouping in such ItemsControls. When the Print function is called I add entries one by one in the ItemsControl's Items instead of using ItemsSource and observe whether the FixedPage has enough vertical space to display the entry. If not, I create new FixedPage, add that to FixedDocument and do the same. Here in my Receipt and Payments view, I've grouping and wanted to print with grouing:

100453-1.gif

BUT it doesn't show Groups in printed page. Here I've another demo project that also doesn't print group:

100439-2.gif

Here's the xaml in MainWndow.xaml:

<Window.Resources>  
    <local:CountryTemplate x:Key="country"/>  
    <local:CountryGroupTemplate x:Key="continent"/>  
</Window.Resources>  
<Grid Margin="20">  
    <Grid.ColumnDefinitions>  
        <ColumnDefinition/>  
        <ColumnDefinition/>  
    </Grid.ColumnDefinitions>  
    <ItemsControl   
        Margin="0 0 10 0"  
        ItemsSource="{Binding Countries}"  
        ItemTemplate="{StaticResource country}">  
        <ItemsControl.GroupStyle>  
            <GroupStyle>  
                <GroupStyle.ContainerStyle>  
                    <Style TargetType="GroupItem">  
                        <Setter Property="Template" Value="{StaticResource continent}"/>  
                    </Style>  
                </GroupStyle.ContainerStyle>  
            </GroupStyle>  
        </ItemsControl.GroupStyle>  
    </ItemsControl>  
    <Button Grid.Column="1" Content="Print" Click="Print"/>  
</Grid>  

and code in MainWindow.xaml.cs:

public partial class MainWindow : Window  
{  
    List<Country> countries;  
    public ICollectionView Countries { get; set; }  
    public MainWindow() {  
        InitializeComponent();          
        countries = new List<Country>() {  
            new Country{ Continent = "Asia", Name = "Bangladesh", Rank = 1 },  
            new Country{ Continent = "Asia", Name = "Pakistan", Rank = 1 },  
            new Country{ Continent = "Africa", Name = "Egypt", Rank = 2 },  
            new Country{ Continent = "Africa", Name = "Sudan" , Rank = 2 },  
            new Country{ Continent = "Europe", Name = "Poland" , Rank = 3 },  
            new Country{ Continent = "Europe", Name = "Finland", Rank = 3 }  
        };  
        Countries = new CollectionViewSource() {  
            Source = countries,  
            GroupDescriptions = { new PropertyGroupDescription(nameof(Country.Continent)) }  
        }.View;  
        DataContext = this;;  
    }  
    void Print(object sender, RoutedEventArgs e) {  
        var dialog = new PrintDialog();  
        if (dialog.ShowDialog() != true) return;  
        var size = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);  
        var document = new FixedDocument();  
        var page = new PrintablePage(size);  
        document.Pages.Add(new PageContent() { Child = page.Page });  
        document.DocumentPaginator.PageSize = size;  
        foreach (var country in countries)   
            page.AddEntry(country);  
          
        dialog.PrintDocument(document.DocumentPaginator, "");  
    }  
}  
public class Country  
{  
    public string Continent { get; set; }  
    public string Name { get; set; }  
    public int Rank { get; set; }  
}  
public class PrintablePage  
{  
    double margin;  
    ItemsControl content;  
    public FixedPage Page { get; set; }  
    public Size PageSize { get; set; }  
    public PrintablePage(Size pageSize) {  
        margin = 96d * 0.7;  
        PageSize = pageSize;  
        initContent();  
        Page = new FixedPage() {  
            Width = PageSize.Width,  
            Height = PageSize.Height,  
            Margin = new Thickness(margin),  
            Children = { content }  
        };  
        measure();  
    }  
    public void AddEntry(Country country) {  
        content.Items.Add(country);  
        content.Items.Refresh();  
        content.UpdateLayout();  
    }  
    void measure() {  
        var availableSize = new Size(PageSize.Width - 2 * margin, PageSize.Height - 2 * margin);  
        foreach (FrameworkElement item in Page.Children) {  
            item.Width = availableSize.Width;  
            item.Measure(availableSize);  
        }  
        FixedPage.SetTop(content, 0);  
    }  
    void initContent() {  
        content = new ItemsControl() {  
            HorizontalContentAlignment = HorizontalAlignment.Stretch,  
            ItemTemplate = new CountryTemplate(),  
            GroupStyle = {  
                new GroupStyle() {  
                    ContainerStyle = new Style(typeof(GroupItem)) {  
                        Setters = {  
                            new Setter(GroupItem.TemplateProperty, new CountryGroupTemplate())  
                        }  
                    }  
                }  
            }  
        };  
        content.Items.GroupDescriptions.Add(new PropertyGroupDescription(nameof(Country.Continent)));  
        content.Items.LiveGroupingProperties.Add(nameof(Country.Continent));  
        content.Items.IsLiveGrouping = true;  
    }  
}  
public class CountryTemplate : DataTemplate  
{  
    public CountryTemplate() {  
        var grid = new FrameworkElementFactory(typeof(Grid));  
        var col1 = new FrameworkElementFactory(typeof(ColumnDefinition));  
        var col2 = new FrameworkElementFactory(typeof(ColumnDefinition));  
        var name = new FrameworkElementFactory(typeof(TextBlock));  
        var rank = new FrameworkElementFactory(typeof(TextBlock));  
        col2.SetValue(ColumnDefinition.WidthProperty, new GridLength(100));  
        rank.SetValue(Grid.ColumnProperty, 1);  
        rank.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right);  
        name.SetBinding(TextBlock.TextProperty, new Binding(nameof(Country.Name)));  
        rank.SetBinding(TextBlock.TextProperty, new Binding(nameof(Country.Rank)));  
        grid.AppendChild(col1);  
        grid.AppendChild(col2);  
        grid.AppendChild(name);  
        grid.AppendChild(rank);  
        VisualTree = grid;  
    }  
}  
public class CountryGroupTemplate : ControlTemplate  
{  
    public CountryGroupTemplate() {  
        TargetType = typeof(GroupItem);  
        var grid = new FrameworkElementFactory(typeof(Grid));  
        var row1 = new FrameworkElementFactory(typeof(RowDefinition));  
        var row2 = new FrameworkElementFactory(typeof(RowDefinition));  
        var header = new FrameworkElementFactory(typeof(TextBlock));  
        var items = new FrameworkElementFactory(typeof(ItemsPresenter));  
        row1.SetValue(RowDefinition.HeightProperty, GridLength.Auto);  
        items.SetValue(Grid.RowProperty, 1);  
        items.SetValue(ItemsPresenter.MarginProperty, new Thickness(10, 0, 0, 0));  
        header.SetBinding(TextBlock.TextProperty, new Binding(nameof(GroupItem.Name)));  
        grid.AppendChild(row1);  
        grid.AppendChild(row2);  
        grid.AppendChild(header);  
        grid.AppendChild(items);  
        VisualTree = grid;  
    }  
}  

of the demo project. In PrintablePage class I initialized the ItemsControl in initContent and when button is clicked, I call AddEntry of the same class. How to add grouping in ItemsControl.Items?

Developer technologies | Windows Presentation Foundation
{count} votes

Accepted answer
  1. Emon Haque 3,176 Reputation points
    2021-06-09T18:25:54.587+00:00

    Here's an alternative solution with some crazy LINQ and nested foreach. First, I've these in print function:

    void print() {  
        var dialog = new PrintDialog();  
        if (dialog.ShowDialog() != true) return;  
        var width = dialog.PrintableAreaWidth;  
        var height = dialog.PrintableAreaHeight;  
        var groupedEntries =   
            rps.GroupBy(x => x.Control)  
            .Select(x => new {  
                Name = x.Key,  
                Cash = x.Sum(x => x.Cash),  
                Kind = x.Sum(x => x.Kind),  
                Total = x.Sum(x => x.Total),  
                Head = x.GroupBy(x => x.Head)  
                .Select(x => new {  
                    Name = x.Key,  
                    Cash = x.Sum(x => x.Cash),  
                    Kind = x.Sum(x => x.Kind),  
                    Total = x.Sum(x => x.Total),  
                    Plot = x.GroupBy(x => x.Plot)  
                    .Select(x => new {  
                        Name = x.Key,  
                        Cash = x.Sum(x => x.Cash),  
                        Kind = x.Sum(x => x.Kind),  
                        Total = x.Sum(x => x.Total),  
                        Tenant = x.GroupBy(x => x.Tenant)  
                        .Select(x => new {  
                            Name = x.Key,  
                            Cash = x.Sum(x => x.Cash),  
                            Kind = x.Sum(x => x.Kind),  
                            Total = x.Sum(x => x.Total),  
                            Entry = x  
                        })  
                    })  
                })  
            });  
        List<object> list = new();  
        foreach (var control in groupedEntries) {  
            list.Add(new Tuple<int, string>(0, control.Name));  
            foreach (var head in control.Head) {  
                list.Add(new Tuple<int, string>(1, head.Name));  
                foreach (var plot in head.Plot) {  
                    list.Add(new Tuple<int, string>(2, plot.Name));  
                    foreach (var tenant in plot.Tenant) {  
                        if(tenant.Entry.Count() > 1) {  
                            list.Add(new Tuple<int, string>(3, tenant.Name));  
                            foreach (var entry in tenant.Entry)   
                                list.Add(new Tuple<int, ReceiptPayment>(4, entry));  
                            list.Add(new Tuple<int, string, int, int, int>(3, tenant.Name, tenant.Cash, tenant.Kind, tenant.Total));  
                        }  
                        else list.Add(new Tuple<int, ReceiptPayment>(3, tenant.Entry.First()));  
                    }  
                    list.Add(new Tuple<int, string, int, int, int>(2, plot.Name, plot.Cash, plot.Kind, plot.Total));  
                }  
                list.Add(new Tuple<int, string, int, int, int>(1, head.Name, head.Cash, head.Kind, head.Total));  
            }  
            list.Add(new Tuple<int, string, int, int, int>(0, control.Name, control.Cash, control.Kind, control.Total));  
        }  
        var document = new FixedDocument();  
        var size = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);  
        document.DocumentPaginator.PageSize = size;  
        var pages = new List<RPPage>();  
        var page = getPage(document, null);  
        pages.Add(page);  
        for (int i = 0; i < list.Count; i++) {  
            if (!page.AddEntry(list[i])) {  
                page = getPage(document, page);  
                page.AddEntry(list[i]);  
                pages.Add(page);  
            }  
        }  
        foreach (var p in pages)   
            p.NumberOfPage = document.Pages.Count;  
              
        dialog.PrintDocument(document.DocumentPaginator, "");  
    }  
    

    in the nested foreach I create Tuple for these 3 ContentControls:

    class RPHeaderItem : ContentControl  
    {  
        public RPHeaderItem(Tuple<int, string> header) {  
            Content = new TextBlock() {  
                FontWeight = FontWeights.Bold,  
                Margin = new Thickness(10 * header.Item1, 0, 0, 0),  
                Text = header.Item2  
            };  
        }  
    }  
    class RPEntryItem : ContentControl  
    {  
        public RPEntryItem(Tuple<int, ReceiptPayment> entry) {  
            var text = new TextBlock() {  
                Margin = new Thickness(10 * entry.Item1, 0, 0, 0),  
                HorizontalAlignment = HorizontalAlignment.Left  
            };  
            var cash = new TextBlock() { Text = entry.Item2.Cash.ToString(Constants.NumberFormat) };  
            var kind = new TextBlock() { Text = entry.Item2.Kind.ToString(Constants.NumberFormat) };  
            var total = new TextBlock() { Text = entry.Item2.Total.ToString(Constants.NumberFormat) };  
    
            if (entry.Item1 == 3) {  
                var tenant = new Run() { Text = entry.Item2.Tenant };  
                var space = new Run() { Text = " - " + entry.Item2.Space };  
                text.Inlines.Add(tenant);  
                text.Inlines.Add(space);  
            }  
            else text.Text = entry.Item2.Space;  
    
            Grid.SetColumn(cash, 1);  
            Grid.SetColumn(kind, 2);  
            Grid.SetColumn(total, 3);  
            Content = new Grid() {  
                ColumnDefinitions = {  
                    new ColumnDefinition(),  
                    new ColumnDefinition(){ Width = new GridLength(70) },  
                    new ColumnDefinition(){ Width = new GridLength(70) },  
                    new ColumnDefinition(){ Width = new GridLength(70) }  
                },  
                Resources = {  
                    {  
                        typeof(TextBlock),  
                        new Style() {  
                            Setters = {  
                                new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right)  
                            }  
                        }  
                    }  
                },  
                Children = { text, cash, kind, total }  
            };  
        }  
    }  
    class RPFooterItem : ContentControl  
    {  
        public RPFooterItem(Tuple<int, string, int, int, int> footer) {  
            var text = new TextBlock() {  
                Margin = new Thickness(10 * footer.Item1, 0, 0, 0),  
                Text = "Total " + footer.Item2,  
                HorizontalAlignment = HorizontalAlignment.Left,  
    
            };  
            var cash = new TextBlock() { Text = footer.Item3.ToString(Constants.NumberFormat) };  
            var kind = new TextBlock() { Text = footer.Item4.ToString(Constants.NumberFormat) };  
            var total = new TextBlock() { Text = footer.Item5.ToString(Constants.NumberFormat) };  
            var separator = new Separator() { Background = Brushes.Black };  
            Grid.SetColumn(cash, 1);  
            Grid.SetColumn(kind, 2);  
            Grid.SetColumn(total, 3);  
            Grid.SetColumn(separator, 1);  
            Grid.SetColumnSpan(separator, 3);  
            Content = new Grid() {  
                RowDefinitions = {  
                    new RowDefinition(){ Height = GridLength.Auto },  
                    new RowDefinition()  
                },  
                ColumnDefinitions = {  
                    new ColumnDefinition(),  
                    new ColumnDefinition(){ Width = new GridLength(70) },  
                    new ColumnDefinition(){ Width = new GridLength(70) },  
                    new ColumnDefinition(){ Width = new GridLength(70) }  
                },  
                Resources = {  
                    {  
                        typeof(TextBlock),  
                        new Style() {  
                            Setters = {  
                                new Setter(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Right),  
                                new Setter(Grid.RowProperty, 1)  
                            }  
                        }  
                    }  
                },  
                Children = { separator, text, cash, kind, total }  
            };  
        }  
    }  
    

    and these ContentControl are directly added to the ItemsControl in AddEntry function:

    public bool AddEntry(object entry) {  
        ContentControl content;  
        if (entry is Tuple<int, string>) content = new RPHeaderItem((Tuple<int, string>)entry);  
        else if (entry is Tuple<int, ReceiptPayment>) content = new RPEntryItem((Tuple<int, ReceiptPayment>)entry);  
        else content = new RPFooterItem((Tuple<int, string, int, int, int>)entry);  
        content.Measure(PageSize);  
        content.UpdateLayout();  
        remainingHeight -= content.DesiredSize.Height;  
        if (remainingHeight < 0) return false;  
        entries.Items.Add(content);  
        return true;  
    }   
    

    not bad!

    103886-test.gif

    EDIT
    ----
    There's one more issue with this printing. When I print as PDF it always shows all entries I added in a page. In real printing on page sometimes I miss the last added entry in a page. To solve the issue, I'd to add the IsComplete property back and when a page completes, I set that to true in viewmodel and in the setter of that property I've to call entries.UpdateLayout() to get the last added entry on real page.

    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Emon Haque 3,176 Reputation points
    2021-05-28T11:47:01.213+00:00

    Not sure whether it's possible with ItemsControl.Items BUT it works if I have a ICollectionView in the PrintablePage class:

    100515-test.gif

    and it takes some time before printing because of those Refresh, UpdateLayout and Measure for each entry. Is there any better way?


  2. Emon Haque 3,176 Reputation points
    2021-05-31T10:18:07.893+00:00

    In my viewmodel, I've these two methods for printing:

    void print() {
        var dialog = new PrintDialog();
        if (dialog.ShowDialog() != true) return;
        var size = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);
        var document = new FixedDocument();
        document.DocumentPaginator.PageSize = size;
        var pages = new List<RPPage>();
    
        var page = getPage(document, null);
        pages.Add(page);
        for (int i = 0; i < rps.Count; i++) {
            if (!page.AddEntry(rps[i])) {
                page.IsComplete = true;
                page = getPage(document, page);
                page.AddEntry(rps[i]);
                pages.Add(page);
            }
        }
        page.IsComplete = true;
        foreach (var p in pages) {
            p.NumberOfPage = document.Pages.Count;
        }
        dialog.PrintDocument(document.DocumentPaginator, "");
    }
    RPPage getPage(FixedDocument doc, RPPage previousPage) {
        RPPage page;
        if (previousPage == null) {
            page = new RPPage(doc.DocumentPaginator.PageSize) {
                Title = "Receipt and Payments",
                Period = "for the period from " + from.Value.ToString("dd MMMM yyyy") + " to " + to.Value.ToString("dd MMMM yyyy"),
                FootNote = $"Generated on {DateTime.Now.ToString("dd MMMM, yyyy | hh:mm:ss tt")}",
            };
        }
        else page = new RPPage(previousPage);
        doc.Pages.Add(new PageContent() { Child = page.Page });
        return page;
    }
    

    and here's the related code for PrintablePage, in my app it's actually named RPPage:

    class RPPage
    {
        double margin, remainingHeight;
        StackPanel header;
        Grid content;
        Border footer, columnNames, pageTotal;
        TextBlock title, period, totalCash, totalKind, totalTotal, footNoteBlock;
        ItemsControl entries;
        Run currentPage, totalPage;
        ICollectionView view;
        List<object> entryList;
    
        public FixedPage Page { get; set; }
        public Size PageSize { get; set; }
        public int PageNo { get; set; }
        public string Title { get; set; }
        public string Period { get; set; }
        public int TotalCash { get; set; }
        public int TotalKind { get; set; }
        public int TotalTotal { get; set; }
        string footNote;
        public string FootNote {
            get { return footNote; }
            set { footNote = value; footNoteBlock.Text = value; measure(); }
        }
        bool isComplete;
        public bool IsComplete {
            get { return isComplete; }
            set { isComplete = value; addPageTotals(); }
        }
        int numberOfPage;
        public int NumberOfPage {
            get { return numberOfPage; }
            set { numberOfPage = value; totalPage.Text = value.ToString(); }
        }
    
        public RPPage(Size pageSize) {
            margin = 96d * 0.7;
            entryList = new List<object>();
            view = new CollectionViewSource() {
                Source = entryList,
                GroupDescriptions = {
                    new PropertyGroupDescription(nameof(ReceiptPayment.Control)),
                    new PropertyGroupDescription(nameof(ReceiptPayment.Head)),
                    new PropertyGroupDescription(nameof(ReceiptPayment.Plot)),
                    new PropertyGroupDescription(nameof(ReceiptPayment.Tenant))
                }
            }.View;
            initializeHeader();
            initializeContent();
            initializeFooter();
            PageSize = pageSize;
            PageNo = 1;
            Page = new FixedPage() {
                Width = PageSize.Width,
                Height = PageSize.Height,
                Margin = new Thickness(margin),
                Children = { header, content, footer }
            };
    
        }
        public RPPage(RPPage previousPage) : this(previousPage.PageSize) {
            Title = previousPage.Title;
            Period = previousPage.Period;
            PageNo = previousPage.PageNo + 1;
            FootNote = previousPage.FootNote;
            AddEntry(new ReceiptPayment() {
                Control = "balance b/d",
                Cash = previousPage.TotalCash,
                Kind = previousPage.TotalKind,
                Total = previousPage.TotalTotal
            });
        }
        void initializeHeader() {
            title = new TextBlock() { FontSize = 16, TextAlignment = TextAlignment.Center };
            period = new TextBlock() { FontSize = 12, TextAlignment = TextAlignment.Center };
    
            var colParticulars = new TextBlock() { Text = "Particulars", HorizontalAlignment = HorizontalAlignment.Left };
            var colReceivable = new TextBlock() { Text = "Cash", HorizontalAlignment = HorizontalAlignment.Right };
            var colReceipt = new TextBlock() { Text = "Kind", HorizontalAlignment = HorizontalAlignment.Right };
            var colBalance = new TextBlock() { Text = "Total", HorizontalAlignment = HorizontalAlignment.Right };
    
            Grid.SetColumn(colReceivable, 1);
            Grid.SetColumn(colReceipt, 2);
            Grid.SetColumn(colBalance, 3);
            var columnGrid = new Grid() {
                ColumnDefinitions = {
                    new ColumnDefinition(),
                    new ColumnDefinition(){ Width = new GridLength(70) },
                    new ColumnDefinition(){ Width = new GridLength(70) },
                    new ColumnDefinition(){ Width = new GridLength(70) }
                },
                Children = { colParticulars, colReceivable, colReceipt, colBalance }
            };
            columnNames = new Border() {
                BorderThickness = new Thickness(0, .5, 0, .5),
                BorderBrush = Brushes.Black,
                Child = columnGrid
            };
            header = new StackPanel() {
                Resources = {
                    {
                        typeof(TextBlock),
                        new Style() {
                            Setters = {
                                new Setter(TextBlock.FontWeightProperty, FontWeights.Bold)
                            }
                        }
                    }
                },
                Children = { title, period, columnNames }
            };
        }
        void initializeContent() {
            entries = new ItemsControl() { 
                ItemsSource = view,
                ItemTemplate = new RPTemplate(null, null),
                GroupStyle = {
                    new GroupStyle() {
                        ContainerStyle = new Style(typeof(GroupItem)) {
                            Setters = {
                                new Setter(GroupItem.TemplateProperty, new GroupedRPTemplate(null, null, 0))
                            }
                        }
                    }
                }
            };
            var totalText = new TextBlock() { Text = "Total", FontWeight = FontWeights.Bold };
            totalCash = new TextBlock() {
                FontWeight = FontWeights.Bold,
                HorizontalAlignment = HorizontalAlignment.Right
            };
            totalKind = new TextBlock() {
                FontWeight = FontWeights.Bold,
                HorizontalAlignment = HorizontalAlignment.Right
            };
            totalTotal = new TextBlock() {
                FontWeight = FontWeights.Bold,
                HorizontalAlignment = HorizontalAlignment.Right
            };
            Grid.SetColumn(totalCash, 1);
            Grid.SetColumn(totalKind, 2);
            Grid.SetColumn(totalTotal, 3);
            var totalGrid = new Grid() {
                ColumnDefinitions = {
                    new ColumnDefinition(),
                    new ColumnDefinition(){ Width = new GridLength(70) },
                    new ColumnDefinition(){ Width = new GridLength(70) },
                    new ColumnDefinition(){ Width = new GridLength(70) }
                },
                Children = { totalText, totalCash, totalKind, totalTotal }
            };
            pageTotal = new Border() {
                BorderThickness = new Thickness(0, .5, 0, 0),
                BorderBrush = Brushes.Black,
                Child = totalGrid
            };
            Grid.SetRow(pageTotal, 1);
            content = new Grid() {
                RowDefinitions = {
                    new RowDefinition(){ Height = GridLength.Auto },
                    new RowDefinition(){ Height = GridLength.Auto }
                },
                Children = { entries, pageTotal }
            };
        }
        void initializeFooter() {
            footNoteBlock = new TextBlock();
            currentPage = new Run();
            totalPage = new Run();
            var pageNo = new TextBlock() {
                Inlines = {
                    currentPage,
                    new Run(){Text = "/" },
                    totalPage
                }
            };
            Grid.SetColumn(pageNo, 1);
            var grid = new Grid() {
                ColumnDefinitions = {
                    new ColumnDefinition(),
                    new ColumnDefinition(){ Width = GridLength.Auto }
                },
                Children = { footNoteBlock, pageNo }
            };
            footer = new Border() {
                BorderThickness = new Thickness(0, .5, 0, 0),
                BorderBrush = Brushes.Black,
                Child = grid
            };
        }
        void measure() {
            var availableSize = new Size(PageSize.Width - 2 * margin, PageSize.Height - 2 * margin);           
            title.Text = Title;
            period.Text = Period;
            currentPage.Text = "Page: " + PageNo;
    
            double y = 0;
            foreach (FrameworkElement item in Page.Children) {
                item.Width = availableSize.Width;
                item.Measure(availableSize);
                FixedPage.SetTop(item, y);
                y += item.DesiredSize.Height;
            }
            var contentHeight = availableSize.Height - header.DesiredSize.Height - footer.DesiredSize.Height;
            content.Height = contentHeight;
            remainingHeight = contentHeight - pageTotal.DesiredSize.Height;
            FixedPage.SetTop(footer, header.DesiredSize.Height + contentHeight);
        }
        public bool AddEntry(ReceiptPayment entry) {
            entryList.Add(entry);
            view.Refresh();
            entries.UpdateLayout();
            entries.Measure(PageSize);
            TotalCash += entry.Cash;
            TotalKind += entry.Kind;
            TotalTotal += entry.Total;
            if (remainingHeight < entries.DesiredSize.Height) {
                entryList.Remove(entry);
                view.Refresh();
                entries.UpdateLayout();
    
                TotalCash -= entry.Cash;
                TotalKind -= entry.Kind;
                TotalTotal -= entry.Total;
                return false;
            }
            return true;
        }
        void addPageTotals() {
            totalCash.Text = TotalCash.ToString(Constants.NumberFormat);
            totalKind.Text = TotalKind.ToString(Constants.NumberFormat);
            totalTotal.Text = TotalTotal.ToString(Constants.NumberFormat);
        }
    }
    
    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.