Reputation: 5005
I have a WindowContainer
class where all ChildWindows
gets automatically registered. The idea is, all ChildWindows
are "locked" inside of the WindowContainer
and you cannot move/drag them outside of this area.
ChildWindow
inherits from Window
.
I have already a solution where it is working:
// Events
private void ChildWindow_OnLocationChanged(object sender, EventArgs eventArgs)
{
_CheckBounds(sender as HtChildWindow);
}
private void ChildWindow_OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
{
_CheckBounds(sender as HtChildWindow);
}
// Private Methods
private void _CheckBounds(HtChildWindow window)
{
Rect trueWindowContainer = WindowContainer.TransformToAncestor(System.Windows.Application.Current.MainWindow).TransformBounds(new Rect(new Point(0, 0), WindowContainer.RenderSize));
if (window.Left < trueWindowContainer.X)
window.Left = trueWindowContainer.X;
if (window.Top < trueWindowContainer.Y)
window.Top = trueWindowContainer.Y;
if (window.Left + window.ActualWidth > trueWindowContainer.X + trueWindowContainer.Width)
window.Left = (trueWindowContainer.X + trueWindowContainer.Width) - window.ActualWidth;
if (window.Top + window.ActualHeight > trueWindowContainer.Y + trueWindowContainer.Height)
window.Top = (trueWindowContainer.Y + trueWindowContainer.Height) - window.ActualHeight;
}
So problem is, that the Window can still get moved outside of the area and it is lagging. I want to avoid this behavior by locking vertical or horizontal movement.
My solution approach would be catch a PreviewMouseMove
or PreviewDragMove
event. But I don't know how to do this. PreviewDragMove
does not exist.
// ##############################################################################################################################
// Properties
// ##############################################################################################################################
/// <summary>
/// True when when mouse is down on the dragmove area
/// </summary>
public bool IsMouseDownOnDrag { get; private set; }
private Rectangle _PartDragMove;
private Point _AnchorPoint;
private bool _IsDragging;
private Rect _DragMoveArea = Rect.Empty;
// ##############################################################################################################################
// Konstructor
// ##############################################################################################################################
private HtChildWindow()
{
Unloaded += _OnUnloaded;
Loaded += _OnLoaded;
}
private void _OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if(_DragMoveArea == Rect.Empty)
_DragMoveArea = SystemParameters.WorkArea;
}
private void _OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
if (_PartDragMove != null)
{
_PartDragMove.PreviewMouseLeftButtonDown -= PartDragMove_OnPreviewMouseLeftButtonDown;
}
}
// ##############################################################################################################################
// Overrides
// ##############################################################################################################################
public override void OnApplyTemplate()
{
_PartDragMove = GetTemplateChild("PART_DragMove") as Rectangle;
if (_PartDragMove != null)
{
_PartDragMove.PreviewMouseLeftButtonDown += PartDragMove_OnPreviewMouseLeftButtonDown;
}
base.OnApplyTemplate();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (IsMouseDownOnDrag)
{
_AnchorPoint = PointToScreen(e.GetPosition(this));
_IsDragging = true;
CaptureMouse();
e.Handled = true;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (_IsDragging)
{
Point currentPoint = PointToScreen(e.GetPosition(this));
double newLeftPosition = Left + currentPoint.X - _AnchorPoint.X;
double newTopPosition = Top + currentPoint.Y - _AnchorPoint.Y;
//control area
if (newLeftPosition < _DragMoveArea.X)
newLeftPosition = _DragMoveArea.X;
if (newTopPosition < _DragMoveArea.Y)
newTopPosition = _DragMoveArea.Y;
if(newLeftPosition + ActualWidth > _DragMoveArea.X + _DragMoveArea.Width)
newLeftPosition = _DragMoveArea.X + _DragMoveArea.Width - ActualWidth;
if (newTopPosition + ActualHeight > _DragMoveArea.Y + _DragMoveArea.Height)
newTopPosition = _DragMoveArea.Y + _DragMoveArea.Height - ActualHeight;
Left = newLeftPosition;
Top = newTopPosition;
_AnchorPoint = currentPoint;
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
IsMouseDownOnDrag = false;
if (_IsDragging)
{
_IsDragging = false;
e.Handled = true;
ReleaseMouseCapture();
}
}
// ##############################################################################################################################
// Events
// ##############################################################################################################################
private void PartDragMove_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
IsMouseDownOnDrag = true;
}
// ##############################################################################################################################
// Public Methods
// ##############################################################################################################################
public void SetDragMoveArea(Rect area)
{
_DragMoveArea = area;
}
So now I'm only calling SetDragMoveArea()
if my ChildWindow
should get locked inside of my WindowContainer
.
I'm extracting the information for this area with the following code
WorkingArea = WindowContainer.TransformToAncestor(System.Windows.Application.Current.MainWindow).TransformBounds(new Rect(new Point(0, 0), WindowContainer.RenderSize));
As default, is it locked inside of the Screen
(See _OnLoaded
).
Upvotes: 2
Views: 600
Reputation: 832
I have found a solution for you. If you want to customize movements you cannot use DragMove
method. Instead you have to implement this functionality on your own, overriding the following three functions: OnMouseLeftButtonDown
, OnMouseMove
and OnMouseLeftButtonUp
.
I have implemented something like that:
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
anchorPoint = e.GetPosition(this);
inDrag = true;
CaptureMouse();
e.Handled = true;
}
Where anchorPoint
is the point that I am using for Binging window position, inDrag
is private boolean and CaptureMouse
is UIElement
method.
And then:
protected override void OnMouseMove(MouseEventArgs e)
{
if (inDrag)
{
Point currentPoint = e.GetPosition(this);
this.Left = this.Left + currentPoint.X - anchorPoint.X;
/*this.Top = this.Top + currentPoint.Y - anchorPoint.Y*/; // this is not changing in your case
anchorPoint = currentPoint;
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
if (inDrag)
{
ReleaseMouseCapture();
inDrag = false;
e.Handled = true;
}
}
// Loss of capture e.g. when you press Alt + Tab
protected override void OnLostMouseCapture(MouseEventArgs e)
{
if (_inDrag)
{
ReleaseMouseCapture();
_inDrag = false;
e.Handled = true;
}
}
where ReleaseMouseCapture
is UIElement
method.
I think it should help you.
Upvotes: 4