【问题标题】:WPF popup location issueWPF弹出位置问题
【发布时间】:2013-12-03 22:32:53
【问题描述】:

我遇到了一个奇怪的 WPF 弹出窗口放置问题。

我已经定义了这个 XAML:

<Window x:Class="PositionBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="300" Width="525">
<Grid>
    <TextBlock Name="Textblock1" Height="60" Width="300" Background="LightGray" HorizontalAlignment="Center"
               VerticalAlignment="Bottom">The PlacementTarget</TextBlock>
    <Popup Name="Popup1" PlacementTarget="{Binding ElementName=Textblock1}" Placement="Top" Width="120" Margin="198,0,199,0" IsOpen="True">
        <TextBlock Background="LightBlue" FontSize="18">This is a Popup</TextBlock>
    </Popup>
</Grid>

在大多数计算机上,这是预期的结果:

但是,在一个特定计算机型号的多个单元上,结果显示如下:

有没有办法强制放置在顶部和左侧?

【问题讨论】:

  • 这很奇怪!您是否检查过它们都使用相同版本的 .NET 框架并且两种显示分辨率相同?
  • 所有计算机都运行 1024x768 显示分辨率和相同版本的 .NET Framework。我试过 4、4.5 和 4.5.1,结果相同。
  • 你解决过这个问题吗?我发现控制弹出窗口是左还是右的系统设置会影响这一点,但我找不到很好的解决方案。
  • 不,我从来没有找到解决方案。那个系统设置在哪里?
  • 我在用于开发的 HP Envy 笔记本电脑上遇到了相同的行为,即顶部或底部放置右对齐弹出窗口。我们的其他开发人员没有看到这种行为,但他们有不同的笔记本电脑品牌。绝对似乎是特定于机器/配置的。在目标、弹出和弹出内容上使用 FlowDirection 属性也没有帮助。该死!

标签: wpf xaml


【解决方案1】:

更新:如果您想让它适用于整个窗口,这是一个更好的解决方案:WPF Handedness with Popups

原文:

我意识到这是一个旧线程,但我只是遇到了这个问题。有了这个:

<Popup 
    Name="Popup"
    Placement="Bottom" 
    PlacementTarget="{Binding ElementName=ToggleButton}"
    ...

我明白了:

我不想依赖用户设置,我想避免背后的代码和数学。所以我只是做了这个 DIRTY hack,但在角落里使用了一个空心矩形。好消息是所有用于在屏幕不同边缘移动弹出窗口的内置逻辑都仍然有效:

<!--POPUP PLACEMENT HACK-->
<Rectangle 
  x:Name="PART_PopPlacer" 
  Fill="Red"
  Width="0" 
  Height="0"
  HorizontalAlignment="Left"
  VerticalAlignment="Bottom"
  Focusable="False"
  Visibility="Hidden"
  IsHitTestVisible="False"
/>

<Popup 
    Name="Popup"
    Placement="Left" 
    PlacementTarget="{Binding ElementName=PART_PopPlacer}"
    ...

这给了这个:

完整代码(应该将矩形放在 xaml 的顶部,这样它就可以被级联元素覆盖):

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
    <!-- COMBO BOX STYLE AND TEMPLATE -->
    <Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
        <Setter Property="MinWidth" Value="120"/>
        <Setter Property="MinHeight" Value="20"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ComboBox}">
                    <Grid>

                        <ToggleButton 
                            Background="White"
                            Focusable="false"
                            IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
                            ClickMode="Press"
                          />

                        <ContentPresenter
                            Name="ContentSite"
                            IsHitTestVisible="False" 
                            Content="{TemplateBinding SelectionBoxItem}"
                            Margin="2"
                          />

                        <!--POPUP PLACEMENT HACK-->
                        <Rectangle 
                          x:Name="PART_PopPlacer" 
                          Fill="Red"
                          Width="0" 
                          Height="0"
                          HorizontalAlignment="Left"
                          VerticalAlignment="Bottom"
                          Focusable="False"
                          Visibility="Hidden"
                          IsHitTestVisible="False"
                      />

                        <Popup 
                            Name="Popup"
                            Placement="Left" 
                            PlacementTarget="{Binding ElementName=PART_PopPlacer}"
                            VerticalOffset="6"
                            IsOpen="{TemplateBinding IsDropDownOpen}"
                            AllowsTransparency="True" 
                            Focusable="False"
                            PopupAnimation="Slide">
                            <Grid 
                              Name="DropDown"
                              SnapsToDevicePixels="True">
                                <Border 
                                    Name="DropDownBorder"
                                    Background="LightYellow"
                                    BorderThickness="1"
                                    BorderBrush="Black"/>
                                <ScrollViewer Margin="2" SnapsToDevicePixels="True">
                                    <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
                                </ScrollViewer>
                            </Grid>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</Page.Resources>

<StackPanel>
    <ComboBox Height="20" Width="50" SelectedIndex="0" Margin="20">
        <ComboBoxItem Content="Very Very Very Very Long Text" />
        <ComboBoxItem Content="Text" />
        <ComboBoxItem Content="Text" />
        <ComboBoxItem Content="Text" />
        <ComboBoxItem Content="Text" />
    </ComboBox>
</StackPanel>

</Page>

【讨论】:

    【解决方案2】:

    菜单和弹出窗口的左右对齐似乎由这个特殊的注册表项控制:

    HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows

    REG_SZ: MenuDropAlignment

    Value: 0 表示向右

    Value: 1 表示向左

    不知何故,我的系统将菜单和弹出窗口的对齐方式从右向左切换了。我检查了这个注册表项,果然值是 1,所以我把它改回 0,现在我的 WPF 弹出对齐按预期工作。

    【讨论】:

      【解决方案3】:

      我能够在我的 HP 笔记本电脑上解决此问题。事实证明,因为它有一个触摸屏,它使用左/右“惯用手”来选择下拉菜单和弹出窗口是与目标控件左对齐还是右对齐(使用上对齐或下对齐时)。

      要修复,请转到控制面板,搜索(右上角)并键入 Tablet PC 设置。在该对话框中(在某些版本的 Windows 上的 General 选项卡下,在其他 PC 上的 Other 选项卡下)您会看到右手和左手操作选项。

      如果菜单和弹出窗口显示在被触摸点的左侧,则右对齐弹出窗口“更好”,因此右手不会遮挡组件。当然,如果您主要使用鼠标,那么它看起来很奇怪,会让我们开发人员感到困惑!

      【讨论】:

        【解决方案4】:

        我在正在处理的应用程序中遇到了同样的弹出窗口问题。我不能指望客户更改他们平板电脑上的设置,所以我使用这段代码为每个人修复了弹出位置:

        var simplePlacement = new CustomPopupPlacement(new Point(0, 0), PopupPrimaryAxis.None);
        popup.Placement = PlacementMode.Custom;
        popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback((popupSize, targetSize, offset) => new [] { simplePlacement });
        

        【讨论】:

        • 对我不起作用。
        【解决方案5】:

        进入“系统设置” - “硬件和声音” - “平板电脑设置” - “用于书写手” - 选择“右手”(PopUps、DropDowns 左对齐) 或“左撇子”(PopUps、DropDowns 右对齐)

        【讨论】:

          猜你喜欢
          • 2015-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-28
          相关资源
          最近更新 更多