2011-04-13 10 views
6

Estoy haciendo una representación personalizada en una subclase Decorator. Nuestra representación requiere la creación de geometrías complejas que solo se deben recrear cuando cambia el tamaño real. Como tal, he movido la creación de geometría a su propia función llamada UpdateGeometry que crea, luego congela la geometría para usar en OnRender. Esta nueva función solo necesita ser llamada en respuesta a un cambio en ActualWidth o ActualHeight.En WPF, ¿cómo puedo obtener el tamaño representado de un control antes de que realmente se presente?

Aún mejor, parece que debemos ser capaces de simplemente anular OnRenderSizeChanged, que de acuerdo con los estados de documentación ...

"Cuando se reemplaza en una clase derivada, participa en las operaciones de renderizado que son dirigida por el sistema de diseño . Este método se invoca después actualización de diseño, y antes de emitir, si RenderSize del elemento ha cambiado como resultado de la disposición UPDA te "

Sin embargo, sin tener en cuenta si estoy usando la anulación o escuchar las notificaciones de cambio de propiedad de ActualWidth y ActualHeight, mi registro muestra consistentemente OnRender como sucede en primer lugar! Um ... ¿Qué?

Para estar seguro de que no era algo que estuviera haciendo en mi código, creé una subclase de decorador de pruebas escueta y agregué el registro allí, tanto en la entrada como en la salida de las anulaciones. Aquí está toda la clase ...

using System; 
using System.Windows.Controls; 

public class TestControl : Decorator 
{ 

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext) 
    { 
     Console.WriteLine("OnRender Entered"); 

     base.OnRender(drawingContext); 

     Console.WriteLine("OnRender Exited"); 
    } 

    protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo) 
    { 
     Console.WriteLine("OnRenderSizeChanged Entered"); 

     base.OnRenderSizeChanged(sizeInfo); 

     Console.WriteLine("OnRenderSizeChanged Exited"); 
    } 

} 

Y como me temía ... aquí es la salida ...

OnRender Entered 
OnRender Exited 
OnRenderSizeChanged Entered 
OnRenderSizeChanged Exited 

Entonces, ¿qué me estoy perdiendo aquí?

Más importante aún, ¿cómo puedo obtener los ActualWidth y ActualHeight valores después de que el subsistema de diseño ha hecho su trabajo, pero antes de que el control se hace para que pueda crear la geometría antes de que sea necesario, en la anulación OnRender?

Mi última versión anula ArrangeOverride como el valor que se pasa allí es un tamaño que contiene lo que los ActualWidth y ActualHeight valores debe será después el sistema de diseño de núcleo tiene en cuenta HorizontalAlignment y VerticalAlignment con valores de 'Stretch', mínimos y máximos, etc., pero lo que realmente son depende del valor que devuelve esa anulación, por lo que es un poco más complejo que eso.

De cualquier manera, todavía me pregunto por qué la llamada OnRenderSizeChanged no ocurre cuando se supone que debe hacerlo. ¿Pensamientos?

Marcos

Respuesta

4

En general, usted debe ser capaz de obtener el tamaño correcto de ArrangeOverride. Esto no incluye cosas como Margen, pero eso probablemente no debería tenerse en cuenta. Puede usar el tamaño pasado como parámetro como su tamaño de "renderizado" o usar el valor de retorno de la llamada base.ArrangeOverride.

EDIT:

El método OnRender se llama desde el método Organizar, después de OnArrangeOverride se llama en última instancia. El OnRenderSizeChanged, por otro lado, se llama desde UpdateLayout, que se distribuye de manera efectiva para que se ejecute todo de una vez para una sección determinada del árbol visual. Esta es la razón por la cual se llama a OnRenderSizeChanged después de OnRender.

La documentación puede hacer referencia a la "representación" como en realidad representada en la pantalla, no cuando se llama a OnRender. WPF puede almacenar en caché las instrucciones de representación para un elemento determinado y ejecutarlas cuando sea necesario. Por lo tanto, el hecho de que se llame a OnRender antes que OnRenderSizeChanged, no significa que las instrucciones de representación reales estén comprometidas con la pantalla en ese momento.

puede modificar su OnRenderSizeChanged para forzar OnRender a ser llamado de nuevo usando:

protected override void OnRenderSizeChanged(System.Windows.SizeChangedInfo sizeInfo) 
{ 
    Console.WriteLine("OnRenderSizeChanged Entered"); 

    base.OnRenderSizeChanged(sizeInfo); 
    this.InvalidateVisual(); 

    Console.WriteLine("OnRenderSizeChanged Exited"); 
} 

También puede saltarse el código OnRender si RenderSize es "0,0".

+0

Sí ... eso es lo que acabo de editar en la parte inferior de mi descripción anterior como lo que estamos haciendo actualmente como un 'work-around', pero eso todavía no explica la anulación OnRenderSizeChanged que no funciona como la documentación dice. Además, la * única * cosa que creo que no toma en consideración es Margen, ya que eso está fuera de lo que se muestra de todos modos. ¿Conoces alguna otra cosa que no se tenga en cuenta? – MarqueIV

+0

@MarquelV - Actualicé mi respuesta en función de sus comentarios. – CodeNaked

+0

Parece que solo me apegaré al ArrangeOverride es lo que tengo que hacer. ¡Tienes la respuesta! :) – MarqueIV

Cuestiones relacionadas