首页 > 解决方案 > 如何一起创建平移和倾斜控件?

问题描述

我想在我的 WPF 应用程序中创建一个控件,允许用户在框/圆内拖动一个点。这将用于驱动摄像机的平移和倾斜值。

我不确定如何创建这样的控件。下图是我要开发的控件类型的示例。

在此处输入图像描述

标签: c#wpf

解决方案


这是一个非常快速的解决方案,可以帮助您入门。

对于 XAML,我使用Ellipse了“点”控件。Ellipse 放置在Canvas控件内(允许点移动):-

<Grid Background="White"
      MouseUp="ParentOnMouseUp">
    <Canvas x:Name="canvas" 
            Background="Green"
            Width="200"
            Height="200"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            MouseMove="CanvasOnMouseMove">

        <!-- Implement your blue circle b/g as an Image control here ... />

        <Ellipse x:Name="dot"
                 Width="20"
                 Height="20"
                 Fill="Blue"
                 Loaded="DotOnLoaded"
                 MouseDown="DotOnMouseDown"/>
    </Canvas>
</Grid>

首先我处理椭圆的MouseDown事件:

private void DotOnMouseDown(object sender, MouseButtonEventArgs e)
{
    _isDraggingDot = true;
}

我在这里所做的只是设置一个标志来指示我开始拖动圆点。

接下来,我处理Canvas MouseMove事件,这是我移动点的地方。它包括确保点不会偏离画布外部的逻辑:

private void CanvasOnMouseMove(object sender, MouseEventArgs e)
{
    if (_isDraggingDot)
    {
        var mousePos = e.GetPosition(canvas);

        var x = mousePos.X;
        if (x < 0)
        {
            x = 0;
        }
        if (x > canvas.Width)
        {
            x = canvas.Width;
        }

        var y = mousePos.Y;
        if (y < 0)
        {
            y = 0;
        }
        if (y > canvas.Height)
        {
            y = canvas.Height;
        }

        dot.SetValue(Canvas.LeftProperty, x - (dot.Width / 2.0)); // offset ensures dot is centred on mouse pointer
        dot.SetValue(Canvas.TopProperty, y - (dot.Height / 2.0));
        }
    }

这也是您计算点与中心的垂直和水平偏移的地方,并使用这些值来更新平移和倾斜。

最后,我MouseUp在外部控件(我的示例中的 Grid)上实现事件:

private void ParentOnMouseUp(object sender, MouseButtonEventArgs e)
{
    _isDraggingDot = false;
    CentreDot();
}

private void CentreDot()
{
    dot.SetValue(Canvas.LeftProperty, (canvas.Width / 2.0) - (dot.Width / 2.0));
    dot.SetValue(Canvas.TopProperty, (canvas.Height / 2.0) - (dot.Height / 2.0));
}

在外部控件上处理事件的原因是为了确保如果用户在 Canvas 外部释放鼠标按钮,点返回到中心。(请注意,我还在 Grid 上设置了 ab/g 颜色,否则默认为透明且不会检测到鼠标事件!)

最后,我将 Ellipse 的Loaded事件连接起来,以便在 UI 加载时最初将点居中:

private void DotOnLoaded(object sender, RoutedEventArgs e)
{
    CentreDot();
}

正如我所提到的,这只是一个快速的解决方案,其中点只是跟随鼠标。一个如果你不喜欢这样,你可以计算鼠标距离画布中心的距离(垂直和水平),然后使用这些值的一小部分来将点定位在远离中心的位置,实际上需要更多的鼠标移动到移动点,这可能感觉更“自然”。

另一个想法可能是将点的位置“捕捉”到最近的四个箭头按钮(N、S、E、W),或者甚至包括中间的点(NE、SE、SW、NW)。


推荐阅读