You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建带指定刻度的WPF拖拽点控件并获取坐标?

Solution for Custom Scale Markings & Coordinate Mapping

Hey there! Let's tackle your two main challenges: adding the custom scale markings and mapping the dot's position to your desired coordinate range. Here's a step-by-step breakdown:

1. Adding Horizontal (-180 to +180) and Vertical (-30 to +30) Scale Markings

You can add scale lines and labels either directly in XAML (for static, fixed-size setups) or generate them dynamically in code-behind (great if your Canvas size might change later). Let's cover both approaches:

Option 1: Static Scale in XAML

Update your Canvas with pre-defined ticks and labels:

<Grid Background="White" MouseUp="ParentOnMouseUp">
    <Canvas x:Name="canvas" Background="Green" Width="200" Height="200" HorizontalAlignment="Center" VerticalAlignment="Center" MouseMove="CanvasOnMouseMove">
        <!-- Draggable Dot -->
        <Ellipse x:Name="dot" Width="20" Height="20" Fill="Blue" Loaded="DotOnLoaded" MouseDown="DotOnMouseDown"/>
        
        <!-- Horizontal X-axis: -180 to +180 -->
        <Line X1="0" Y1="190" X2="200" Y2="190" Stroke="Black" StrokeThickness="2"/>
        <!-- Major Ticks & Labels -->
        <Line X1="0" Y1="185" X2="0" Y2="195" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="-180" Canvas.Left="-15" Canvas.Top="195" Foreground="Black"/>
        
        <Line X1="50" Y1="185" X2="50" Y2="195" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="-90" Canvas.Left="42" Canvas.Top="195" Foreground="Black"/>
        
        <Line X1="100" Y1="185" X2="100" Y2="195" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="0" Canvas.Left="97" Canvas.Top="195" Foreground="Black"/>
        
        <Line X1="150" Y1="185" X2="150" Y2="195" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="+90" Canvas.Left="142" Canvas.Top="195" Foreground="Black"/>
        
        <Line X1="200" Y1="185" X2="200" Y2="195" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="+180" Canvas.Left="182" Canvas.Top="195" Foreground="Black"/>
        
        <!-- Vertical Y-axis: -30 to +30 -->
        <Line X1="10" Y1="0" X2="10" Y2="200" Stroke="Black" StrokeThickness="2"/>
        <!-- Major Ticks & Labels -->
        <Line X1="5" Y1="0" X2="15" Y2="0" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="+30" Canvas.Left="20" Canvas.Top="-5" Foreground="Black"/>
        
        <Line X1="5" Y1="50" X2="15" Y2="50" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="+15" Canvas.Left="20" Canvas.Top="45" Foreground="Black"/>
        
        <Line X1="5" Y1="100" X2="15" Y2="100" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="0" Canvas.Left="20" Canvas.Top="95" Foreground="Black"/>
        
        <Line X1="5" Y1="150" X2="15" Y2="150" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="-15" Canvas.Left="20" Canvas.Top="145" Foreground="Black"/>
        
        <Line X1="5" Y1="200" X2="15" Y2="200" Stroke="Black" StrokeThickness="2"/>
        <TextBlock Text="-30" Canvas.Left="20" Canvas.Top="195" Foreground="Black"/>
    </Canvas>
</Grid>

Option 2: Dynamic Scale Generation (Code-Behind)

If you want the scale to adapt to Canvas size changes, add this method to your code-behind:

private void GenerateScaleMarkings()
{
    // Horizontal Scale (-180 to +180)
    double horizontalTickStep = canvas.Width / 4;
    for (int i = 0; i <= 4; i++)
    {
        double xPos = i * horizontalTickStep;
        int labelVal = -180 + (i * 90);
        
        // Add tick line
        canvas.Children.Add(new Line
        {
            X1 = xPos, Y1 = canvas.Height - 10,
            X2 = xPos, Y2 = canvas.Height,
            Stroke = Brushes.Black, StrokeThickness = 2
        });
        
        // Add label
        var label = new TextBlock { Text = labelVal.ToString(), Foreground = Brushes.Black };
        Canvas.SetLeft(label, xPos - label.ActualWidth / 2);
        Canvas.SetTop(label, canvas.Height + 5);
        canvas.Children.Add(label);
    }
    
    // Vertical Scale (-30 to +30)
    double verticalTickStep = canvas.Height / 4;
    for (int i = 0; i <= 4; i++)
    {
        double yPos = i * verticalTickStep;
        int labelVal = 30 - (i * 15); // Top = +30, Bottom = -30
        
        // Add tick line
        canvas.Children.Add(new Line
        {
            X1 = 0, Y1 = yPos,
            X2 = 10, Y2 = yPos,
            Stroke = Brushes.Black, StrokeThickness = 2
        });
        
        // Add label
        var label = new TextBlock { Text = labelVal.ToString(), Foreground = Brushes.Black };
        Canvas.SetLeft(label, 15);
        Canvas.SetTop(label, yPos - label.ActualHeight / 2);
        canvas.Children.Add(label);
    }
}

Call this method in your DotOnLoaded event:

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

2. Mapping Dot Position to Your Desired Coordinates

To convert the dot's Canvas position to your target range (-180/+180 horizontal, -30/+30 vertical), add this mapping method:

private (double X, double Y) GetDotCoordinates()
{
    // Get the dot's center position on the Canvas
    double dotCenterX = (double)dot.GetValue(Canvas.LeftProperty) + dot.Width / 2;
    double dotCenterY = (double)dot.GetValue(Canvas.TopProperty) + dot.Height / 2;
    
    // Map X to -180 to +180
    double scaledX = ((dotCenterX / canvas.Width) * 360) - 180;
    
    // Map Y to +30 to -30 (WPF Y increases downward, so we invert the range)
    double scaledY = 30 - ((dotCenterY / canvas.Height) * 60);
    
    // Round for readability (adjust precision as needed)
    return (Math.Round(scaledX, 2), Math.Round(scaledY, 2));
}

Use this method whenever you need the coordinates—for example, in the ParentOnMouseUp event to get the final position after dragging:

private void ParentOnMouseUp(object sender, MouseButtonEventArgs e) 
{ 
    _isDraggingDot = false; 
    // Retrieve and use the coordinates
    var coords = GetDotCoordinates();
    Debug.WriteLine($"Dot Coordinates: X = {coords.X}, Y = {coords.Y}");
    // CentreDot(); 
}

Quick Note:

  • WPF's Y-axis increases downward, so we flip the vertical mapping to make the top of the Canvas correspond to +30 and the bottom to -30.

内容的提问来源于stack exchange,提问作者Ayan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:23:58