【问题标题】:Button click event not responding after collapsing parent折叠父项后按钮单击事件没有响应
【发布时间】:2013-05-18 11:35:27
【问题描述】:

我有一个UserControl 和多个StackPanel。我喜欢根据用户操作隐藏特定面板。启动时可见的StackPanel 为我提供了许多工作按钮。这些按钮在代码隐藏文件中具有单击事件。折叠面板然后使其再次可见后,按钮不再起作用。这是我UserControl的一部分:

<StackPanel x:Name="buttonPanel" Orientation="Horizontal">
    <Button x:Name="ReMindNodeNotes" Content="&#xE104;"
            FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323" 
            HorizontalAlignment="Left" BorderThickness="1" Padding="0"
            UseLayoutRounding="True" Click="NoteClicked" />
    <Button x:Name="ReMindNodeRemove" Content="&#xE107;"
            FontFamily="Segoe UI Symbol" FontSize="14" Foreground="#FF292323" 
            HorizontalAlignment="Left" BorderThickness="1" Padding="0"
            UseLayoutRounding="True" Click="RemoveClicked" />
</StackPanel>

这里是代码(现在只是一些文本):

private void NoteClicked(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("NoteClicked...");
}

private void RemoveClicked(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("RemoveClicked...");
}

过去两天我一直在寻找解决方案。到目前为止没有运气。谁能帮忙...?

谢谢彼得


跟进 1...

下面是折叠面板的代码:

    private void MoreClicked(object sender, RoutedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(this.nodeName);
        this.buttonPanel.Visibility =
            this.buttonPanel.Visibility ==
                Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

如果 buttonPanel 有焦点,它就可以工作。如果焦点在另一个面板上,则不会。此外,我可能应该提到...用户可以创建用户控件的多个实例。

谢谢


跟进 2...

我当然会继续研究解决方案... ;-) 我找到了解决方案,但这不是我想要的解决方案。让我解释一下。

用户可以交互地创建前面提到的用户控件的多个实例。创建新实例时,该实例将获得焦点。现在每个实例都有自己的一组按钮,这些按钮位于堆栈面板上。当焦点转到另一个实例时,我希望前一个实例的面板折叠。然后应将焦点设置到新的(或选定的现有)实例。

当我手动执行此操作时,它可以工作!但是,当我尝试通过 GotFocus 和 LostFocus 事件来实现这一点时,它没有。这是手动解决方案的代码(有效):

    private void MoreClicked(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = 
            this.buttonPanel.Visibility == 
                Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
    }

以下是 LostFocus 和 GotFocus 事件:

    private void NodeGotFocus(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = Visibility.Visible;
    }

    private void NodeLostFocus(object sender, RoutedEventArgs e)
    {
        this.buttonPanel.Visibility = Visibility.Collapsed;
    }

非常感谢您的帮助!再次感谢...

【问题讨论】:

  • 你所说的行为很奇怪。你能分享你折叠面板的代码吗?
  • 我将代码添加到 Oleg 的原始帖子中。还不知道如何添加另一个帖子... ;-)
  • 我已经使用您的代码创建了一个示例应用程序 - 它按预期工作 - 似乎问题在于您如何使用页面上的控件,而不是事件处理程序本身。顺便说一句,当您在 XAML 中定义名称时,VS 会在代码隐藏中创建相应的字段,因此您只需执行 this.buttonPanel.Visibility
  • 感谢您的提示!我不知道访问面板和按钮可以直接在后面的代码中访问。你能把你的样品寄给我吗?这可能真的很有帮助!
  • 当然。我在您的个人资料中没有找到任何电子邮件,请发送至dropbox.com/s/698t98lqybyciwi/Sample.zip

标签: wpf button visibility stackpanel


【解决方案1】:

感谢您提供样品morincer。然而,问题要复杂一些。让我尝试解释经过更多研究后找到的解决方案。也许其他开发者也可以从中受益。

我将 GotFocus 和 LostFocus 事件添加到我的用户控件中。如果我单击用户控件内的某个位置,焦点每次都会更改。奇怪的是,这些事件仅在用户控件本身而不是子控件上定义。我在用户控件中有几个按钮和一个文本框,例如,当我单击具有焦点的用户控件的按钮之一时,无论如何都会为用户控件触发 LostFocus 和 GotFocus 事件。

在这种情况下,对我来说最重要的事件是 LostFocus 事件。当用户控件失去焦点时 - 例如另一个控件 - 我希望按钮面板消失。由于每次触摸用户控件内的对象时都会触发 LostFocus 事件,因此我无法区分要隐藏和显示按钮的情况。

通过如下更改 LostFocus 事件,我离解决方案更近了一点:

    private void LostFocus(object sender, RoutedEventArgs e)
    {
        Object fo = FocusManager.GetFocusedElement();
        if (fo.GetType().ToString().Contains("TextBox") ||
            fo.GetType().ToString().Contains("ScrollViewer"))
        {
            this.buttonPanel.Visibility = Visibility.Collapsed;
        }
    }

这涵盖了大多数情况。当光标位于 TextBox 中时,按钮面板关闭。当用户点击背景时,按钮面板也会关闭。这似乎是一个 ScrollViewer(通过调试代码找到)。谁能解释一下...?

然而,没有涉及的情况是当用户点击另一个用户控件时。当然,当用户单击 TextBox(请参阅代码)时会这样做,但当用户单击按钮时不会。我试图比较 sender 和 FocusManager.GetFocusedElement()。问题是发件人返回用户控件(这是我正在寻找的),但 FocusManager.GetFocusedElement() 返回被按下的按钮。现在我可以要求它是一个边框的父级,然后要求它是一个堆栈面板的边框父级,依此类推,直到我到达用户控件。然而,引入了文件隐藏代码,其想法是拆分设计和逻辑,而该解决方案会将它们再次绑定在一起。如果我要更改 XAML,我也必须更改逻辑。对我来说似乎不是正确的解决方案。

我通过在构造函数中给每个用户控件一个唯一的名称找到了一个独奏。然后我也给所有按钮唯一的名称(无论如何我不在我的代码中使用它们)从用户控件的名称开始。然后,这使我可以在运行时比较名称并确定焦点是否已更改到用户控件的另一个实例。代码如下:

    private void NodeLostFocus(object sender, RoutedEventArgs e)
    {
        Object fo = FocusManager.GetFocusedElement();
        if (fo.GetType().ToString().Contains("ScrollViewer"))
        {
            this.buttonPanel.Visibility = Visibility.Collapsed;
        }
        else if (fo.GetType().ToString().Contains("TextBox"))
        {
            if (!((TextBox)fo).Name.Contains(this.nodeName))
            {
                this.buttonPanel.Visibility = Visibility.Collapsed;
            }
        }
        else if (fo.GetType().ToString().Contains("Button"))
        {
            if (!((Button)fo).Name.Contains(this.nodeName))
            {
                this.buttonPanel.Visibility = Visibility.Collapsed;
            }
        }
    }

现在可以了!但是……我不喜欢这个解决方案。我依赖于名称而不是一个好的架构。有谁知道如何将实际发送者与作为按下按钮的父级的用户控件(FocusManager.GetFocusedElement())进行比较?或者任何其他依赖于良好编程的解决方案?

再次感谢

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    相关资源
    最近更新 更多