2011-09-16 9 views
1

대부분의 속성이 매우 가벼운 개체 (최대 200 자의 텍스트)가 있어야합니다. 하나의 속성은 크기가 클 수 있고 비동기로 가져올 수있는 FlowDocument입니다. Async = True로 설정할 때 "호출 스레드는 다른 스레드가이 개체를 소유하고 있기 때문에이 개체에 액세스 할 수 없습니다."라는 메시지와 함께 True로 설정하면 실패합니다.WPF 바인딩 IsAsync 실패

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

생산 가져 오기는 더 복잡하지만, 심지어 간단한 하드 코딩 FlowDocument와 IsAsyc 사실에 같은 고장이다.

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가 3MB가 될 수 있고 다른 모든 속성 10K를 결합하면 큰 성능이 나오고 가장 많이 사용되는 버튼이 다음 객체가됩니다. FlowDocument는 SQL의 varchar (max)에서 왔으며 줄 바꿈 및 강조 표시된 단어로 서식이 지정됩니다. 그것은 단지 비싸지 않습니다 - 다른 속성들에 비하면 비싸기도합니다.

FlowDocumentReader는 대용량 문서 에서처럼 첫 번째 페이지를 빠르게 가져온 다음 약 100/초로 페이지를로드하므로 일부 비동기식 지원이 나타납니다. 하지만 다른 모든 속성을 검색 한 후에도 페이지 1을 얻는 것이 좋습니다.

문제는 martin이 "FlowDocument가 디스패처 개체이기 때문에이를 만든 스레드에서만 액세스 할 수 있습니다."라는 문제가있었습니다.

해결 방법은 XAML 문자열로 serialize하는 것입니다. 내가 속성이 때 FlowDocument 생성 (로드 된) 된 것을 추측하고있어 코드를 보지 않고 컨버터

<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을 수행하면 비동기가 아닌 과거를지나 비동기 get을 호출하지만 XMAL에서는 실패합니다. – Paparazzi

+0

왜 downvote? 명확하지 않거나, 연구가 부족하거나, 유용하지 않은 것은 무엇입니까? – Paparazzi

답변

2

와 문자열

public string XAMLdocFlowDocument 
    { 
     get 
     { 
      Thread.Sleep(6000); 
      return XamlWriter.Save(FlowDocumentSlow); 
     } 
    } 

바인딩 독서. 이것은 속성 바인딩이 async이기 때문에 백그라운드 스레드에서 수행됩니다.

FlowDocument는 디스패처 개체이므로이 개체를 만든 스레드에서만 액세스 할 수 있습니다.이 경우이 속성을 읽는 백그라운드 스레드입니다.

이렇게 생성 된 FlowDocument는 UI 스레드에서 액세스 할 수 없습니다.

문서를 비동기 적으로로드하려면 다른 방법이 필요합니다.

아마도 동기식 (일반) 바인딩을 사용하고 XamlReader.LoadAsync을 사용하여 문서를로드 할 수 있습니까? 나는 그것을 직접 시도하지 않았지만 실험할만한 가치가 있다고 생각한다.

+0

질문에 get을 추가했습니다. 흥미로운 점은 get을 호출하고 get은 오류없이 flowdocument를 반환한다는 것입니다. UI가 바인딩하려고하면 실패합니다. get에 대한 호출이 적절한 UI 스레드에 있어야하는 것처럼 보입니다. 문서에 따르면 IsAsync = True를 추가하면 일반 호출이 비동기 호출로 바뀝니다. 나는 당신을 추천 할 것이다. 그러나 솔직히 말해서 나는 그것을 완전히 이해하지 못한다. – Paparazzi

+0

get 호출은 (다른 스레드에서) 비동기 적으로 완료됩니다. 문제는 get 메서드에서 새 FlowDocument 인스턴스를 만드는 것입니다. 인스턴스가 올바르게 리턴되었지만 다른 스레드 (get 호출을 만든 스레드)가 작성했기 때문에 UI 스레드에서 사용할 수 없습니다. 이것이 UI가 반환 된 FlowDocument 인스턴스를 "사용"하려고 시도 할 때까지는 오류가 발생하지 않는 이유입니다. –

+0

UI 스레드에서 FlowDocument 인스턴스를 만들어야합니다. 따라서 질문은 비동기 적으로로드해야하는 방법입니다. –