I have a project that requires the ability to drag a user control (hosted within a grid) around the screen. This works just fine with the below code:
void MyUserControl_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var ct = (CompositeTransform) RenderTransform ?? new CompositeTransform {CenterX = 0.5, CenterY = 0.5};
ct.TranslateX += e.Delta.Translation.X;
ct.TranslateY += e.Delta.Translation.Y;
}
The issue is that the user control can be dragged all the way out of the screen area. To prevent this, I tried the example shown here: http://msdn.microsoft.com/en-us/library/system.windows.uielement.manipulationdelta.aspx
Unfortunately, it uses containingRect.Contains(shapeBounds) whereas in windows 8, we are expected to replace shapeBounds(this is a rect) with a Point. I am not sure on how to work with this.
So the question is how can we ensure that a user control or any UIElement cannot be dragged out of the Window.Current.Bounds area in windows 8 store app?
Thanks.
EDIT: More details on the xaml structure:
The mainpage contains a Grid with horizontal and vertical alignment set to stretch. Usercontrols are added to this grid as required. Each usercontrol has a parent grid that contains 3 different views (fullscreen, window and small). The views are shown based on the user's choice. The drag behavior must be applied only when the window grid is shown. So we have this
<Grid> <!-- this is the parent grid on mainpage with horizontal and vertical alignment to stretch-->
<Grid> <!-- this is the usercontrol's main grid (added to above grid via code). This grid must be draggable if the below grid is window -->
<Grid /> <!-- this is one of the child grids that is shown based on user's choice (fullscreen, window or small view).-->
</Grid>
</Grid>
I dont have much choice in changing the layout. Using the above ManipulationDelta event in the usercontrol (which is enabled/disabled based on the child grid shown), I am able to get the drag behavior, but the control can go out of window bounds. So is there any way we can add the below FlickBehavior in WinRTXamlToolkit through code instead of xaml OR enable/disable the behavior based on some condition?
<i:Interaction.Behaviors>
<views:HeavyFlickBehavior />
</i:Interaction.Behaviors>
You can check the FlickBehavior
in WinRT XAML Toolkit for an example of how to achieve that with a parent Canvas
and Canvas.Top/Left
properties instead of RenderTransform
, assuming the Canvas
defines your bounds.
Here's an abstract:
private void OnAssociatedObjectManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
_startPosition = new Point(
Canvas.GetLeft(this.AssociatedObject),
Canvas.GetTop(this.AssociatedObject));
}
private void OnAssociatedObjectManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs manipulationDeltaRoutedEventArgs)
{
var dx = manipulationDeltaRoutedEventArgs.Cumulative.Translation.X;
var dy = manipulationDeltaRoutedEventArgs.Cumulative.Translation.Y;
var x = _startPosition.X + dx;
var y = _startPosition.Y + dy;
if (manipulationDeltaRoutedEventArgs.IsInertial)
{
while (x < 0 ||
x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth)
{
if (x < 0)
x = -x;
if (x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth)
x = 2 *
(_canvas.ActualWidth - this.AssociatedObject.ActualWidth) -
x;
}
while (y < 0 ||
y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight)
{
if (y < 0)
y = -y;
if (y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight)
y = 2 * (_canvas.ActualHeight - this.AssociatedObject.ActualHeight) -
y;
}
}
else
{
if (x < 0)
x = 0;
if (x > _canvas.ActualWidth - this.AssociatedObject.ActualWidth)
x = _canvas.ActualWidth - this.AssociatedObject.ActualWidth;
if (y < 0)
y = 0;
if (y > _canvas.ActualHeight - this.AssociatedObject.ActualHeight)
y = _canvas.ActualHeight - this.AssociatedObject.ActualHeight;
}
Canvas.SetLeft(this.AssociatedObject, x);
Canvas.SetTop(this.AssociatedObject, y);
}