WPF应用中按钮为何持续超出边界?
WPF鼠标悬停按钮移动时超出边界问题解决
我是C#新手,代码可能存在冗余或问题,请见谅。
我正在学习WPF应用开发,想要实现鼠标悬停时按钮移动的功能,目前已实现该功能,但按钮会出现超出边界的问题。当随机数值超过230左右时,按钮会消失,直到放大窗口才会重新出现。我是否忽略了关键代码?
原XAML代码
<Window x:Class="Opdracht7.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Opdracht7" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Button x:Name="klikmij" Content="Click me!" MouseEnter="onMouseEnter" Click="onMouseClick" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="-0.989,-0.519" Height="33" Width="68"/> </Grid> </Window>
原C#代码
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using static System.Net.Mime.MediaTypeNames; namespace Opdracht7 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private void onMouseEnter(object sender, MouseEventArgs e) { Random rnd1 = new Random(); int value1 = rnd1.Next(0, 250); int value2 = rnd1.Next(0, 250); int value3 = rnd1.Next(0, 250); int value4 = rnd1.Next(0, 250); Debug.WriteLine(value1); Debug.WriteLine(value2); Debug.WriteLine(value3); Debug.WriteLine(value4); klikmij.Margin = new Thickness(value1,value2, value3, value4); } private void onMouseClick(object sender, RoutedEventArgs e) { MessageBox.Show("Congratulations! You won nothing!"); } public MainWindow() { InitializeComponent(); } } }
问题原因
- Margin设置逻辑错误:Margin的四个参数为
Left, Top, Right, Bottom,按钮实际占用宽度是Left + Width + Right,高度是Top + Height + Bottom,当该值超过Grid宽高时,按钮会被挤出可视区域。 - Random实例重复创建:每次鼠标进入都新建Random,受系统时钟精度影响,可能生成重复随机值,导致位置异常。
- 未考虑按钮自身尺寸:随机位置时未减去按钮宽高,导致按钮右侧或底部超出容器边界。
修复方案
方案1:调整Margin计算逻辑(基于Grid)
- 将Random提升为类成员,避免重复创建。
- 以容器可用空间(Grid宽高 - 按钮宽高)为随机上限,确保按钮完全在可视区域内。
- 仅设置Left和Top,Right和Bottom保持0即可。
修改后的C#代码:
using System; using System.Windows; using System.Windows.Input; namespace Opdracht7 { public partial class MainWindow : Window { private readonly Random _random = new Random(); private void onMouseEnter(object sender, MouseEventArgs e) { double maxWidth = gridContainer.ActualWidth - klikmij.ActualWidth; double maxHeight = gridContainer.ActualHeight - klikmij.ActualHeight; int left = _random.Next(0, (int)Math.Max(0, maxWidth)); int top = _random.Next(0, (int)Math.Max(0, maxHeight)); klikmij.Margin = new Thickness(left, top, 0, 0); } private void onMouseClick(object sender, RoutedEventArgs e) { MessageBox.Show("恭喜!你啥也没赢到!"); } public MainWindow() { InitializeComponent(); } } }
对应XAML给Grid命名:
<Window x:Class="Opdracht7.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="450" Width="800"> <Grid x:Name="gridContainer"> <Button x:Name="klikmij" Content="点我!" MouseEnter="onMouseEnter" Click="onMouseClick" Height="33" Width="68" HorizontalAlignment="Left" VerticalAlignment="Top"/> </Grid> </Window>
方案2:使用Canvas容器(更直观)
Canvas支持直接设置Canvas.Left和Canvas.Top控制元素位置,无需计算Margin。
修改后的XAML:
<Window x:Class="Opdracht7.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="450" Width="800"> <Canvas x:Name="canvasContainer"> <Button x:Name="klikmij" Content="点我!" MouseEnter="onMouseEnter" Click="onMouseClick" Height="33" Width="68"/> </Canvas> </Window>
修改后的C#代码:
using System; using System.Windows; using System.Windows.Input; namespace Opdracht7 { public partial class MainWindow : Window { private readonly Random _random = new Random(); private void onMouseEnter(object sender, MouseEventArgs e) { double maxX = canvasContainer.ActualWidth - klikmij.ActualWidth; double maxY = canvasContainer.ActualHeight - klikmij.ActualHeight; Canvas.SetLeft(klikmij, _random.Next(0, (int)Math.Max(0, maxX))); Canvas.SetTop(klikmij, _random.Next(0, (int)Math.Max(0, maxY))); } private void onMouseClick(object sender, RoutedEventArgs e) { MessageBox.Show("恭喜!你啥也没赢到!"); } public MainWindow() { InitializeComponent(); } } }
内容的提问来源于stack exchange,提问作者ZanyZilch
相关产品推荐
相关产品推荐

