我正在尝试使用附加属性将“平移”变换应用于我的Canvas-画布在拖动时会移动,但跳动性很强,并试图不断跳回到原始位置。当我滚动出画布时,它也会完全混乱,并将画布拖离屏幕。
我附加的属性类方法:
private Point _originalMouseDownPoint;
private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
var pos = mouseEventArgs.GetPosition(AssociatedObject);
MouseX = pos.X;
MouseY = pos.Y;
var canvas = sender as Canvas;
if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;
var translateTransform = new
TranslateTransform(pos.X - _originalMouseDownPoint.X, pos.Y - _originalMouseDownPoint.Y);
canvas.RenderTransform = translateTransform;
}
private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e) {
var canvas = sender as Canvas;
canvas.CaptureMouse();
canvas.Focus();
_originalMouseDownPoint = e.GetPosition(canvas);
BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
}
private void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e) {
var canvas = sender as Canvas;
canvas.ReleaseMouseCapture();
BaseViewModel.Mode = MouseHandlingModeEnum.None;
}
然后我的XAML只是通过画布行为来进行设置。
<i:Interaction.Behaviors>
<attachedProperties:MouseBehaviour MouseX="{Binding PanelX , Mode=OneWayToSource}"
MouseY="{Binding PanelY, Mode=OneWayToSource}" />
</i:Interaction.Behaviors>
(忽略绑定,它们是单独的功能。
程序应在画布上平移。我见过有人使用矩阵变换,是否应该尝试以某种方式实现它?
答案 0 :(得分:0)
根据我的经验,当我只需要以简单的方式拖动或移动对象时,我喜欢使用Canvas.Left / Top。当我做更复杂的事情时(很少见),我会使用转换。通常,它更容易调试和简化。 您可以执行以下操作:
private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
var pos = mouseEventArgs.GetPosition(AssociatedObject);
MouseX = pos.X;
MouseY = pos.Y;
var canvas = sender as Canvas;
if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;
Canvas.SetLeft(AssociatedObject, MouseX - _originalMouseDownPoint.X);
Canvas.SetTop(AssociatedObject, MouseY - _originalMouseDownPoint.Y);
}
private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e) {
var canvas = sender as Canvas;
canvas.CaptureMouse();
canvas.Focus();
_originalMouseDownPoint = e.GetPosition((UIElement)sender);
BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
}
private void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e) {
var canvas = sender as Canvas;
canvas.ReleaseMouseCapture();
_originalMouseDownPoint = null;
BaseViewModel.Mode = MouseHandlingModeEnum.None;
}
我假设您的BaseViewModel.Mode
是用于指示拖动条件的标志。
如果要将VM绑定到拖动,则可以添加Position属性并直接访问DataContext(var vm = DataContext as AssociatedObjectViewModel
)并设置新位置。然后,在XAML中,您可以将Canvas.Left
和Canvas.Top
绑定到这些属性。但是,这并非总是可能的,这取决于您如何设置所有内容,有时在“隐藏代码”中更轻松/更轻松地解决此问题。
答案 1 :(得分:0)
public class MouseBehaviour : Behavior<Panel> {
public static readonly DependencyProperty MouseYProperty = DependencyProperty.Register(
"MouseY", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));
public static readonly DependencyProperty MouseXProperty = DependencyProperty.Register(
"MouseX", typeof(double), typeof(MouseBehaviour), new PropertyMetadata(default(double)));
private Point _originalMouseDownPoint;
private double _hOff = 1;
private double _vOff = 1;
public double MouseY {
get => (double)GetValue(MouseYProperty);
set => SetValue(MouseYProperty, value);
}
public double MouseX {
get => (double)GetValue(MouseXProperty);
set => SetValue(MouseXProperty, value);
}
protected override void OnAttached() {
AssociatedObject.MouseUp += AssociatedObjectOnMouseUp;
AssociatedObject.MouseMove += AssociatedObjectOnMouseMove;
AssociatedObject.MouseDown += AssociatedObjectOnMouseDown;
}
protected override void OnDetaching()
{
AssociatedObject.MouseUp -= AssociatedObjectOnMouseUp;
AssociatedObject.MouseMove -= AssociatedObjectOnMouseMove;
AssociatedObject.MouseDown -= AssociatedObjectOnMouseDown;
}
/// <summary>
/// Deals with mouse movement event
/// </summary>
/// <param name="sender"></param>
/// <param name="mouseEventArgs"></param>oop
private void AssociatedObjectOnMouseMove(object sender, MouseEventArgs mouseEventArgs) {
//Keep track of position of mouse on the canvas
var canvasPosition = mouseEventArgs.GetPosition(AssociatedObject);
MouseX = canvasPosition.X;
MouseY = canvasPosition.Y;
//If we're currently panning
var canvas = sender as Canvas;
var scrollViewer = canvas.Parent as ScrollViewer;
//Position of the scroll viewer
var scrollPosition = mouseEventArgs.GetPosition(scrollViewer);
if (BaseViewModel.Mode != MouseHandlingModeEnum.Panning) return;
//Then update the scroll viewer based on our mouse movement
scrollViewer.ScrollToHorizontalOffset(
_hOff + (_originalMouseDownPoint.X - scrollPosition.X));
scrollViewer.ScrollToVerticalOffset(_vOff + (_originalMouseDownPoint.Y - scrollPosition.Y));
}
/// <summary>
/// Deals with the mouse down event on the canvas
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AssociatedObjectOnMouseDown(object sender, MouseButtonEventArgs e)
{
var canvas = sender as Canvas;
var scrollViewer = canvas.Parent as ScrollViewer;
//Gives the current offset of the scroll viewer
_hOff = scrollViewer.HorizontalOffset;
_vOff = scrollViewer.VerticalOffset;
_originalMouseDownPoint = e.GetPosition(scrollViewer);
BaseViewModel.Mode = MouseHandlingModeEnum.Panning;
canvas.CaptureMouse();
canvas.Focus();
}
/// <summary>
/// Deals with mouse up event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void AssociatedObjectOnMouseUp(object sender, MouseButtonEventArgs e)
{
var canvas = sender as Canvas;
canvas.ReleaseMouseCapture();
BaseViewModel.Mode = MouseHandlingModeEnum.None;
}
}
对于以后的读者来说,我最终使用了ScrollViewer,将Canvas包裹在Pan画布上,而Pan遍历了Pancan,现在看来它工作得很好。