2013-08-12 3 views
16

컨트롤을 기본 요소로 분할하고 레이아웃 관리를 수행하고 바인딩을 적용하는 등 일반적인 WPF 렌더링을 납치하고 싶습니다.사용자 정의 DrawingContext로 렌더링

필자가 이해하는 한, WPF의 전체 렌더링은 레이아웃 관리자가 계산 한 위치에서 종속성 속성 시스템에 의해 정의 된 값으로 프리미티브 (텍스트, 이미지, 선, 곡선)를 렌더링하는 것으로 이어집니다. 내 자신의 프리미티브 렌더링 논리를 제공 할 수 있다면 예를 들어 렌더링 할 수있을 것입니다. 사용자 정의 문서 유형으로, 다음되는 네트워크 등

내 계획을 통해 실시간 렌더링을위한 프리미티브를 전송 :

  1. 사용자 정의 DrawingContext를 구현합니다. DrawingContextDrawEllipse, DrawText, DrawImage 등의 메소드를 정의하는 추상 클래스입니다.이 기능을 구현하려면 자체 구현을 제공해야합니다.
  2. WPF UserControl을 만들고이를 주어진 DrawingContext으로 렌더링하도록합니다.

그러나 나는 다음과 같은 문제가 발생했습니다 :

  1. DrawingContext 내가 쉽게 무시할 수 없습니다 추상적 인 내부 방법 void PushGuidelineY1(double coordinate)void PushGuidelineY2(double leadingCoordinate, double offsetToDrivenCoordinate)가 포함되어 있습니다. (아마도 이것을 극복하기위한 트릭이 있습니까?)
  2. 전체를에 렌더링하는 방법은 보이지 않습니다. DrawingContext? 왜?

나는

void RenderRecursively(UIElement e, DrawingContext ctx) 
{ 
    e.OnRender(ctx); 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(e); i++) 
     RenderRecursively((UIElement)VisualTreeHelper.GetChild(e, i), ctx); 
} 

과 같은 작업을 수행 할 수 있습니다 -하지만 나는 UIElement을 렌더링 할 수있는 직접적인 방법이 있는지 궁금합니다. (물론이 문제는 사소한 것이지만, 인프라가 없기 때문에 이것이 적절한 방법인지 궁금합니다.)

따라서 DrawingContext은 상속을위한 것이 아닙니다. 커스텀 DrawingContext을 올바른 방향으로 나아갈 생각인가 아니면 전략을 재고해야합니까? WPF에서 지원되는 사용자 지정 컨텍스트에 그리는가, 아니면 다른 차단 지점을 찾아야합니까?

+6

DrawingContext의 설명에서 :'DrawingContext를 직접 인스턴스화하지 마십시오. 그러나 DrawingGroup.Open 및 DrawingVisual.RenderOpen과 같은 특정 메서드에서 드로잉 컨텍스트를 얻을 수 있습니다. "나에게 이것은 실제로 사용자 정의 DrawingContext를 어딘가에 제공 할 수있는 방법이 없다는 것을 의미합니다. – Clemens

+0

@Clemens : 예, 저는이 말을 보았습니다. 그러나 "일반적으로 직접 작성해서는 안되며, 내부적으로 처리해야하며, DrawingVisual로 그리기 만하면 DrawingVisual에서 올바르게 초기화됩니다."라고 이해했습니다. 어쨌든 재미있는 것은 그림 그리기에 유효한 차단 점이있는 경우입니다. – Vlad

+2

DrawingVisual에 드로잉 할 수있는 유일한 방법은 DrawingVisual.RenderOpen에서 제공하는 DrawingContext에 드로잉하는 것입니다. 사용자 지정 DrawingContext를 Visual과 연결할 수있는 방법은 없습니다. 그 아이디어는 무의미하다. – Clemens

답변

3

반대 방향에서이 문제에 접근해야 할 수도 있습니다. 자신의 DrawingContext을 제공하는 대신 WPF에 Drawing을 제공하도록 요청할 수 있습니다. 그래서 당신이 목표로하고있는 '밀어 넣기 (push)'접근법보다 '끌어 당기는'접근 방식이 더 많습니다. 그러나 동일한 장소에 도달 할 수 있어야합니다 : Drawing이 있으면 그 부분의 외관을 완전히 표현한 것입니다 시각적 트리의 데이터 구조는 사용자가 DrawingContext을 호출 할 때 발견 한 모든 것을 발견하고 발견 할 수있는 데이터 구조입니다.

이것이 Sebastian에서 내 보낸 XPS 문서 내보내기와 동일한 기본 접근 방식이라고 생각합니다. 하지만 직접 직접 사용하는 것은 XPS API를 통해 직접 사용하는 것보다 더 직접적인 방법입니다.

마음에 드는 부분은 매우 간단합니다 : VisualTreeHelper.GetDrawing. 이 경우 DrawingGroup이 반환됩니다. (Drawing은 추상 기본 클래스입니다.)이 문서 페이지는 돌아 오는 나무를 걷는 방법을 보여줍니다. 불행하게도이 작업은 모든 작업을 수행하지는 못합니다. 노드를 호출 한 노드에 대한 비주얼을 제공하고 노드에 하위 노드가있는 경우 포함되지 않습니다.

그래서 불행히도 이미 계획했던 것처럼 시각적 트리를 재귀 적으로 작성해야합니다. 올바른 결과를 얻으려면 비주얼 마스크에 연결된 불투명 마스크, 비 마스크 기반 불투명도, 클립 영역, 효과 및 변형을 처리해야합니다. 당신은 제안 된 접근법이 올바르게 작동하도록하기 위해 모든 것을해야 했으므로 여기서 실제로 변하는 것은 아무것도 없습니다. (Sebastian이 제안한 것처럼 XPS API를 사용하면 XPS 문서에서 정보를 원하는 형식으로 추출하는 것이 문제가 될 수 있지만 결국 정보가 손실 될 수 있습니다. 보존 할 수 있습니다.)

+0

내 테스트에서이 작동하지 않았다. 'GetDrawing'은'OnRender '중에 그려지는 비주얼이 헬퍼 메소드에 의해 열거되지 않기 때문에 대부분의'Control'에 대해'null'을 만들기 때문에 제가 제안한 접근 방법을 사용해야한다고 생각합니다.'Border'를 열거하고 당신은'null'을 얻을 것이다. – Sebastian

+0

null이 아닌 'BorderBrush'와 0이 아닌'BorderThickness'을 가진'Border'에서'GetDrawing'을 호출하면, 동일한'GeometryDrawing'을 포함하는 널이 아닌'DrawingGroup'을 돌려줍니다 size '를 Border,'RectangleGeometry'를'Geometry','Pen'을'Thickness'와'BorderBrush' 설정과 일치시킵니다. 혹시 a) 실제로 페인트 칠을하지 않은 국경이나 b) 시각화를 아직 실현하지 못했던 국경에서 시험을 했습니까? –

+0

바로 여기 있을지도 모릅니다. 이전에는 경계가 시각화 된 적이 없었습니다. 그게 문제 일지는 모르지만 나는 아직 확인하지 못했다. 거짓 비난 죄송합니다! – Sebastian

2

winRT 용 FlowDocumentViewer를 만드는 것과 유사한 작업을 시도했습니다. 그러나 WinRT가 WPF에 비해 성숙도가 떨어짐에 따라 렌더링 스레드를 통해 네이티브 레이어에 너무 많은 권한을 위임하여 아무데도 갈 수 없었습니다. 그러나 이것이 내가 배운 것입니다. 나는 그것을 잘 설명하기를 바랍니다.

WPF는 하드웨어 가속 그래픽 렌더링을 사용합니다. 따라서 간단히 말하면 WPF LayoutEngine은 논리적 비주얼 트리를 생성 한 다음 렌더링 명령으로 변환 한 다음 실행하거나 렌더링 할 Graphics 하드웨어로 보냅니다.

DrawingContext는 단순한 클래스가 아니며 렌더링을 위해 기본 그래픽 시스템과 상호 작용하고 크기 조정, 캐싱 등을 관리합니다. WPF 런타임에는 모든 비주얼을 렌더링하는 기본 구현이 있습니다. IMO, 추상 클래스로 만들어져 마이크로 소프트가 Silverlight 등에 대해 다른 구현을 제공 할 수있게하는 이유입니다. 그러나 그것은 우리에 의해 오버라이드 (override) 될 것입니다.

WPF 렌더링을 바꿔야하는 경우 가장 좋은 방법은 UserControl을 만들고 배열 및 측정 호출을 재정의 한 다음 DrawingVisual.RenderOpen()을 사용하여 각 요소를 DrawingVisual로 렌더링하고 코드에서 정렬하는 것입니다. 데이터 바인딩 알림을 관리하는 것은 스스로해야 할 또 다른 일입니다.

매우 흥미로운 프로젝트처럼 보입니다. 행운을 빕니다!

+0

사실, 히트 테스트와 같은 간단한 작업에 사용되는 많은 내부 DrawingContext가 있습니다. 내 궁극적 인 목표는 WPF를 일부 문서 형식으로 렌더링하여 사용자 지정 UserControl이 도움이되지 않도록하는 것입니다. 어쨌든 귀하의 조언을 주셔서 감사합니다! – Vlad

4

(다른 사람들이 언급했듯이) 자신의 DrawingContext 구현을 제공 할 수 없기 때문에 귀하의 접근 방식이 효과가 없을 것이라고 생각합니다.

대신 다음을 제안합니다. WPF 렌더링을 "평평하게"하려면 WPF에서 XPS 문서로 비주얼을 내보내도록하십시오. 이 과정에서 모든 렌더링은 기본적으로 단순 렌더링 프리미티브로 열거되며 남아있는 것은 모두 Canvas, 기본 도형, 글리프 및 기타 드로잉 프리미티브입니다.

그런 다음 문서의 페이지에서 시각적으로 반복합니다. 내가 아는 한 시각은 프리미티브만으로 구성되므로 OnRender에 전화 할 필요가 없습니다. 대신 외부 인스턴스에서 (instanceof -ascascades와 속성 읽기/해석을 사용하여) 시각적 인 인트로 스턴스를 수행 할 수 있습니다. WPF처럼 속성을 해석해야하기 때문에 여전히 많은 작업을 수행하고 있지만 볼 수있는 한 적어도 많은 주요 사용 사례에서 작동해야합니다.

+0

XPS 문서로 접근하는 것이 좋은 방법 인 것 같습니다. XPS 문서 내용을 빠르게 확인하면 원본 글꼴이 그대로 유지되지 않고 문서에 포함된다는 것을 알 수 있습니다. 단, 포함 된 글꼴 자체를 사용할 수 있으므로 문제가되지는 않습니다. 이 접근법의 가능한 문제점은 WPF를 사용하면 복잡성을 제어 할 수 있지만 XPS의 경우 간단한 WPF 소스의 경우에도 모든 XPS 기능을 구문 분석해야 할 수도 있습니다. – Vlad

+0

답변 해 주셔서 감사합니다. 비록 당신이 제안한 방식대로 진행하기로 결정하지는 않았지만, 그것은 분명히 아주 좋은 아이디어이며 훨씬 더 많은 상향 회를받을 가치가 있습니다. – Vlad

1

를 대신 작성하려고의 자신의 DrawingContext 어쩌면 당신은 OnRender 방법에있는 당신의 활동을 수행 FrameworkElement 또는 UIElement 또는 Visual에서 파생되는 클래스를 만들 수 있습니다. 여전히 Draw[Something]의 구현을 사용해야하지만 인수 및 작업 순서를 제어하게됩니다.보조 소스에서 프리미티브와 명령어를 파싱 할 수 있으며 런타임에 UIElement/FrameworkElement가 명령어를 작성할 수 있습니다.

+0

이것은 작동하지만 사용자 지정 Visual에서만 가능합니다. 내 문제는 무엇을 잡는 것입니다. TextBlock의 OnRender가하고 있습니다. – Vlad

+0

이것은 흥미로운 문제입니다. 대답을 찾으면 경험 공유를 고려하십시오. :-) –

관련 문제