WPF 如何检测 Popup 的最终位置

4
有没有可能检测弹出窗口的最终位置?我有一个自定义的弹出窗口,呈现在指定的UI元素下方,我想让它根据相对于指定的UI控件的位置绘制边框。默认行为是可以的,即弹出窗口在控件下方绘制。然而,根据弹出窗口的行为,如果它遇到屏幕边缘,弹出窗口会在不同的位置绘制。我的问题是,是否有办法检测弹出窗口的最终位置,然后根据其新位置绘制边框。还是需要手动处理以确定弹出窗口是否在不同于其默认放置位置的位置绘制。
下面是Git扩展中的一张图片,您可以看到没有将“dev”与下拉菜单的其余部分分开。现在我已经能够愉快地复制这种行为。然而,弹出窗口具有一个很好的功能,即如果遇到屏幕边缘,弹出窗口将相应地移动accordingly,不过这就是我的问题所在,因为当弹出窗口被移动或在另一个位置呈现时,我需要捕捉到这个移动并适当地绘制弹出窗口的边框,即使选择选项的弹出窗口在dev按钮上方被绘制,顶部也会有一个完整的线条,底部会有适当的间隙。我会抽空画个例子。

enter image description here


我相信在Popup中使用事件并检查Placement属性会得到你想要的结果。 - Kcvin
我尝试了Opened事件,但即使它在控件上方呈现,位置仍然设置为底部。 - Heinrich
你能分享一下你想要实现的屏幕吗? - pushpraj
我已经添加了更多的细节,希望能有所帮助 :) - Heinrich
1个回答

4
似乎您正在尝试在弹出框周围创建边框。 这里有一个示例。
<Grid>
    <ToggleButton Content="open popup"
                  x:Name="toggle"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center" />
    <Popup PlacementTarget="{Binding ElementName=toggle}"
           IsOpen="{Binding IsChecked,ElementName=toggle}"
           AllowsTransparency="True">
        <Border Background="White"
                CornerRadius="4"
                BorderBrush="Black"
                BorderThickness="1"
                Padding="5"
                Margin="0,0,10,10">
            <StackPanel>
                <Button Content="somebutton" />
                <RadioButton Content="a radiobutton" />
                <CheckBox Content="a checkbox" />
            </StackPanel>
            <Border.Effect>
                <DropShadowEffect Opacity=".25" />
            </Border.Effect>
        </Border>
    </Popup>
</Grid>

使用这种方法,即使弹出窗口的某些部分超出应用程序边界,您也可以绘制边框或阴影。
结果: popup 您可以将边框和/或阴影包装在可重用的样式中以实现重用。
编辑:
我尝试与您的要求匹配,并创建了相同的可重用模板。
<Grid RenderOptions.EdgeMode="Aliased">
    <Grid.Resources>
        <ControlTemplate TargetType="HeaderedContentControl"
                         x:Key="PopupButton">
            <Grid>
                <ToggleButton Content="{TemplateBinding Header}"
                              x:Name="toggle"
                              HorizontalAlignment="Center"
                              VerticalAlignment="Center">
                    <ToggleButton.Template>
                        <ControlTemplate TargetType="ToggleButton">
                            <Border BorderBrush="Gray"
                                    Background="White"
                                    BorderThickness="1"
                                    Padding="4"
                                    x:Name="border">
                                <StackPanel Orientation="Horizontal">
                                    <ContentPresenter />
                                    <TextBlock Text="▼"
                                               Margin="4,0,0,0"
                                               FontSize="8"
                                               VerticalAlignment="Center" />
                                </StackPanel>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked"
                                         Value="True">
                                    <Setter Property="BorderThickness"
                                            TargetName="border"
                                            Value="1,1,1,0" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </ToggleButton.Template>
                </ToggleButton>
                <Popup PlacementTarget="{Binding ElementName=toggle}"
                       IsOpen="{Binding IsChecked,ElementName=toggle}"
                       AllowsTransparency="True">
                    <Grid>
                        <Border Background="White"
                                BorderBrush="Gray"
                                BorderThickness="1"
                                Padding="5"
                                Margin="0,0,5,5">
                            <ContentPresenter />
                            <Border.Effect>
                                <DropShadowEffect Opacity=".25" />
                            </Border.Effect>
                        </Border>
                        <Rectangle Fill="White"
                                   Stroke="Transparent"
                                   StrokeThickness="1"
                                   Width="{Binding ActualWidth,ElementName=toggle}"
                                   Height="3"
                                   Margin=".5,-1,0,0"
                                   HorizontalAlignment="Left"
                                   VerticalAlignment="Top" />
                    </Grid>
                </Popup>
            </Grid>
        </ControlTemplate>
    </Grid.Resources>
    <HeaderedContentControl Header="dev"
                            Template="{StaticResource PopupButton}">
        <StackPanel>
            <Button Content="somebutton" />
            <RadioButton Content="a radiobutton" />
            <CheckBox Content="a checkbox" />
        </StackPanel>
    </HeaderedContentControl>
</Grid>

你可以在资源文件和应用程序中定义模板用于多个项目。
例如:
    <HeaderedContentControl Header="header"
                            Template="{StaticResource PopupButton}">
        <!--popup content here-->
    </HeaderedContentControl>

结果

结果


啊,是的,边框是个好主意,但问题是要确保弹出窗口和按钮之间没有出现缝隙。看一下编辑后的效果,希望能更清楚地解释一些 :) - Heinrich
看起来不错。但是如果你移动窗口,弹出框不会跟着移动。 对此有什么想法吗? - Christoph
@Christoph,这是弹出窗口的预期行为。最简单的方法是在窗口接收到点击等事件后关闭弹出窗口。另一个选项是将弹出窗口位置与主窗口同步。请随时为此创建一个新问题。 - pushpraj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接