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.