-1

I have a custom WPF class subclassing RickTextBox so I can add inline displays for custom data objects. Occasionally, I need to clear everything and rebuild the document from the list of classes. When I do that, though, I get a strange error:

doc.Blocks.Clear();  // <-- Error at this line
--------------------------------------------------------------
Additional information: Cannot serialize a generic type System.Collections.ObjectModel.ObservableCollection [System.Collections.ObjectModel.ObservableCollection ...

I really have no clue what could be causing this. I'm not doing any explicit serialization so something within WPF is trying to. Does anybody know what's going on?

FYI, here is the custom inline display for my object (don't worry, the code-behind work will eventually migrate to XAML). I've narrowed the problem down to CellVMs, which is an IEnumerable<IEnumerable<ReportTableCellViewModel>>

public class ReportTableRun : InlineUIContainer
    {
        public ReportTableRun() : this(null)
        {
        }

        public ReportTableRun(ReportTableViewModel table, DataTemplate cellTemplate=null) : base()
        {
            mTable = table;

            DynamicGrid grid = new DynamicGrid();
            grid.DefaultRowHeight = new GridLength(50);
            grid.DefaultColumnWidth = new GridLength(50);

            Binding bind0 = new Binding("CellVMs");
            bind0.Mode = BindingMode.OneWay;
            bind0.Source = mTable;
            BindingOperations.SetBinding(grid, DynamicGrid.ItemsSourceProperty, bind0);

            Binding bind3 = new Binding("RowSharedGroupNames");
            bind3.Mode = BindingMode.OneWay;
            bind3.Source = mTable;
            BindingOperations.SetBinding(grid, DynamicGrid.RowSharedSizeGroupNamesProperty, bind3);

            Binding bind4 = new Binding("ColumnSharedGroupNames");
            bind4.Mode = BindingMode.OneWay;
            bind4.Source = mTable;
            BindingOperations.SetBinding(grid, DynamicGrid.ColumnSharedSizeGroupNamesProperty, bind4);

            grid.ItemTemplate = cellTemplate;

            this.Child = grid;
        }

        private ReportTableViewModel mTable;
    }

and here is the code for rebuilding the document.

private void BuildDocument()
        {
            FlowDocument doc = Document;

            IEnumerable<IReportComponentViewModel> components = ReportTemplateViewModel.ComponentVMs;
            List<Paragraph> parList = new List<Paragraph>();
            Paragraph par = new Paragraph();
            parList.Add(par);
            foreach(IReportComponentViewModel c in components)
            {
                if (c is ReportTableViewModel)
                    par.Inlines.Add(new ReportTableRun(c as ReportTableViewModel, ReportTableCellTemplate));
            }

            doc.Blocks.Clear();
            foreach(Paragraph p in parList)
                doc.Blocks.Add(p);

        }
ryan0270
  • 1,135
  • 11
  • 33
  • You have a sample project I can reproduce this? – 123 456 789 0 Jul 03 '14 at 02:36
  • I could perhaps try to put something together when I get back to work next week. I ended up getting around the problem by not using ObservableCollection directly in on my my classes. I made a separate specialized ObservableCollection explicitly using the template, e.g. class MyObservableCollection : ObservableCollection – ryan0270 Jul 03 '14 at 12:26

1 Answers1

0

I had the same problem, can't clear BlockCollection, because use the FlowDocument in both places: print and preview. Run's and other atom elements must be single-used (with one parent).

So, it solved by copying inline elements before second adding:

    Inline CopyInline(Inline iln)
    {
        string strType;
        Inline ilnRes;
        strType = (string)SpIntConst.GetLastElement(iln.GetType().ToString().Split('.'));
        switch (strType)
        {
            case "Run":
                ilnRes = new Run(((Run)iln).Text) { Style = iln.Style };
                break;
            case "Bold":
                Inline newInl;
                Bold boldSend;
                boldSend = iln as Bold;
                newInl = CopyInline(boldSend.Inlines.ElementAt(0));
                ilnRes = new Bold(newInl);
                break;
            case "InlineUIContainer":
                ilnRes = new InlineUIContainer(_gGraph.GraphImage);
                break;
            default:
                ilnRes = null;
                break;
        }
        return ilnRes;
    }
    Paragraph CopyParagraph(Paragraph par)
    {
        Paragraph parRes = new Paragraph();
        foreach (Inline iln in par.Inlines)
            parRes.Inlines.Add(CopyInline(iln));
        return parRes;
    }
    TableCell CopyTableCell(TableCell tblCell)
    {
        TableCell tblCellRes = new TableCell() { Style = tblCell.Style };
        return tblCellRes;
    }
    TableRow CopyTableRow(TableRow tr)
    {
        TableRow trRes = new TableRow();
        foreach (TableCell tblCell in tr.Cells)
            trRes.Cells.Add(CopyTableCell(tblCell));
        return trRes;
    }
    TableRowGroup CopyTableRowGroup(TableRowGroup trg)
    {
        TableRowGroup trgRes = new TableRowGroup();
        foreach (TableRow tr in trg.Rows)
            trgRes.Rows.Add(CopyTableRow(tr));
        return trgRes;
    }
    Table CopyTable(Table tbl)
    {
        Table tblRes = new Table();
        for (int i = 0; i < tbl.Columns.Count; i++)
            tblRes.Columns.Add(new TableColumn() { Width = tbl.Columns[i].Width });
        foreach (TableRowGroup trg in tbl.RowGroups)
            tblRes.RowGroups.Add(CopyTableRowGroup(trg));
        return tblRes;
    }
    Block CopyBlock(Block bl)
    {
        string type;
        Block blRes;
        type = (string)SpIntConst.GetLastElement(bl.GetType().ToString().Split('.'));
        switch (type)
        {
            case "Paragraph":
                Paragraph par = bl as Paragraph;
                blRes = CopyParagraph(par);
                break;
            case "Table":
                Table tbl = bl as Table;
                blRes = CopyTable(tbl);
                break;
            default:
                blRes = null;
                break;
        }
        return blRes;
    }
    FlowDocument CopyDoc(FlowDocument fd)
    {
        FlowDocument fdRes = new FlowDocument()
        {
            PageWidth = fd.PageWidth,
            PageHeight = fd.PageHeight,
            PagePadding = fd.PagePadding
        };
        foreach (Block bl in fd.Blocks)
            fdRes.Blocks.Add(CopyBlock(bl));
        return fdRes;
    }
    private void btnPreview_Click(object sender, RoutedEventArgs e)
    {
        SetParams();
        PrintPreview pp = new PrintPreview(CopyDoc(_doc), _mw.CurrHelpPath);
        ...
    }