2011-02-27 4 views
2

나는 내 창문 어딘가에 앉아있다. 이 Window의 루트에는 MainGrid라는 그리드가있다. 윈도우의 크기가 커지면 내 윈도우의 모든 내용을 확대하는데 사용하는 MainGrid의 LayoutTransform에 ScaleTransform이 적용되었습니다. 그러나 내 컨트롤 중 하나는 캔버스에 BitmapCache을 사용하여 드로잉 성능을 최적화합니다. BitmapCache는 컨트롤에 적용될 수있는 ScaleTransform을 고려하지 않으므로 확대하면 컨트롤이 흐리게 표시됩니다.컨트롤 또는 UIElement에 적용된 ScaleTransform을 찾으십니까?

BitmapCache에는 캐시 된 이미지의 크기를 늘리는 데 사용할 수있는 RenderAtScale 속성이 있습니다. 그러나, 내가 가진 문제는 스케일 값이 무엇인지 알아내는 우아한 방법을 모른다는 것입니다. 지금은 컨트롤에 속성이있어서 내 윈도우가 컨트롤에 해당 값을 전달할 수 있습니다. 그러나 스케일 값을 전달하는 외부 소스에 의존 할 필요가 없다면 좋겠다.

Control에 적용되는 모든 ScaleTransforms의 요약을 가져올 수있는 방법이 있습니까?

답변

1

언제든지 재귀 적으로 모든 컨트롤의 부모를 통과하여 ScaleTransform의 합계를 사용할 수 있습니다.

나는 다른 방법으로는 할 수 없다고 생각합니다.

+0

입니까? 그렇다면, 필자가 제안한 것과 똑같은 모든 컨트롤에 도우미 메서드를 추가 할 수 있습니다. 시각적 트리를 반복적으로 실행하여 적용해야하는 ScaleTransforms의 합계를 얻습니다. – JacobJ

+0

부모의 ScaleTransorms 변경 사항을 재귀 적으로 등록 할 수도 있습니다. 같은 도우미 클래스. –

2

Elad Katz에 따르면 ScaleTransform이 어떤 부모에게 적용되지 않는지 직접 확인할 수있는 방법이 없다고 생각합니다. 당신이 ScaleTransform가 MainGrid에 적용되는 것으로 알고있는 경우

그러나, 당신은 MainGrid의 ScaleTransformScaleX 또는 ScaleY-RenderAtScale을 바인딩 할 수 있습니다. 어쩌면 이것은 당신이 이미하고있는 일이다 그러나 나는 이름으로 아마

어쨌든 끝으로 바인딩에 ScaleTransform를 참조 할 수있는 가장 쉬운 방법입니다 그것을 던져 그것을

<Grid Name="MainGrid"> 
    <Grid.LayoutTransform> 
     <TransformGroup> 
      <ScaleTransform x:Name="MainGridScaleTransform" .../> 
     </TransformGroup>    
    </Grid.LayoutTransform> 

당시 유사합니다 바인딩 그렇지 않으면이

<BitmapCache RenderAtScale="{Binding ElementName=MainGridScaleTransform, 
            Path=ScaleX}"/> 

, 당신은 함께 경로에서 ScaleTransform를 얻을 수 TransformGroup

<BitmapCache RenderAtScale="{Binding ElementName=MainGrid, 
Path=(LayoutTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)}"/> 
012 Elad 카츠의 권고를 바탕으로

또는 TransformGroup

<BitmapCache RenderAtScale="{Binding ElementName=MainGrid, 
           Path=(LayoutTransform).(ScaleTransform.ScaleX)}"/> 
+0

나는 당신이 말하는 것을 얻습니다. 나를 위해 BitmapCache 내 창을 액세스 할 수 없습니다. 그것은 컨트롤 자체에 저장되어 있고 컨트롤은 실제로 별도의 컨트롤 라이브러리 바이너리에 정의되어 있습니다. 그러나 바인딩으로 무엇을 몰고 있는지 이해하고이를 컨트롤에 추가 한 "AppliedScale"종속성 속성에 사용할 수 있습니다. – JacobJ

2

없이 3,516,, 나는 교복을 ScaleTransform의 총을 시도하는 VisualTree를 스캔 할 몇 가지 코드를 만들었습니다. 어떤 알고리즘이이 알고리즘에 대한 최적화를 가지고 있거나 고려하지 않은 몇 가지 사항을 생각할 수 있다면 알려주십시오. 다시, 내 목표는 현재 적용된 ScaleTransform 주어진 주어진 적절한 RenderAtScale 얻는 것입니다. OnRenderSizeChanged은 모든 레이아웃 작업이 완료된 후에 발생하므로이 작업을 수행 할 수있는 곳으로 보입니다. 그러나 아마도 GetTotalTransformScale()을 트리거 할 수있는 더 좋은 곳이 있을까요?

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
{ 
    base.OnRenderSizeChanged(sizeInfo); 
    double totalTransformScale = GetTotalTransformScale(); 
    BitmapCache bitmapCache = (BitmapCache)MyCachedCanvas.CacheMode; 
    if (bitmapCache.RenderAtScale != totalTransformScale) 
     bitmapCache.RenderAtScale = totalTransformScale; 
} 

private double GetTotalTransformScale() 
{ 
    double totalTransform = 1.0d;  
    DependencyObject currentVisualTreeElement = this;    
    do 
    { 
     Visual visual = currentVisualTreeElement as Visual; 
     if (visual != null) 
     { 
      Transform transform = VisualTreeHelper.GetTransform(visual); 

      // This condition is a way of determining if it 
      // was a uniform scale transform. Is there some better way? 
      if ((transform != null) && 
       (transform.Value.M12 == 0) && 
       (transform.Value.M21 == 0) && 
       (transform.Value.OffsetX == 0) && 
       (transform.Value.OffsetY == 0) && 
       (transform.Value.M11 == transform.Value.M22)) 
      {       
       totalTransform *= transform.Value.M11; 
      } 
     } 
     currentVisualTreeElement = VisualTreeHelper.GetParent(currentVisualTreeElement); 
    } 
    while (currentVisualTreeElement != null); 

    return totalTransform; 
} 
+1

우리는 Scale tranforms 만 있고 X와 Y scale (M11, M22)이 같은 특별한 경우에만이 기능이 작동한다고 언급하고 싶습니다. 이것은 대부분의 경우의 경우이지만 특수한 경우를 제외하고 않습니다. – Robetto

0

나는이 오래된 질문 알아요,하지만 난 비슷한 문제를 자신했다 : 나는 최고 수준에서 ScaleTransform을 무시하는 컨트롤의 한 유형을 만들 필요가 있었다.

UIElementRenderTransform 속성을 가지며 기본적으로는 ScaleTransform입니다.

3

PresentationSourceRootVisual을 사용하여 요소의 총 변환을 계산할 수 있습니다. 일반적인 패턴은 부모 사이에 적용 규모를 발견하고 아이가 내 컨트롤의 VisualTree의 ScaleTransform의 모든 변경에 대한 변경 알림을받을 수있는 간결/우아한 방법이 있나요

Visual child = /* some visual */ this; 
Visual parent = PresentationSource.FromVisual(child).RootVisual; 

// calculate the transform needed to go from the parent to the child coordinate spaces 
var childTransform = parent.TransformToDescendant(child); 

// use the transform to scale a 1x1 rectangle 
// use Inverse as the transform is from Parent coordinates to child, we want 
// child to parent 
var unitRect = new Rectangle(0, 0, 1, 1); 
var transformedUnit = childTransform.Inverse.TransformBounds(unitRect); 

// transformedUnit.Width and transformedUnit.Height are now the scale factors (X and Y) 
Debug.Assert(transformedUnit.Width == 0.25 && transformedUnit.Height == 0.25); 
+0

그러나 이것은 도중의 모든 스케일 변환을 무시합니다. 예를 들면 : 스케일을 제어하는 ​​슬라이더가있는 창이 있습니다. 이 스케일 변환을 전체 "창"(RootVisual)에 적용하는 것은 유용하지 않습니다. 대신 "MainWindowControl"이이 위치를 차지하고 ScaleTransform을 가져옵니다. 따라서 요약하는 것이 중요합니다. (곱하기 매트릭스) – Robetto

+0

@ 로벳 토, 이해가 안됩니다. 'TransformToDescendant' 호출은 변환 유형에 관계없이 지정한 노드 사이의 시각적 트리에서 적용된 모든'.Transform'을 고려합니다. "이 루프는 우리가 조상을 만날 때까지 시각적 트리를 걸어 갈 것입니다. 그렇게하면 자손 -> 조상 변환이 누적됩니다." (http://referencesource.microsoft.com/#PresentationCore/src/Core/CSharp/System/Windows/Media/Visual.cs#46e3a62ee137ecab#references) – Mitch

+0

위의 코드에서 재귀 또는 루프가 표시되지 않습니다. 그러나 트랙이 올바른 것입니다. 단위 제곱에 역수를 곱하여 올라가거나 변환을 곱하여 루트에서 이동합니다 (그러나 모두). 그것이 내 요점이었다. – Robetto

관련 문제