2011-02-10 7 views
5

He creado un comportamiento personalizado (sin mezcla) para arrastrar UIElements y obtener una miniatura translúcida de lo que está arrastrando debajo del cursor (blends version mueve el objeto de destino que no es lo que Necesito)Silverlight Behavior onDetaching override no se llama

Anyhoo, el código es realmente muy simple y funciona bien, el problema que tengo es que onDetaching() no se está llamando, lo que significa que mis eventos para el UIElement no se están desenganchando.

Esto me preocupa un poco, ya que supongo que la única razón por la que no se separa el comportamiento es porque todavía está siendo referenciado por algo. No debería ser el UIElement, ya que tuvimos problemas de fuga en una etapa, pero ahora los hemos resuelto y esto se aclara a través de WinDbg.

Lo único interesante (?) Es el comportamiento asociado a una imagen en un control de elementos, pero esto no debería marcar la diferencia, ¿verdad?

Aquí está mi código actual:

public class DragBehavior : Behavior<UIElement> 
{ 
    private const double DRAG_DISTANCE = 20; 
    private const int DRAG_ICON_HEIGHT = 100; 

    Point m_firstPoint; 
    private bool m_isDragging = false; 
    private Popup m_dragPopup = null; 
    private Image m_draggedImage;   

    protected override void OnAttached() 
    { 
     this.AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); 
     this.AssociatedObject.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove); 
     this.AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); 

     base.OnAttached(); 
    } 

    void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     m_firstPoint = e.GetPosition(null); 
     m_isDragging = true; 
    } 

    void AssociatedObject_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (m_isDragging) 
     { 
      Point currentPosition = e.GetPosition(null); 

      if (m_dragPopup == null) 
      { 
       double deltaX = currentPosition.X - m_firstPoint.X; 
       double deltaY = currentPosition.Y - m_firstPoint.Y; 

       double movement = Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY)); 
       if (movement > DRAG_DISTANCE) 
       { 
        // Get a screen shot of the element this behaviour is attached to 
        WriteableBitmap elementScreenshot = new WriteableBitmap(AssociatedObject, null); 

        // Create an image out of it 
        m_draggedImage = new Image(); 
        m_draggedImage.Height = DRAG_ICON_HEIGHT; 
        m_draggedImage.Stretch = Stretch.Uniform; 
        m_draggedImage.Source = elementScreenshot; 
        m_draggedImage.Opacity = 0.4; 

        // Add the image to the popup 
        m_dragPopup = new Popup(); 
        m_dragPopup.Child = m_draggedImage; 

        m_dragPopup.IsOpen = true; 
        m_dragPopup.UpdateLayout(); 

        m_dragPopup.HorizontalOffset = currentPosition.X - m_draggedImage.ActualWidth/2; 
        m_dragPopup.VerticalOffset = currentPosition.Y - m_draggedImage.ActualHeight/2; 

        AssociatedObject.CaptureMouse(); 
       } 
      } 
      else 
      { 
       m_dragPopup.HorizontalOffset = currentPosition.X - m_draggedImage.ActualWidth/2; 
       m_dragPopup.VerticalOffset = currentPosition.Y - m_draggedImage.ActualHeight/2; 
      } 
     } 
    } 

    void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
    { 
     if (m_isDragging == true && m_dragPopup != null) 
     { 
      m_isDragging = false; 
      m_dragPopup.IsOpen = false; 
      m_dragPopup = null; 
     } 

     AssociatedObject.ReleaseMouseCapture(); 

     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     GC.Collect(); 
    } 

    protected override void OnDetaching() 
    { 
     this.AssociatedObject.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown); 
     this.AssociatedObject.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove); 
     this.AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp); 

     base.OnDetaching(); 
    } 
} 

Conozco dos puestos que he visto en esto ...

Ésta - forums.silverlight.net/forums/p/142038/ 317146.aspx no ayuda, ya que he tratado de forzar un GC inútil, y este - Automatically calling OnDetaching() for Silverlight Behaviors Realmente no me explico porque dicen que es el enlace del UIElement al comportamiento que lo causa, pero seguramente cuando la referencia de raíz UIElement se rompa, la referencia de raíz al comportamiento también se eliminará y, en consecuencia, ambos se pueden eligable para GC.

Esperaba que esto fuera simple, pero si no, comenzaré con WinDbg para ver qué está pasando realmente.

¡Cualquier ayuda es muy apreciada! :)

Gracias,

Andy.

+1

¿No puede ayudarlo? Supongo que intentaré postular en los foros de Silverlight. ¡Actualizaré este hilo si llego a algún lado! – Andy

Respuesta

0

No muestra de dónde se está llamando al Detach. Algo necesita llamar al object.Detach() (DragBehavior) para que se llame al método OnDetaching().

Si desea separarlo en el controlador de eventos AssociatedObject_MouseLeftButtonUp, puede llamar a detach al final del método, siempre y cuando no tenga que hacer nada más con él.

void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
{ 
    if (m_isDragging == true && m_dragPopup != null) 
    { 
     m_isDragging = false; 
     m_dragPopup.IsOpen = false; 
     m_dragPopup = null; 
    } 

    AssociatedObject.ReleaseMouseCapture(); 

    this.Detach() 
} 

Definitivamente no haría ninguna llamada a GC, lo que puede tener un gran impacto en el rendimiento.

+4

Creo que ese es el punto que está haciendo. Silverlight debería llamar a 'Detach' cuando la vista se elimina del árbol visual. –