2011-09-16 68 views
1

擁有大多數屬性的對象非常輕量級 - 文本最多200個字符。一個屬性是FlowDocument,它可以很大並且想要檢索它Async。當我使用以下消息設置Async = True時失敗:「調用線程無法訪問此對象,因爲不同的線程擁有它。」WPF綁定IsAsync失敗

<FlowDocumentReader Name="FlowDocumentPageViewer1" HorizontalAlignment="Stretch" 
     Document="{Binding Source={x:Static Application.Current}, Path=MyGabeLib.Search.SelectedDoc.DocFlowDocument, Mode=OneWay, IsAsync=True}" /> 

生產獲取更復雜但IsAsyc上的相同失敗即使使用簡單的硬編碼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 MB,並且所有其他屬性10K組合在一起,所以這是大性能打擊,最常用的按鈕是下一個對象。 FlowDocument來自SQL中的varchar(max),並用突出顯示的換行符和單詞格式化。它不僅很大 - 與其他屬性相比,它也很昂貴。

FlowDocumentReader本身似乎有一些異步支持,因爲在大文檔上我快速獲得第一頁,然後以大約100 /秒的速度加載頁面。但我仍然希望在檢索完所有其他屬性後獲取第1頁。

問題在於martin聲明「由於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; 
     } 
+0

在這種情況下什麼是FallbackValue?這是否需要在綁定中指定(因爲可能會在異步操作正在處理時應用此操作?) – Ricibob

+0

仍然會因FallbackValue失敗。如果我做了PriorityBinding,它會通過非異步,甚至調用異步獲取,但在XMAL中失敗。 – Paparazzi

+0

爲什麼downvote?什麼不明確,顯示缺乏研究,或沒有用處? – Paparazzi

回答

2

沒有看到我猜的FlowDocument的創建(和加載)當屬性是代碼讀。這是在後臺線程中完成的,因爲屬性綁定是異步的。

由於FlowDocument是調度程序對象,因此只能從創建它的線程訪問它,在這種情況下,它是讀取屬性的後臺線程。

因此,創建的FlowDocument不能被您的UI線程訪問。

您需要另一種異步加載文檔的方法。

也許你可以使用同步(正常)綁定並使用XamlReader.LoadAsync加載文檔?我沒有嘗試過,但我猜測這是值得嘗試的。

+0

我添加了問題。有趣的是,它調用get和get返回flowdocument而沒有錯誤。當UI嘗試綁定時失敗。看起來像獲得的呼叫應該在適當的UI線程上。根據文檔,你需要做的就是添加IsAsync = True,並且它將定期進入異步調用。我會看你的建議,但說實話,我不完全明白它。 – Paparazzi

+0

get調用異步完成(在另一個線程上)。問題是你正在get方法中創建一個新的FlowDocument實例。即使該實例被正確地返回,它也不能被UI線程使用,因爲它是由另一個線程(進行get調用的線程)創建的。這就是爲什麼直到UI嘗試「使用」返回的FlowDocument實例纔會發生錯誤。 –

+0

您需要在UI線程上創建FlowDocument實例。那麼問題就是你應該如何異步加載它。 –