Имейте объект с очень легкими большинством свойств - текст до 200 символов. Одним из свойств является FlowDocument, которое может быть большим и хотеть получить его Async. Сбой, когда я устанавливаю Async = True с сообщением: «Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им.»
<FlowDocumentReader Name="FlowDocumentPageViewer1" HorizontalAlignment="Stretch"
Document="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.Search.SelectedDoc.DocFlowDocument, Mode=OneWay, IsAsync=True}" />
Production Get является более сложным, но тот же сбой в IsAsyc True, даже с простым жестко закодированным FlowDocument.
public FlowDocument DocFlowDocument
{
get
{
FlowDocument docFlowDocumentFast = new FlowDocument();
Paragraph p = new Paragraph();
Run r = new Run();
r.Foreground = System.Windows.Media.Brushes.Red;
r.Text = "Hard Code Simple FlowDocument";
p.Inlines.Add(r);
docFlowDocumentFast.Blocks.Add(p);
return docFlowDocumentFast;
}
{
Он вызывает SelectedDoc.DocFlowDocument и документ возвращается!
С IsAsync = False он работает просто отлично.
Я думаю, что проблема в статическом источнике, но, очевидно, я не знаю, как это исправить.
public partial class App : Application
{
private static GabeLib staticGabeLib = new GabeLib();
private GabeLib myGabeLib = staticGabeLib;
public GabeLib MyGabeLib
{ get { return myGabeLib; } }
public static GabeLib StaticGabeLib
{ get { return staticGabeLib; } }
}
Когда GabeLib запускается, он считывает настройки приложения и пользователя из базы данных.
Если есть лучший способ приблизиться к этому, я попробую. Поскольку FlowDocument может иметь размер 3 МБ, а все остальные свойства 10 КБ вместе взятые, это большой удар по производительности, и наиболее часто используемая кнопка - следующий объект. FlowDocument происходит из varchar (max) в SQL и форматируется с выделением разрывов строк и слов. Он не просто большой - по сравнению с другими объектами он также дорогой.
Похоже, что сам FlowDocumentReader имеет некоторую асинхронную поддержку, поскольку в большом документе я быстро получаю первую страницу, а затем страницы загружаются со скоростью около 100 в секунду. Но я все еще хотел бы получить страницу 1 после того, как все остальные свойства будут восстановлены.
Проблема была, как сказал Мартин: «Поскольку FlowDocument является объектом диспетчера, доступ к нему возможен только из потока, который его создал».
Решение состояло в том, чтобы сериализовать в строку XAML.
public string XAMLdocFlowDocument
{
get
{
Thread.Sleep(6000);
return XamlWriter.Save(FlowDocumentSlow);
}
}
Привязка к строке с помощью конвертера
<FlowDocumentReader Grid.Row="3" Grid.Column="0" VerticalAlignment="Stretch"
Document="{Binding Path=XAMLdocFlowDocument, IsAsync=True,
Converter={StaticResource flowDocumentToXamlConverter}, Mode=OneWay}" />
Конвертер
[ValueConversion(typeof(string), typeof(FlowDocument))]
public class FlowDocumentToXamlConverter : IValueConverter
{
#region IValueConverter Members
/// <summary>
/// Converts from XAML markup to a WPF FlowDocument.
/// </summary>
public object Convert(object value, System.Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
var flowDocument = new FlowDocument();
if (value != null)
{
var xamlText = (string)value;
flowDocument = (FlowDocument)XamlReader.Parse(xamlText);
}
// Set return value
return flowDocument;
}