Как перевести все данные в главный поток для вывода отчёта?

Поскольку программа большая, выделю только те участки кода:

Есть WPF-объект с FlowDocument:
ReportEngine ReportView = new ReportEngine();

VisualSpaceReport.Document = ReportView.ReportData;

Он инициализируется и биндится при запуске программы. Остальное с ним работаю через методы.

Из события PropertyChangedEventArgs вызываю метод
UI.UI_ControlViewer.UI_Viewer.UI_Report.AddLog((sender as Libraries.Events).Value, e.PropertyName);

Сам метод выглядит так:
public void AddLog(object value, string propertyName)// => Dispatcher.InvokeAsync(() =>
{
    switch (propertyName)
    {
        case "Append":
            ReportView.Append(value as string, new Libraries.Interfaces.Formatting());
            break;
        case "Assign":
            ReportView.Assign(value as string);
            break;
        case "Create table":
            ReportView.Create(value as string);
            break;
        case "Close table":
            ReportView.Close(value as string);
            break;
        case "Table":

            switch (value)
            {
                case Structures.TableForProcessing.Add add_process:
                    ReportView.Add(add_process.id, add_process.text, add_process.value, add_process.formattingText, add_process.formattingValue);
                    break;

                case Structures.TableForProcessing.Assign assign_process:
                    ReportView.Assign(assign_process.id, assign_process.index, assign_process.value, assign_process.processing);
                    break;

                case Structures.TableForReporting.Setting setting_process:
                    ReportView.Setting(setting_process.id, setting_process.index, setting_process.background);
                    break;

                case Structures.TableForReporting.Add add:
                    ReportView.Add(add.id, add.text, add.value);    //?  add.formatting -- не работает (вызывает конфликт потока [Freezable])
                    break;

                case Structures.TableForReporting.Assign assign:
                    ReportView.Assign(assign.id, assign.index, assign.select, assign.value, assign.formatting);
                    break;
            }

            break;
        case "Appendf":

            switch (value)
            {
                case Structures.DataForReporting.Add add:
                    ReportView.Append(add.text, add.formatting); //?  add.formatting -- не работает (вызывает конфликт потока [Freezable])
                        break;
            }

            break;
    }

    VisualSpaceReport.FindScrollViewer()?.PageDown();
}//);


Dispatcher.InvokeAsync использую из-за того, что некоторые реализации не используют потоки, что вызывают зависания программы. Пришлось закомментировать, чтобы найти источник проблемы.
ReportView работает нормально, если находиться в основном потоке.
У меня данные приходят (в основном) из потоков. Вся большая часть кода работает нормально.
Но при заходе в Appendf у меня часто возникает сообщение:
"Не удается использовать объект DependencyObject, принадлежащий к другому потоку, отличному от его родительского объекта Freezable."

Проблема возникает именно при форматировании текста. Добавление просто текста работает нормально.
Как мне заставить перевести все эти данные в главный поток или как-то иначе решить проблему с потоками?

P.S. Дополню, как выглядит ReportView.Append и ReportView.Assign, а также общий для них статический метод, где и возникает проблема:
public void Append(string text, Interfaces.Formatting formatting = null) //! В отличие от Append в базовых классах он создаёт и добавляет текст. Вариант быстрого создания абзаца с текстом.
{
    if (formatting != null) formatting.Margin = new Thickness(0, 0, 0, 10);
    ReportData.Blocks.Add(Interfaces.Base.Paragraph.Create(formatting));
    Interfaces.Base.Paragraph.Assign(ReportData.Blocks.Last() as Paragraph, text, formatting);
}

public void Assign(string text, Interfaces.Formatting formatting = null)
{
    Interfaces.Base.Paragraph.Assign(ReportData.Blocks.Last() as Paragraph, text, formatting);
}


public static System.Windows.Documents.Paragraph Assign(System.Windows.Documents.Paragraph target, string text, Formatting formatting = null)
{
    ToSpan(target).Inlines.Clear();

    if (formatting != null)
        // здесь форматирование не работает от потоков, только те, которые находятся в главном потоке.
        ToSpan(target).Inlines.Add(new Run(text)
        {
            Background = formatting.Background,
            Foreground = formatting.Foreground,

            FontFamily = formatting.FontFamily,
            FontSize = formatting.FontSize,
            FontStretch = formatting.FontStretch,
            FontStyle = formatting.FontStyle,
            FontWeight = formatting.FontWeight,

            TextDecorations = formatting.TextDecoration
        });
    else
        ToSpan(target).Inlines.Add(text);

    return target;
}

И ещё заметил, что для Append и Assign разные типы исключений:
  • для Append:
    System.InvalidOperationException: "Вызывающий поток не может получить доступ к данному объекту, так как владельцем этого объекта является другой поток."

  • для Assign:
    System.InvalidOperationException: "Не удается использовать объект DependencyObject, принадлежащий к другому потоку, отличному от его родительского объекта Freezable."


Это происходит при использовании конструкции вызова:
Dispatcher.Invoke(() => { UI.UI_ControlViewer.UI_Viewer.UI_Report.AddLog((sender as Libraries.Events).Value, e.PropertyName); });


В ходе исследования выяснил, что не работают свойства Background, Foreground и TextDecoration. Любая попытка применить новые свойства к ним заканчивается исключением любого из двух типов, что было выше.
  • Вопрос задан
  • 365 просмотров
Пригласить эксперта
Ответы на вопрос 1
@CHolfield
Оберни вызов AddLog примерно так
ReportView.invoke((MethodInvoker)delegate
                {
                    AddLog();//параметры не забудь
                });
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы