Сбой привязки WPF к IsAsync - PullRequest
       35

Сбой привязки WPF к IsAsync

1 голос
/ 16 сентября 2011

Имейте объект с очень легкими большинством свойств - текст до 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;
        }

1 Ответ

2 голосов
/ 17 сентября 2011

Не видя код, я предполагаю, что FlowDocument создается (и загружается) при чтении свойства. Это делается в фоновом потоке, поскольку привязка свойства асинхронна.

Поскольку FlowDocument является объектом диспетчера, доступ к нему можно получить только из потока, который его создал, который в данном случае является фоновым потоком, который читает свойство.

Таким образом, созданный FlowDocument не может быть доступен для вашего потока пользовательского интерфейса.

Вам понадобится другой подход для асинхронной загрузки документа.

Возможно, вы могли бы использовать синхронную (обычную) привязку и использовать XamlReader.LoadAsync для загрузки документа? Я сам не пробовал, но, думаю, с этим стоит поэкспериментировать.

...