首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >WPF将弹出窗口置于切换按钮下的固定位置

WPF将弹出窗口置于切换按钮下的固定位置
EN

Stack Overflow用户
提问于 2018-08-01 12:25:59
回答 1查看 604关注 0票数 0

我正在尝试构建一个显示ListView的自定义ComboBox。下面是我试图实现的一个屏幕截图:

我的大部分代码都基于this very helpful blog,它讨论了如何将DataGrid (或者在我的例子中是GridView)嵌入到ComboBox中。从功能的角度来看,一切都在工作。然而,我似乎找不到一种方法来修复下拉。理想情况下,我希望它总是出现在上面,无论窗口大小或窗口位置如何。当前,弹出窗口尝试右对齐,除非窗口靠近屏幕的左边缘,此时弹出窗口会向内移动。问题是,正如下面的XAML所示,ListView位于弹出窗口中,而弹出窗口并不真正绑定到正常窗口,因此我们无法直接控制它们的位置。

代码语言:javascript
运行
复制
<Window.Resources>
  <Style x:Key="ComboBoxTest2" TargetType="{x:Type ComboBox}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="ComboBox">
          <Grid>
            <ToggleButton x:Name="TGButton" Grid.Column="2" Focusable="false"
                          IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
                          RelativeSource={RelativeSource TemplatedParent}}"
                          Padding="0,0,50,0">
              <ToggleButton.Template>
                <ControlTemplate>
                  <Grid>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="*" />
                      <ColumnDefinition Width="30" />
                    </Grid.ColumnDefinitions>
                    <Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="5"
                         Background="LightGray" BorderBrush="Black" BorderThickness="1" />
                    <Border x:Name="Border2" Grid.Column="0" CornerRadius="5,0,0,5"
                            Margin="1" Background="White" BorderBrush="Black"
                            BorderThickness="0,0,1,0" />
                    <Path x:Name="Arrow" Grid.Column="1"  Fill="Black"
                          HorizontalAlignment="Center" VerticalAlignment="Center"
                          Data="M 0 0 L 4 4 L 8 0 Z"/>
                  </Grid>
                  <ControlTemplate.Triggers>
                    <Trigger Property="ToggleButton.IsMouseOver" Value="true">
                      <Setter TargetName="Border" Property="Background" Value="DarkGray" />
                    </Trigger>
                    <Trigger Property="ToggleButton.IsChecked" Value="true">
                      <Setter TargetName="Border" Property="Background" Value="DarkGray" />
                      <Setter TargetName="Border" Property="CornerRadius" Value="5,5,0,0" />
                      <Setter TargetName="Border2" Property="CornerRadius" Value="5,0,0,0" />
                    </Trigger>
                  </ControlTemplate.Triggers>
                </ControlTemplate>
              </ToggleButton.Template>
            </ToggleButton>
            <ContentPresenter Name="ContentSite" IsHitTestVisible="False"
                            Content="{TemplateBinding SelectionBoxItem}"
                            ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                            ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                            Margin="3,3,40,3" />
            <TextBox x:Name="PART_EditableTextBox" Visibility="Hidden"
                     IsReadOnly="{TemplateBinding IsReadOnly}" Width="50" />
            <Popup Name="Popup" IsOpen="{TemplateBinding IsDropDownOpen}"
                   AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"
                   Placement="Relative" VerticalOffset="{TemplateBinding ActualHeight}"
                   HorizontalOffset="{TemplateBinding ActualWidth}">
             <Grid Name="DropDown" SnapsToDevicePixels="True"
                   MinWidth="{TemplateBinding ActualWidth}"
                   MaxHeight="{TemplateBinding MaxDropDownHeight}">
               <Border x:Name="DropDownBorder" Background="White" BorderThickness="1"
                       BorderBrush="Black"/>
                 <ListView ItemsSource="{TemplateBinding ItemsSource}"
                           SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent},
                           Path=SelectedItem}">
                   <ListView.View>
                     <GridView>
                       <GridViewColumn Header="Key" DisplayMemberBinding="{Binding Key}" />
                       <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
                     </GridView>
                   </ListView.View>
                 </ListView>
               </Grid>
             </Popup>
           </Grid>
         </ControlTemplate>
       </Setter.Value>
     </Setter>
   </Style>
 </Window.Resources>
<Grid>
  <ComboBox x:Name="cBox" Height="30" Width="200" ItemsSource="{Binding Path=People}"
            SelectedValue="Selected" DisplayMemberPath="Name" SelectedValuePath="Name"
            Style="{StaticResource ComboBoxTest2}" 
            SelectionChanged="Function_SelectionChanged" />
</Grid>

我在一些地方读到,Adorners可能是一个解决方案,因为他们将接收所有调整大小的事件,并可以动态地重新定位弹出窗口。另一种选择可能是使用像DevExpress这样的库,但我正在努力避免这种情况。顺便说一下,我的问题不是this one的副本,因为用于在XAML中放置弹出窗口的偏移量只在渲染时有效,而不是在调整大小/移动时使用。

EN

回答 1

Stack Overflow用户

发布于 2018-08-01 12:34:47

只需更改弹出窗口的位置选项,您就可以获得您想要显示的内容。

MainWindow.xaml

代码语言:javascript
运行
复制
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="300">
    <Window.Resources>
        <Style x:Key="ComboBoxTest2" TargetType="{x:Type ComboBox}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ComboBox">
                        <Grid>
                            <ToggleButton x:Name="TGButton" Grid.Column="2" Focusable="false"
                          IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,
                          RelativeSource={RelativeSource TemplatedParent}}"
                          Padding="0,0,50,0">
                                <ToggleButton.Template>
                                    <ControlTemplate>
                                        <Grid>
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="*" />
                                                <ColumnDefinition Width="30" />
                                            </Grid.ColumnDefinitions>
                                            <Border x:Name="Border" Grid.ColumnSpan="2" CornerRadius="5"
                         Background="LightGray" BorderBrush="Black" BorderThickness="1" />
                                            <Border x:Name="Border2" Grid.Column="0" CornerRadius="5,0,0,5"
                            Margin="1" Background="White" BorderBrush="Black"
                            BorderThickness="0,0,1,0" />
                                            <Path x:Name="Arrow" Grid.Column="1"  Fill="Black"
                          HorizontalAlignment="Center" VerticalAlignment="Center"
                          Data="M 0 0 L 4 4 L 8 0 Z"/>
                                        </Grid>
                                        <ControlTemplate.Triggers>
                                            <Trigger Property="ToggleButton.IsMouseOver" Value="true">
                                                <Setter TargetName="Border" Property="Background" Value="DarkGray" />
                                            </Trigger>
                                            <Trigger Property="ToggleButton.IsChecked" Value="true">
                                                <Setter TargetName="Border" Property="Background" Value="DarkGray" />
                                                <Setter TargetName="Border" Property="CornerRadius" Value="5,5,0,0" />
                                                <Setter TargetName="Border2" Property="CornerRadius" Value="5,0,0,0" />
                                            </Trigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </ToggleButton.Template>
                            </ToggleButton>
                            <ContentPresenter Name="ContentSite" IsHitTestVisible="False"
                            Content="{TemplateBinding SelectionBoxItem}"
                            ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
                            ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
                            Margin="3,3,40,3" />
                            <TextBox x:Name="PART_EditableTextBox" Visibility="Hidden"
                     IsReadOnly="{TemplateBinding IsReadOnly}" Width="50" />
                            <Popup Name="Popup" IsOpen="{TemplateBinding IsDropDownOpen}"
                   AllowsTransparency="True" Focusable="False" PopupAnimation="Slide"
                   Placement="Bottom">
                                <Grid Name="DropDown" SnapsToDevicePixels="True"
                   MinWidth="{TemplateBinding ActualWidth}"
                   MaxHeight="{TemplateBinding MaxDropDownHeight}">
                                    <Border x:Name="DropDownBorder" Background="White" BorderThickness="1"
                       BorderBrush="Black"/>
                                    <ListView ItemsSource="{TemplateBinding ItemsSource}"
                           SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent},
                           Path=SelectedItem}">
                                        <ListView.View>
                                            <GridView>
                                                <GridViewColumn Header="Key" DisplayMemberBinding="{Binding Key}" Width="80" />
                                                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="250"/>
                                            </GridView>
                                        </ListView.View>
                                    </ListView>
                                </Grid>
                            </Popup>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <ComboBox x:Name="cBox" Height="30" Width="200" ItemsSource="{Binding}"
            SelectedValue="Selected" DisplayMemberPath="Name" SelectedValuePath="Name"
            Style="{StaticResource ComboBoxTest2}" 
            SelectionChanged="Function_SelectionChanged" />
    </Grid>
</Window>

MainWindow.xaml.cs

代码语言:javascript
运行
复制
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = Enumerable.Range(1, 100).Select(x => new { Key = x, Name = $"Person {x} with really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really really long name" }).ToList();
        }

        private void Function_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // do whatever you want
        }
    }
}

输出:

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

https://stackoverflow.com/questions/51625331

复制
相关文章

相似问题

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