【问题标题】:Popup not closing with 2 way binding to button弹出窗口未通过 2 路绑定按钮关闭
【发布时间】:2014-10-21 01:26:09
【问题描述】:

我有一个基于组合框功能的自定义控件。

下面是简化的模板:

<Window x:Class="WpfApplication70.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        WindowStartupLocation="CenterScreen">
    <StackPanel>
        <Grid>
            <ToggleButton  Name="PART_DropDownButton"
                           MinHeight="20"
                           ClickMode="Release">
                <Path x:Name="BtnArrow"
                      Height="4"
                      Width="8"
                      Stretch="Uniform"
                      Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "
                      Margin="0,0,6,0"
                      Fill="Black"
                      HorizontalAlignment="Right" />
            </ToggleButton>
            <Popup IsOpen="{Binding IsChecked, Mode=TwoWay, ElementName=PART_DropDownButton}"
                   StaysOpen="False"
                   MaxHeight="400">
                <Ellipse Fill="Red"
                         Width="50"
                         Height="50" />
            </Popup>
        </Grid>
    </StackPanel>
</Window>

这似乎可行,因为我可以单击按钮,弹出窗口打开,然后在我单击弹出窗口外部时关闭。

但是,我希望在按下按钮时打开弹出窗口,而不是松开。但是,当您在弹出窗口外单击时,将“ClickMode”更改为 Press 会停止弹出窗口关闭。

我该如何解决这个问题?

【问题讨论】:

标签: wpf binding popup


【解决方案1】:

通过阅读 ComboBox 的 .net 源代码设法弄清楚了这一点(不知道 CaptureMode.SubTree,所以也学到了一些新东西 :))。这是一个显示实际答案的 userControl。

XAML

<UserControl x:Class="WpfApplication74.CustomDropdown"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
    <ToggleButton  Name="PART_DropDownButton"
                   IsChecked="{Binding IsOpen, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                   MinHeight="20"
                   HorizontalContentAlignment="Right"
                   ClickMode="Press">
        <Path x:Name="BtnArrow"
              Height="4"
              Width="8"
              Stretch="Uniform"
              Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "
              Margin="0,0,6,0"
              Fill="Black" />
    </ToggleButton>
    <Popup IsOpen="{Binding IsOpen, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
           StaysOpen="False"
           MaxHeight="400"
           Width="{Binding ActualWidth, ElementName=PART_DropDownButton}"
           Opened="OnPopupOpened"
           Name="PART_Popup">
        <Border BorderThickness="1"
                BorderBrush="Black"
                Background="#EEE"
                Padding="20">
            <StackPanel>
                <TextBox />
                <Slider />
                <TextBox />
                <Slider />
            </StackPanel>
        </Border>
    </Popup>
</Grid>

代码隐藏

public partial class CustomDropdown : UserControl
{
    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }

    public static readonly DependencyProperty IsOpenProperty =
        DependencyProperty.Register("IsOpen", typeof(bool), typeof(CustomDropdown), new PropertyMetadata(false));

    public CustomDropdown()
    {
        InitializeComponent();
    }

    void OnPopupOpened(object sender, EventArgs e)
    {
        Mouse.Capture(this, CaptureMode.SubTree);
    }

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        if (Mouse.Captured == this && e.OriginalSource == this)
        {
            SetCurrentValue(CustomDropdown.IsOpenProperty, false);
            ReleaseMouseCapture();
        }

        e.Handled = true;
    }
}

【讨论】:

  • 非常感谢。这对我来说也是新的,对我帮助很大。我在 IsOpen 依赖属性更改事件中调用 Mouse.Capture。 (如组合框参考源referencesource.microsoft.com/#PresentationFramework/src/…)。否则我在从用户控件的另一个元素打开相同的弹出窗口时遇到问题。
【解决方案2】:

尝试在事件中手动设置Popup的属性IsOpen:Checked和Unchecked,当Popup关闭时,将ToggleButton.IsChecked重置为False。

例子:

XAML

<StackPanel>
    <Grid>
        <ToggleButton  Name="PART_DropDownButton"
                       Checked="PART_DropDownButton_Checked"
                       Unchecked="PART_DropDownButton_Unchecked">

            <Path x:Name="BtnArrow"
                  Height="4"
                  Width="8"
                  Stretch="Uniform"
                  Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "
                  Margin="0,0,6,0"
                  Fill="Black"
                  HorizontalAlignment="Right" />
        </ToggleButton>

        <Popup Name="MyPopup"
               StaysOpen="False"
               Closed="MyPopup_Closed"
               MaxHeight="400">

            <Ellipse Fill="White"
                     Width="50"
                     Height="50" />
        </Popup>
    </Grid>
</StackPanel>

Code-behind

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

    private void MyPopup_Closed(object sender, EventArgs e)
    {
        if (PART_DropDownButton != Mouse.DirectlyOver)
            PART_DropDownButton.IsChecked = false;
    }

    private void PART_DropDownButton_Checked(object sender, RoutedEventArgs e)
    {
        MyPopup.IsOpen = true;
    }

    private void PART_DropDownButton_Unchecked(object sender, RoutedEventArgs e)
    {
        MyPopup.IsOpen = false;
    }
}

【讨论】:

  • 不确定这应该有什么帮助。问题是我想将 ClickMode 设置为“Press”,以便在鼠标按下时打开弹出窗口,但这样做会禁用通常的“当您在其外部单击时关闭弹出窗口”行为
猜你喜欢
  • 1970-01-01
  • 2020-06-29
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-06
相关资源
最近更新 更多