Ошибка сериализации потокового документа WPF при очистке блоков

#wpf #richtextbox #flowdocument

#wpf #richtextbox #потоковый документ

Вопрос:

У меня есть пользовательский класс WPF, подкласс RickTextBox, поэтому я могу добавлять встроенные дисплеи для пользовательских объектов данных. Иногда мне нужно все очистить и перестроить документ из списка классов. Однако, когда я это делаю, я получаю странную ошибку:

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

Я действительно понятия не имею, что может быть причиной этого. Я не выполняю никакой явной сериализации, поэтому что-то внутри WPF пытается. Кто-нибудь знает, что происходит?

К вашему сведению, вот настраиваемое встроенное отображение для моего объекта (не волнуйтесь, работа с кодом в конечном итоге перейдет на XAML). Я сузил проблему до CellVMs , что является 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;
    }
  

и вот код для перестроения документа.

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

        }
  

Комментарии:

1. У вас есть пример проекта, который я могу воспроизвести?

2. Возможно, я мог бы попытаться собрать что-нибудь вместе, когда вернусь к работе на следующей неделе. В итоге я решил обойти проблему, не используя ObservableCollection непосредственно в моих классах. Я явно создал отдельную специализированную ObservableCollection, используя шаблон, например, класс MyObservableCollection : ObservableCollection<MyObject>

Ответ №1:

У меня была та же проблема, не удается очистить BlockCollection , потому что используйте потоковый документ в обоих местах: печать и предварительный просмотр. Run ‘s и другие элементы atom должны использоваться один раз (с одним родителем).

Итак, это решается путем копирования встроенных элементов перед вторым добавлением:

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