【问题标题】:How to set the popup control hide automatically in WPF?如何在WPF中设置弹出控件自动隐藏?
【发布时间】:2015-08-12 10:48:55
【问题描述】:

如图所示,我希望鼠标进入 ButtonOne 按钮时显示“一个”弹出控件。当我将鼠标从 ButtonOne 移动到 Button Two 时,“One”弹出控件隐藏而“Two”显示。当鼠标不在按钮或弹窗上时,弹窗控件会自动隐藏。

我尝试使用 mouse_enter 和 mouse_leave 事件,但是当鼠标悬停在按钮上并移动时,弹出控件会闪烁。当鼠标不在按钮或弹出控件上时,弹出控件不会隐藏。

那么,如何解决这个问题?

XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <StackPanel>
        <Button Name="ButtonOne" Height="100" Width="100" HorizontalAlignment="Left" MouseEnter="Button_MouseEnter" MouseLeave="ButtonOne_MouseLeave">Button One</Button>
        <Button Name="ButtonTwo" Height="100" Width="100" HorizontalAlignment="Left" MouseEnter="Button_MouseEnter_1" MouseLeave="ButtonTwo_MouseLeave">Button Two</Button>
        <Popup Name="Pop1" StaysOpen="False" Placement="Right" PlacementTarget="{Binding ElementName=ButtonOne}" PopupAnimation="Fade" AllowsTransparency="True" MouseEnter="Pop1_MouseEnter" MouseLeave="Pop1_MouseLeave">
            <Border BorderBrush="Beige" BorderThickness="2" Background="White">
                <StackPanel>
                    <TextBlock Text="One"></TextBlock>
                    <Button Content="OneManagement"></Button>
                </StackPanel>
            </Border>
        </Popup>
        <Popup Name="Pop2" StaysOpen="False" Placement="Right" PlacementTarget="{Binding ElementName=ButtonTwo}"  PopupAnimation="Fade" AllowsTransparency="True">
            <Border BorderBrush="Beige" BorderThickness="2" Background="White">
                <StackPanel>
                    <TextBlock Text="Two"></TextBlock>
                    <Button Content="TwoManangement"></Button>
                </StackPanel>
            </Border>
        </Popup>
    </StackPanel>
</Grid>

代码背后:

    public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_MouseEnter(object sender, MouseEventArgs e)
    {
        Pop2.IsOpen = false;
        Pop1.IsOpen = true;
    }

    private void Button_MouseEnter_1(object sender, MouseEventArgs e)
    {
        Pop1.IsOpen = false;
        Pop2.IsOpen = true;
    }


    private void ButtonOne_MouseLeave(object sender, MouseEventArgs e)
    {
        Pop1.IsOpen = false;
    }

    private void ButtonTwo_MouseLeave(object sender, MouseEventArgs e)
    {
        Pop2.IsOpen = false;
    }

    private void Pop1_MouseEnter(object sender, MouseEventArgs e)
    {
        Pop1.IsOpen = true;
    }

    private void Pop1_MouseLeave(object sender, MouseEventArgs e)
    {
        Pop1.IsOpen = false;
    }

}

【问题讨论】:

  • 使用 .Visible 属性和 .Click 事件?
  • 你能发布你的 xaml 吗?

标签: c# wpf popup


【解决方案1】:

如果您将Pop1 StaysOpen 属性设置为False,则在弹出窗口打开的那一刻,将触发ButtonOneMouseLeave 事件,即使鼠标实际上仍在按钮上。之后,当弹出窗口仍处于打开状态时,您的按钮将不再触发 MouseEnterMouseLeave 事件。这是因为当StaysOpen 为假时,Popup 控件拦截所有鼠标和键盘事件,以确定这些事件之一何时发生在 Popup 控件之外。

因此,您可以将弹出窗口的StaysOpen 属性设置为True

<Popup Name="Pop1" StaysOpen="True" ...
<Popup Name="Pop2" StaysOpen="True" ...

然后,您的按钮的MouseLeave 事件处理程序可以检查鼠标离开的位置:

private void ButtonOne_MouseLeave(object sender, MouseEventArgs e)
{
    Point leavePoint = e.GetPosition(ButtonOne);
    if (leavePoint.X < ButtonOne.ActualWidth)
    {
        Pop1.IsOpen = false;
    }
}

private void ButtonTwo_MouseLeave(object sender, MouseEventArgs e)
{
    Point leavePoint = e.GetPosition(ButtonTwo);
    if (leavePoint.X < ButtonTwo.ActualWidth)
    {
        Pop2.IsOpen = false;
    }
}

通过检查离开位置,我们仅在鼠标通过弹出窗口位置以外的其他位置(在本例中位于按钮右侧)离开按钮时关闭弹出窗口。换句话说,对于这种情况,我们希望当鼠标从顶部、左侧和底部离开按钮时弹出窗口关闭,但如果鼠标从右侧离开按钮,我们希望保持弹出窗口打开。

随后,我们可以对弹出窗口MouseLeave 事件处理程序使用类似的逻辑:

private void Pop1_MouseLeave(object sender, MouseEventArgs e)
{
    Point leavePoint = e.GetPosition(ButtonOne);
    if (leavePoint.X > ButtonOne.ActualWidth)
    {
        Pop1.IsOpen = false;
    }
}

private void Pop2_MouseLeave(object sender, MouseEventArgs e)
{
    Point leavePoint = e.GetPosition(ButtonTwo);
    if (leavePoint.X > ButtonTwo.ActualWidth)
    {
        Pop2.IsOpen = false;
    }
}

【讨论】:

  • 有效!真是太神奇了!我还有几个问题: 1. 为什么StaysOpen设置为False,弹窗一打开,ButtonOne的MouseLeave事件就被触发了? 2.mouseleave事件检查位置时为什么不“闪烁”?换句话说,当我在 MouseLeave 事件中设置 IsOpen=false 时,为什么弹出控件会闪烁? 3. 在你的 ButtonOne_MouseLeave 和 ButtonTow_MouseLeave 方法中,应该是 leavePoint.X > ButtonOne.ActualWidth 和 leavePoint.X > ButtonTwo.ActualWidth?
  • 1.当StaysOpen 为假时,Popup 控件拦截所有鼠标和键盘事件,以确定这些事件之一何时发生在 Popup 控件之外。因此按钮失去其鼠标捕获,因此触发了MouseLeave 事件。
  • 2.我猜之前弹窗闪烁是因为MouseEnterMouseLeave 事件之间存在循环循环,所以弹窗反复打开和关闭。此外,通过检查离开位置,我们仅在鼠标通过弹出窗口位置以外的其他位置(在本例中位于按钮右侧)离开按钮时关闭弹出窗口。换句话说,对于这种情况,我们希望当鼠标从顶部、左侧和底部离开按钮时弹出窗口关闭,但如果鼠标从右侧离开按钮,我们希望保持弹出窗口打开。
  • 3.正如我在第 2 条中解释的那样,我猜代码 leavePoint.X &lt; ButtonOne.ActualWidth 是正确的。
【解决方案2】:

最好使用StaysOpen="False",这样当焦点丢失时弹出窗口会自动关闭。你可以像下面这样使用

<Popup x:Name="myPopUp" StaysOpen="False">

【讨论】:

  • @im-lucky 即使属性 StaysOpen 设置为 false,用户也需要单击其他位置才能使弹出窗口消失。用户在将鼠标从 ButtonOne 移动到 ButtonTwo 之前无法单击某处,然后在返回之前单击某处。
猜你喜欢
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
相关资源
最近更新 更多