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

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();
        }
    }
}

问题原因

  1. Margin设置逻辑错误:Margin的四个参数为Left, Top, Right, Bottom,按钮实际占用宽度是Left + Width + Right,高度是Top + Height + Bottom,当该值超过Grid宽高时,按钮会被挤出可视区域。
  2. Random实例重复创建:每次鼠标进入都新建Random,受系统时钟精度影响,可能生成重复随机值,导致位置异常。
  3. 未考虑按钮自身尺寸:随机位置时未减去按钮宽高,导致按钮右侧或底部超出容器边界。

修复方案

方案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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:05:23