首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在单击另一个控件时打开WPF弹出窗口,仅使用XAML标记?

如何在单击另一个控件时打开WPF弹出窗口,仅使用XAML标记?
EN

Stack Overflow用户
提问于 2008-12-12 06:19:12
回答 5查看 144K关注 0票数 63

我有两个控件,一个是TextBlock,一个是PopUp。当用户在文本块上单击(MouseDown)时,我希望显示弹出窗口。我认为我可以在弹出窗口中使用EventTrigger来实现这一点,但我不能在EventTrigger中使用setter,我只能启动故事板。我想严格地用XAML来做这件事,因为这两个控件在一个模板中,而我不知道如何在代码中找到弹出窗口。

从概念上讲,这是我想要做的,但不能做,因为您不能在EventTrigger中放置setter (就像使用DataTrigger一样):

<TextBlock x:Name="CCD">Some text</TextBlock>

<Popup>
    <Popup.Style>
        <Style>
            <Style.Triggers>
                <EventTrigger SourceName="CCD" RoutedEvent="MouseDown">
                    <Setter Property="Popup.IsOpen" Value="True" />
                </EventTrigger>
            </Style.Triggers>
        </Style>
    </Popup.Style>
...

当事件发生在不同的控件上时,在XAML中严格显示弹出窗口的最佳方式是什么?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2008-12-30 09:00:15

我做了一些简单的事情,但是很有效。

我使用了一个典型的ToggleButton,通过更改其控件模板将其重新设置为文本块的样式。然后,我将ToggleButton上的IsChecked属性绑定到弹出窗口上的IsOpen属性。Popup有一些像StaysOpen这样的属性,可以让你修改关闭行为。

下面的代码在XamlPad中有效。

 <StackPanel>
  <ToggleButton Name="button"> 
    <ToggleButton.Template>
      <ControlTemplate TargetType="ToggleButton">
        <TextBlock>Click Me Here!!</TextBlock>
      </ControlTemplate>      
    </ToggleButton.Template>
  </ToggleButton>
  <Popup IsOpen="{Binding IsChecked, ElementName=button}" StaysOpen="False">
    <Border Background="LightYellow">
      <TextBlock>I'm the popup</TextBlock>
    </Border>
  </Popup> 
 </StackPanel>
票数 89
EN

Stack Overflow用户

发布于 2012-01-21 02:23:48

以下方法与Helge Klein的方法相同,不同之处在于当您单击弹出窗口之外的任何位置(包括ToggleButton本身)时,弹出窗口会自动关闭:

<ToggleButton x:Name="Btn" IsHitTestVisible="{Binding ElementName=Popup, Path=IsOpen, Mode=OneWay, Converter={local:BoolInverter}}">
    <TextBlock Text="Click here for popup!"/>
</ToggleButton>

<Popup IsOpen="{Binding IsChecked, ElementName=Btn}" x:Name="Popup" StaysOpen="False">
    <Border BorderBrush="Black" BorderThickness="1" Background="LightYellow">
        <CheckBox Content="This is a popup"/>
    </Border>
</Popup>

在IsHitTestVisible绑定中使用"BoolInverter“,这样当您再次单击ToggleButton时,弹出窗口将关闭:

public class BoolInverter : MarkupExtension, IValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool)
            return !(bool)value;
        return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Convert(value, targetType, parameter, culture);
    }
}

...which集中展示了combining IValueConverter and MarkupExtension的便捷技术。

我确实发现了这种技术的一个问题:当屏幕上同时出现两个弹出窗口时,WPF是错误的。具体地说,如果您的切换按钮在工具栏中的“溢出弹出窗口”上,那么在您单击它之后会有两个弹出窗口打开。然后,您可能会发现,当您单击窗口上的其他位置时,第二个弹出窗口(您的弹出窗口)将保持打开状态。在这一点上,关闭弹出窗口是困难的。用户不能再次单击ToggleButton关闭弹出窗口,因为IsHitTestVisible为假,因为弹出窗口是打开的!在我的应用程序中,我不得不使用一些技巧来缓解这个问题,比如下面在主窗口上的测试,它说(路易·布莱克的声音)“如果弹出窗口是打开的,而用户点击了弹出窗口之外的某个地方,就关闭这个该死的弹出窗口。”:

PreviewMouseDown += (s, e) =>
{
    if (Popup.IsOpen)
    {
        Point p = e.GetPosition(Popup.Child);
        if (!IsInRange(p.X, 0, ((FrameworkElement)Popup.Child).ActualWidth) ||
            !IsInRange(p.Y, 0, ((FrameworkElement)Popup.Child).ActualHeight))
            Popup.IsOpen = false;
    }
};
// Elsewhere...
public static bool IsInRange(int num, int lo, int hi) => 
    num >= lo && num <= hi;
票数 54
EN

Stack Overflow用户

发布于 2015-03-27 18:32:22

下面使用EventTrigger来显示Popup。这意味着我们不需要用于状态绑定的ToggleButton。在本例中,使用了ButtonClick事件。您可以调整它以使用另一个元素/事件组合。

<Button x:Name="OpenPopup">Popup
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.Click">
            <EventTrigger.Actions>
                <BeginStoryboard>
                    <Storyboard>
                        <BooleanAnimationUsingKeyFrames 
                                 Storyboard.TargetName="ContextPopup" 
                                 Storyboard.TargetProperty="IsOpen">
                            <DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
                        </BooleanAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger.Actions>
        </EventTrigger>
    </Button.Triggers>
</Button>
<Popup x:Name="ContextPopup"
       PlacementTarget="{Binding ElementName=OpenPopup}"
       StaysOpen="False">
    <Label>Popupcontent...</Label>
</Popup>

请注意,Popup通过名称引用Button,反之亦然。因此,PopupButton上都需要x:Name="..."

实际上,可以通过将Storyboard内容替换为描述in this SO Answer的自定义SetProperty EventTrigger操作来进一步简化它

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/361209

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档