在WPF中检测点击和弹出按钮外部

在WPF中检测点击和弹出按钮外部,wpf,Wpf,我对WPF中的弹出按钮有问题。 当我按下它一次,弹出窗口显示一些项目来选择ElementTreeControl。在我按下相同的弹出按钮后,它应该会关闭,但它会关闭并再次打开。 我解决了这个问题,它也工作了,但是当我在这个控件之外单击,它关闭了StayOpen=false,我无法再次打开它-需要按两次PopupButton 在如何检测控件何时被按下以及何时处于其外部区域方面,是否有一些属性或解决方法 我希望弹出按钮是: 关闭时: 单击即可打开 打开时: 通过第二次单击弹出按钮关闭 通过单击外部区域

我对WPF中的弹出按钮有问题。 当我按下它一次,弹出窗口显示一些项目来选择ElementTreeControl。在我按下相同的弹出按钮后,它应该会关闭,但它会关闭并再次打开。 我解决了这个问题,它也工作了,但是当我在这个控件之外单击,它关闭了StayOpen=false,我无法再次打开它-需要按两次PopupButton

在如何检测控件何时被按下以及何时处于其外部区域方面,是否有一些属性或解决方法

我希望弹出按钮是:

关闭时:

单击即可打开 打开时:

通过第二次单击弹出按钮关闭 通过单击外部区域关闭 弹出按钮单击操作:

private Popup rtWindowBoundsPopup;

private async void ButtonClickAsync(object pmSender, RoutedEventArgs pmE)
{
    if (pmSender is PopupButton lcButton)
    {
        if (lcButton.Tag is StarElement lcStarElement)
        {
            if (!string.IsNullOrEmpty(DatabaseName))
            {
                lcStarElement = await rtStarHelper.AssureMetaData(lcStarElement, DatabaseName);
            }
            else
            {
                StarDim lcStarDim = rtStarHelper.GetDimFromDimId(lcStarElement.Dim.DimId, true);
                lcStarElement.Dim = await rtStarHelper.AssureMetaData(lcStarDim);
            }
            ShowTreeViewPopup(lcButton, lcStarElement);
        }
    }
}


private void ShowTreeViewPopup(PopupButton pmButton, StarElement pmStarElement)
 {
     ElementTreeControl lcElementTreeControl;
     if (rtWindowBoundsPopup == null)
     {
         rtWindowBoundsPopup = new Popup();// { IsLightDismissEnabled = true };
        rtWindowBoundsPopup.Opened += WindowBoundsPopupOpened;
     }

     if (rtWindowBoundsPopup.Child is ElementTreeControl lcTreeControl)
     {
         lcElementTreeControl = lcTreeControl;
         lcElementTreeControl.HideAddionalCols();
     }
     else
     {
         lcElementTreeControl = new ElementTreeControl { Tag = pmButton };
         rtWindowBoundsPopup.Child = lcElementTreeControl;
         lcElementTreeControl.SelectionChanged += PopupListBoxSelectionChangedAsync;
     }

     Point lcPoint = UiHelper.CalcOffsets(pmButton);
     Rect lcCurrentwindowbounds = CurrentWindow.RestoreBounds;
     if (lcPoint.Y < lcCurrentwindowbounds.Height / 2)
     {
         lcElementTreeControl.MaxHeight = lcCurrentwindowbounds.Height - lcPoint.Y - pmButton.ActualHeight;
     }
     else
     {
         lcElementTreeControl.MaxHeight = lcPoint.Y - pmButton.ActualHeight;
     }
     lcElementTreeControl.Width = Math.Max(pmButton.ActualWidth, 400);
     lcElementTreeControl.MaxWidth = lcCurrentwindowbounds.Width;
     lcElementTreeControl.MinHeight = 150;
     lcElementTreeControl.Init(rtStarCube, pmStarElement, rtStarHelper);
     lcElementTreeControl.CaptionColWidth = lcElementTreeControl.Width;
     rtWindowBoundsPopup.PlacementTarget = pmButton;
     rtWindowBoundsPopup.Placement = PlacementMode.Bottom;
     rtWindowBoundsPopup.StaysOpen = false;//false;
     rtWindowBoundsPopup.Closed -= WindowBoundsPopupOnClosed;
     rtWindowBoundsPopup.Closed += WindowBoundsPopupOnClosed;

     rtWindowBoundsPopup.IsOpen = true;
}

在WindowBoundsPopupOnClosed中,什么都没有发生,我尝试过让它在那里工作,但没有这样做。

在哪里关闭弹出窗口?我只看到你把IsOpen设置为true。当前行为:第一次单击PopupButton将打开弹出窗口。现在由于StaysOpen设置为false,再次单击弹出窗口外的按钮将关闭弹出窗口,因为弹出窗口已失去焦点,因为它已从弹出窗口移动到弹出按钮。IsOpen现在返回false。然后,第二次单击将调用事件处理程序ButtonClickAsync,它将IsOpen再次设置为true,从而重新打开弹出窗口

您的代码太复杂了,因为您使用的是C而不是XAML

PopupButton应该是一个ToggleButton或者基于它

<Window>
  <StackPanel>
    <ToggleButton x:Name="PopupButton" />
    <Popup IsOpen="{Binding ElementName=PopupButton, Path=IsChecked}">
      <ElementTreeControl Tag="pmButton" />
    </Popup>
  </StackPanel>
</Window>
UserControl,其中包含PopupButton

评论 然后,应该从ElementTreeControl类内的ElementTreeControl.Loaded事件处理程序调用ElementTreeControl.Init等方法。我现在不知道StarElement是什么,但它应该绑定到ElementTreeControl的DependencyProperty。我没有足够的上下文,但我想您应该添加ElementTreeControl.OnSelectionChanged的覆盖,这样您就可以将PopUpplistBoxSelectionChangedAsync的代码移动到ElementTreeControl


为什么不能尝试在放置弹出窗口的视图中捕获单击事件。因此,当您在弹出窗口外单击时,事件将被触发。您好!这是来自遗留代码,这就是它如此复杂的原因。popupButton是从其他控件启动的,但我将尝试调整您使用toggleButton所说的内容。弹出窗口关闭,因为属性StaysOpen设置为false,并且在选择更改事件中-IsOpen设置为false。您仍然可以绑定到按钮,无论它定义在何处。您还可以使用EventTrigger。我更新了我的问题,展示了如何使用ÈventTrigger`,通过点击切换按钮来切换弹出窗口。这可能是您场景中的最佳解决方案。
<Window>
  <Window.Triggers>

    <!-- 
      EventTriggers must be defined in the scope of the Popup "RtWindowBoundsPopup" 
      and in the routing path of the raised event.
    -->
    <EventTrigger RoutedEvent="ToggleButton.Unchecked" 
                  Sourcename="PopupButton">      
      <BeginStoryboard>
        <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="RtWindowBoundsPopup"
                                          Storyboard.TargetProperty="IsOpen"
                                          Duration="0">
            <DiscreteBooleanKeyFrame Value="False" />
          </BooleanAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>

    <EventTrigger RoutedEvent="ToggleButton.Checked" 
                  Sourcename="PopupButton">      
      <BeginStoryboard>
        <Storyboard>
          <BooleanAnimationUsingKeyFrames Storyboard.TargetName="RtWindowBoundsPopup"
                                          Storyboard.TargetProperty="IsOpen"
                                          Duration="0">
            <DiscreteBooleanKeyFrame Value="True" />
          </BooleanAnimationUsingKeyFrames>
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Window.Triggers>

  <StackPanel>
    <ControlWithPopupButton />
    <Popup x:Name="RtWindowBoundsPopup">
      <ElementTreeControl Tag="pmButton" />
    </Popup>
  </StackPanel>
</Window>
<ControlWithPopupButton>

  <!-- 
    PopupButton must derive from ToggleButton
    or raise both Routed Events ToggleButon.Check and ToggleButton.Unchecked. 
  -->
  <PopupButton x:Name="PopupButton" />
</ControlWithPopupButton>