WPF中Canvas.GetRight返回NaN,拖拽Thumb后坐标计算错误求助
Hey there! Let's break down why you're seeing those NaN values and fix that coordinate calculation issue with your draggable Thumb (template as Rectangle) in a Canvas.
Why Canvas.GetRight() and Canvas.GetBottom() return NaN
This is totally expected WPF behavior! When you position elements in a Canvas, you typically use Canvas.Left and Canvas.Top properties to set their top-left corner position. WPF only tracks Canvas.Right and Canvas.Bottom if you explicitly assign values to them. Since you're dragging the element (which modifies Canvas.Left/Canvas.Top under the hood), those right/bottom properties are never set—hence the NaN return values.
Why your manual calculation was wrong
Your formula assumed the element was positioned using Canvas.Right/Canvas.Bottom, but that's not the case here. When using Canvas.Left/Canvas.Top, the right edge of the element is simply the left position plus the element's actual width, and the bottom edge is the top position plus the element's actual height. Your original formula subtracted values from the Canvas width/height, which would only apply if you were using right/bottom-based positioning.
The Correct Solution
Here's how to get accurate left, top, right, and bottom coordinates after dragging:
Step 1: Handle the DragCompleted Event
In your code-behind, use the Thumb.DragCompleted event to capture the final position once dragging stops:
private void DragableThumb_DragCompleted(object sender, DragCompletedEventArgs e) { var dragableThumb = sender as Thumb; if (dragableThumb == null) return; // Get the top-left position from Canvas double left = Canvas.GetLeft(dragableThumb); double top = Canvas.GetTop(dragableThumb); // Calculate right and bottom using the element's actual rendered size double right = left + dragableThumb.ActualWidth; double bottom = top + dragableThumb.ActualHeight; // Use your coordinates as needed Console.WriteLine($"Final Position - Left: {left:F2}, Top: {top:F2}, Right: {right:F2}, Bottom: {bottom:F2}"); }
Key Notes
- Always use
ActualWidthandActualHeightinstead ofWidth/Height—these properties give you the rendered size of the control, which is critical if yourThumb(or its templateRectangle) uses dynamic sizing (likeAuto). - This calculation works regardless of the
Canvas's size, because we're measuring relative to the element's top-left corner (set byCanvas.Left/Canvas.Top), not theCanvas's edges. - If you ever need to set
Canvas.Right/Canvas.Bottomexplicitly (for right-aligned positioning), you could do so in the drag handler—but for most drag scenarios, sticking withLeft/Topis simpler.
Quick Check for Your XAML
Just to confirm, make sure your Thumb is properly placed in the Canvas and has its drag behavior set up. For example:
<Canvas x:Name="MainCanvas" Width="800" Height="600"> <Thumb x:Name="DragableThumb" DragDelta="DragableThumb_DragDelta" DragCompleted="DragableThumb_DragCompleted"> <Thumb.Template> <ControlTemplate> <Rectangle Width="100" Height="100" Fill="Blue" Stroke="Black"/> </ControlTemplate> </Thumb.Template> </Thumb> </Canvas>
And your DragDelta handler should update the Canvas.Left/Canvas.Top values:
private void DragableThumb_DragDelta(object sender, DragDeltaEventArgs e) { var thumb = sender as Thumb; if (thumb == null) return; Canvas.SetLeft(thumb, Canvas.GetLeft(thumb) + e.HorizontalChange); Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange); }
That should resolve both the NaN issue and the incorrect coordinate values!
内容的提问来源于stack exchange,提问作者nikhil

