2015-01-12 10 views
4

우리는 다소 큰 WPF 비즈니스 응용 프로그램이 있으며 기존 WPF FixedPage/FixedDocument 보고서의 다시 작업하고 있습니다.UIElement.UpdateLayout을 사용해야하는 이유는 무엇입니까?

다소 바쁜 생태계입니다. 우리는 당신이 입을 수있는 많은 다른 컨트롤을 가진 폼 생성기를 내장하고 있습니다 (미니 빌트인 비주얼 스튜디오처럼 생각하십시오). 모두 잘 작동합니다. 화면에서 양식을 채운 다음 동일한 사본을 표준 8.5x11 용지에 인쇄 할 수 있습니다 (XPS로).

코드에서이 보고서를 수직 청크로 구분합니다. 각 덩어리가 인쇄 된 종이 위에 1 인치 또는 2 개의 키가 될 것이라고 가정 해보십시오. 이것이 우리가 페이지 매김을 처리하는 방법입니다. 다음 청크가 페이지에 비해 너무 크면 NewPage()를 반복합니다. 내가 언급했듯이, 이것은 잘 작동했다.

WPF는 엄청난 학습 곡선을 가지고 있으며 코드의 크기를 줄이기 위해 이전 코드와 리팩터링을 거쳐 DataTemplates, 강력한 형식의 ViewModels 및 일반 ContentControls를 사용해 행복하게 작업했습니다. 화면상의 양식 생성기는 여전히 작동하지만 FixedDocument 보고서가 이상하게 보입니다.

이러한 세로 조각으로 돌아가서 우리는 사용자의 양식을 개별 그리드 컨트롤로 종이에 인쇄합니다. 멋진 일은 없어. 각 그리드 (위에서 언급했듯이)는 체크 박스, 라디오 버튼, 텍스트 블록 등 임의의 혼합을 포함하는 1 ~ 2 개의 고배율을 가질 수 있습니다. 때때로, 지금 즉, 100 × 67

System.Windows.Controls.Grid g = ..... 

g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
g.Arrange(new Rect(g.DesiredSize)); 

를 적절한 크기를 다시 얻을 : 그리드는 이러한 재고 (표준) MS WPF 컨트롤을 포함하면

, 나는 하루 종일이 작업을 수행 할 수 그리드는 하나 개의 제어 할 수 있습니다 - 헤더를 사용하면 (예 : "이 달의 일정) 유일한 자식 컨트롤은 ContentControl을이다

ContentControl에 단순히 뷰 모델에 바인딩되는 그리드에 추가 할 경우 :

..

리소스 딕셔너리에이 바인딩을 선택하는 두 개의 DataTemplates가 있습니다. 여기에 그 내용을 보여 드리겠습니다.

<UserControl.Resources> 

    <w:MarginConverter x:Key="boilerMargin" /> 

    <DataTemplate DataType="{x:Type render:BoilerViewModel}"> 
     <render:RtfViewer 
      Width="{Binding Path=Width}" 
      TextRTF="{Binding Path=Rtf}"/> 
    </DataTemplate> 

    <DataTemplate DataType="{x:Type render:Qst2NodeViewModel}"> 
     <ContentControl Content="{Binding Path=BoilerVm}"> 
      <ContentControl.Margin> 
       <MultiBinding Converter="{StaticResource boilerMargin}"> 
        <Binding Path="NodeCaptionVm.Height" /> 
        <Binding Path="NodeLeft" /> 
       </MultiBinding> 
      </ContentControl.Margin> 
     </ContentControl> 
    </DataTemplate> 
</UserControl.Resources> 

ContentControl은 맨 아래의 데이터 형식을 선택합니다. 그런 다음 템플릿은 위의 작은 템플릿을 사용합니다.

공상 변환기는 단지 여백을 설정합니다. 읽기가 어려울 수 있지만이 모든 내용은 상위 usercontrol 내의 화면에 올바르게 표시됩니다. 그것은 모든 적절한 크기와 칭의와 모든 것입니다.

인쇄 된 보고서 측면 (XPS)에서 코드에서 이러한 컨트롤을 만들고 현재 FixedPage에 맞는지 확인해야합니다. 이 단계를 수행 할 때 : (이 ContentControl을 포함하는 격자에서)

g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
g.Arrange(new Rect(g.DesiredSize)); 

다시 0,0 크기가됩니다. 예를 들어 730x27과 같아야합니다. 다시, 화면에서, UserControl에서 호스팅,이 모든 작동합니다. 코드를 인스턴스화하고 순수하게 코드로 측정하려고하면 오류가 발생합니다. 나는 컨트롤이 그리드에 추가되고 행과 열 집합이 Children 컬렉션 등에 추가되었음을 확인했다.나는에 UpdateLayout 비싼 것을 읽어 봤는데 피해야 할

g.UpdateLayout(); //this fixes it 
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
g.Arrange(new Rect(g.DesiredSize)); 

, 나는 차라리 : 내가 에 UpdateLayout 호출로 두 문 앞에 추가하면

,이 같은, 그것은 작동 FixedDocument 보고서의 내 FixedPage에 추가하기 전에 각 그리드 섹션에서 호출하지 마십시오. 수십 또는 수백 번의 반복이있을 수 있습니다. 그리드에 일반 WPF 컨트롤이 있고 ContentControls가없고 멋진 데이터 형식을 찾고 조회하는 경우에도 UpdateLayout 호출 없이도 제대로 작동합니다.

어떤 조언이 필요합니까? 고맙습니다!

Xaml 엔진을 사용하기 시작한 이유를 이해해야 만하는 이유를 알 수 없습니다. 내가 고급 기능을 사용하여 처벌받는 것처럼 느껴집니다.

답변

4

설명하기가 복잡하지만 일반 단어를 사용해 보도록하겠습니다 ... wpf에서는 모든 것이 발송자와 함께 작동합니다. 또한 우선 순위별로 정렬 된 작업을 가진 배급자를 이미 알고있는 것처럼 보입니다.

먼저 컨트롤이 initalized되고 예를 들어

후 트리거되고 바인딩, 다음 값은 측정되는 모든 말 ... 등 등에 업데이트됩니다

어떻게 든 관리되는 모든 ContentControl을 설정하여 무엇 ContentControl을 물건 안에, 당신은 당신이 나중에

깨끗한 레이아웃 디스패처와 나사 고정 작업 할 수 있도록하기 위해

일부 컨트롤 또는 값 때문에 WPF에서 매우 일반적 레이아웃의 보류중인 작업을 완료하기 위해 기본적으로 힘 디스패처입니다에 UpdateLayout 호출하는 것을 망쳐 나중에 추가 될 수 있습니다 재 측정하는 일에.

귀하의 경우에는 한 번의 호출로 발송자가 숨을 쉬지 않고 한꺼번에 작성하는 것처럼 보입니다. 따라서 디스패처 큐를 정규화하려면 UpdateLayout 메서드가 필요합니다.

이 정보가 도움이되기를 바랍니다. Dispatcher.BeginInvoke를 사용하여 문제를 해결할 수도 있습니다.

+0

여기 뭔가있는 것 같아요. 측정 코드를 무시하고 그리드를 내 보고서 (FixedDocument의 현재 FixedPage)에 추가하면 매우 흥미로운 일이 발생합니다. 먼저 그리드가 Measured, Arranged입니다. 나는 이것을 밟았다. arrangeBounds가 0,0으로 오르는 것과 같은 문제가 있습니다. 그런 다음 몇 가지 이유로 다시 돌아와 측정을 반복합니다. 두 번째로, 그리드의 실제/실제 크기가 나타납니다. 나는 왜 그것이 반복되고 있는지 알았 으면 좋겠다. 그건 내가 뭘 놓치고 있는지 더 잘 이해할 수있다. –

+0

나에게 말하기가 어렵다. 코드가 잘 모르겠지만, 어떻게 움직이는 지 알 수있다. :) –

+0

두 번째 단계에서 호출 스택의 "외부 코드"를 보았습니다. 두 번째 단계는 실제로 컨트롤의 정확한 크기를 가져 오는 것입니다. WPF 엔진이 UpdateLayout을 호출하여이를 수행하고 있음을 알았습니다. 첫 번째 과거에, 그렇지 않은 경우. 매우 흥미로운.글쎄, 적어도 내 측정을하는 방법을 알고, 나는 아직도 거기에 템플릿이나 ContentControls되지 않습니다 거기에 정상적인 컨트롤이 처음으로 작동하는지 이해하고 싶습니다. 아마 당신이 말하는 이유 때문일 겁니다. 더 많은 것을 찾으면 업데이트 할 것입니다. 다시 한 번 감사드립니다 –

0

UpdateLayout 내 경우에는 작동하지 않습니다. 디스패처가 레이아웃 작업을 처리 할 때까지 기다려야했습니다.

toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
Application.Current.Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle); 
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize)); 

이 접근법에 대해서는 another article이 발견되었습니다.