Странное поведение во время движения UIElement. Зачем?
У меня проблемы с пониманием (и исправлением) ошибки, с которой я сталкиваюсь.
У меня есть пользовательский интерфейс, как на следующей картинке:
Все эти области, окрашенные в светло-голубой цвет, являются полотнами, и они являются подвижными. Вот где у меня есть проблема. Тот, что в левом верхнем углу, может быть перемещен без проблем. Два других, когда я их перетаскиваю, исчезают. Я не могу объяснить почему.
Это код для перемещения элементов:
// this is all inside the MouseMove event handler function
// If there is no dragged element
if (this.DraggedElement == null || !this.IsDragInProgress)
return;
/*
* Calculating the new position for the dragged element
*/
// Mouse current position
Point cursor = e.GetPosition(this);
double xMove = 0;
double yMove = 0;
// Movement detected
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
if (this.ConstrainToBounds(this.DraggedElement, mainWindow))
{
TranslateTransform translate = new TranslateTransform(xMove, yMove);
this.DraggedElement.RenderTransform = translate;
}
}
Предполагается, что код метода ConstrainToBounds() не позволяет мне перемещать холст за границы окна (он отлично работает для верхнего левого холста, но не для остальных) и выглядит следующим образом:
private Boolean ConstrainToBounds(Canvas element, UIElement container)
{
try
{
Boolean respects = true;
// Values used to reset the element position to a proper location
double xReset = 0;
double yReset = 0;
// Left x-axis constraint
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X + 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Right x-axis constraint
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X - 1;
yReset = element.TranslatePoint(new Point(), container).Y;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Top y-axis constraint
if (element.TranslatePoint(new Point(), container).Y <= new Point(0, 0).Y)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y + 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
// Bottom y-axis constraint
if (element.TranslatePoint(new Point(), container).Y + element.RenderSize.Height >= container.RenderSize.Height)
{
respects = false;
// Get elements' current position and adjust
xReset = element.TranslatePoint(new Point(), container).X;
yReset = element.TranslatePoint(new Point(), container).Y - 1;
TranslateTransform translate = new TranslateTransform(xReset, yReset);
element.RenderTransform = translate;
}
return respects;
}
catch (Exception ex)
{
throw ex;
}
}
Edit_1: добавлен код из MainWindow.xaml:
<Window
Name="mainWindow"
x:Class="WPF_TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="480" Width="555">
<Grid Name="mainGrid">
<Canvas Grid.Row="0"
Grid.Column="0"
Background="AliceBlue"
Name="LeftTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp" >
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Canvas Grid.Row="0"
Grid.Column="2"
Background="AliceBlue"
Name="RightTop"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Label Grid.Row="2"
Grid.Column="0"
Name="LeftBottom">
</Label>
<Canvas Grid.Row="2"
Grid.Column="3"
Background="AliceBlue"
Name="RightBottom"
MouseDown="onMouseDown"
MouseMove="onMouseMove"
MouseUp="onMouseUp">
<Ellipse Fill="Blue"
Width="100"
Height="100"/>
</Canvas>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="50" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Edit_2: Итак, я обнаружил, что когда я перемещаю верхний правый холст, он фактически выходит за пределы вида (в позиции 600,0). В настоящее время пытаюсь понять, почему это происходит.
1 ответ
Вместо использования преобразований рендера, может быть проще обновить Canvas Margin
имущество:
if (cursor != MouseClickLocation)
{
// Moving on the x-axis and y-axis
xMove = cursor.X - MouseClickLocation.X;
yMove = cursor.Y - MouseClickLocation.Y;
// Actually moving the element
this.DraggedElement.Margin = this.CalculateNewPosition(this.DraggedElement, mainWindow, xMove, yMove);
}
куда CalculateNewPosition
может выглядеть примерно так (предупреждение, не проверено):
private Thickness CalculateNewPosition(Canvas element, UIElement container, double translationX, double translationY)
{
Thickness currentPosition = element.Margin;
Thickness newPosition = new Thickness(currentPosition.Left + translationX, currentPosition.Top + translationY, 0, 0);
int containerWidth = container.ActualWidth;
int containerHeight = container.ActualHeight;
int elementWidth = element.ActualWidth;
int elementHeight = element.ActualHeight;
if (newPosition.Left < 0)
newPosition.Left = 0;
else if (newPosition.Left + elementWidth > containerWidth)
newPosition.Left = containerWidth - elementWidth;
if (newPosition.Top < 0)
newPosition.Top = 0;
else if (newPosition.Top + elementHeight > containerHeight)
newPosition.Top = containerHeight - elementHeight;
return newPosition;
}
Я не уверен, почему конкретно ваш код не работает для других кругов. Возможно, это связано с проверками границ, такими как:
if (element.TranslatePoint(new Point(), container).X <= new Point(0, 0).X)
if (element.TranslatePoint(new Point(), container).X + element.RenderSize.Width >= container.RenderSize.Width)
Предполагается, что new Point(0,0)
а также TranslatePoint
возвращаются точки относительно каждой содержащей ячейки сетки. Я не уверен, что это предположение верно; одно (или оба) сравнения могут быть абсолютными в отношении приложения или чего-либо подобного. Было бы трудно точно установить это только путем беглого изучения вашего кода; вам нужно будет запустить отладчик, проверить ваши значения и посмотреть, где они отличаются от того, что вы ожидаете.