Nello script #43 abbiamo visto come implementare un semplice sistema di Drag-and-drop mediante l'uso delle AttachedProperties.
Nello script di oggi vedremo come risolvere due dei limiti più grossi del precedente sistema.
Il primo assolutamente non trascurabile è che tale sistema funziona solo se utilizziamo dei Canvas per realizzare il layout della nostra applicazione, affidandoci alle proprietà Canvas.Left e Canvas.Top per la disposizione degli oggetti; infine è possibile trascinare l'elemento e rilasciarlo in qualsiasi parte dell'interfaccia, caratteristica che magari non è sempre desiderabile.
Per ovviare al primo inconveniente dobbiamo ripensare la filosofia del DragManager e applicare una TranslateTransform, invece che modificare la posizione rispetto al Canvas.
Per prima cosa aggiungiamo un nuovo metodo, GetTranslateTransform, che accetta come parametro un oggetto del tipo UIElement e restituisce se esistente l'attuale TranslateTransform, altrimenti ne crea una nuova e l'applica all'elemento.
private static TranslateTransform GetTranslateTransform(UIElement uielement) { if (uielement == null) throw new ArgumentNullException("uielement"); TranslateTransform _translateTransform = null; if (uielement.RenderTransform is TranslateTransform) { _translateTransform = (TranslateTransform)uielement.RenderTransform; } else if (uielement.RenderTransform is TransformGroup) { TransformGroup _transformGroup = (TransformGroup)uielement.RenderTransform; foreach (Transform item in _transformGroup.Children) { if (item is TranslateTransform) { _translateTransform = (TranslateTransform)item; } } } else { _translateTransform = new TranslateTransform(); uielement.RenderTransform = _translateTransform; } return _translateTransform; }
È con quest'oggetto TranslateTransform che modificheremo nell'eventhandler element_MouseMove al fine di muovere l'oggetto per lo schermo.
static void element_MouseMove(object sender, MouseEventArgs e) { UIElement _element = (UIElement)sender; if (_isMouseCapured) { TranslateTransform _translateTranform = GetTranslateTransform(_element); //modifica la trasformazione per muovere l'oggetto _translateTranform.Y += e.GetPosition(null).Y - _mouseLastPosition.Y; _translateTranform.X += e.GetPosition(null).X - _mouseLastPosition.X; //aggiorna le variabili _mouseLastPosition.X = e.GetPosition(null).X; _mouseLastPosition.Y = e.GetPosition(null).Y; //trovo le coordinare correnti dell'oggetto GeneralTransform _objGeneralTransform = _element.TransformToVisual(Application.Current.RootVisual as UIElement); Point _point = _objGeneralTransform.Transform(new Point(0, 0)); //controllo che tra l'oggetti con cui collido si trovi un "dockItem" UIElement u = (from ui in VisualTreeHelper.FindElementsInHostCoordinates( new Rect(_point.X, _point.Y, ((FrameworkElement)_element).ActualWidth, ((FrameworkElement)_element).ActualHeight), (UIElement)VisualTreeHelper.GetParent(_element)) where (bool)ui.GetValue(IsDragDockProperty) == true select ui).FirstOrDefault(); if (u != null) { if (_currentDockItem != u) { _currentDockItem = u; } } else { _currentDockItem = null; } } }
La parte più importante del codice è quella che verifica le collisioni dell'oggetto trascinato con gli altri elementi dell'interfaccia, il risultato viene filtrato in base al valore dell'AttachedProperty IsDragDockProperty e poi salvato nel campo _currentDockItem.
IsDragDockProperty è un'AttachedProperties definita dal DragManager che indica su quali aree è possibile rilasciare l'elemento che stiamo trascinando.
Il valore del campo _currentDockItem è valutato al rilascio del mouse e nel caso questo sia nullo, l'oggetto trascinato è riportato nella sua posizione originale.
Lo XAML seguente mostra la creazione di due regioni (Border) nelle quali è possibile rilasciare l'oggetto che stiamo trascinando.
Rilasciandolo invece fuori da queste aree farà si che sia ripristinata la sua precedente posizione.
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:DragDropSilverlightApplication" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="DragDropSilverlightApplication.Page" Width="400" Height="300" mc:Ignorable="d"> <Canvas x:Name="LayoutRoot" Background="White"> <Border my:DragManager.IsDragDock="true" Height="100" Width="100" Canvas.Left="29" Canvas.Top="135" BorderBrush="#FF000000" BorderThickness="1,1,1,1" Background="#00FFFFFF" /> <Border my:DragManager.IsDragDock="true" Height="100" Width="100" BorderBrush="#FF000000" BorderThickness="1,1,1,1" HorizontalAlignment="Right" Canvas.Top="29" Canvas.Left="29" /> <Rectangle my:DragManager.IsDraggable="true" Fill="Red" Height="50" Width="50" Canvas.Top="135" Canvas.Left="201" RenderTransformOrigin="0.5,0.5" /> <Rectangle my:DragManager.IsDraggable="true" Fill="Red" Height="50" Width="50" RenderTransformOrigin="0.5,0.5" Canvas.Top="29" Canvas.Left="201" /> </Canvas> </UserControl>
Allo script è allegata la soluzione completa con il codice interamente commentato.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.