【发布时间】:2018-08-01 04:25:58
【问题描述】:
我正在尝试构建一个显示 ListView 的自定义 ComboBox。这是我要实现的目标的屏幕截图:
我的大部分代码都基于this very helpful blog,它讨论了如何在 ComboBox 中嵌入 DataGrid(或在我的情况下为 GridView)。从功能的角度来看,一切正常。但是,我似乎无法找到修复下拉菜单的方法。理想情况下,无论窗口大小或窗口位置如何,我都希望它始终如上所示。目前,弹出窗口尝试右对齐,除非窗口靠近屏幕的左边缘,此时弹出窗口向内迁移。如下面的 XAML 所示,问题在于 ListView 位于 Popup 内,而 Popup 并没有真正绑定到普通窗口,因此我们无法直接控制它们的位置。
<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>
我在一些地方读到 Adorner 可能是一种解决方案,因为它们会接收所有调整大小事件并可以动态重新定位弹出窗口。另一种选择可能是使用像 DevExpress 这样的库,但我试图避免这种情况。顺便说一句,我的问题不是 this one 的重复,因为用于在 XAML 中放置 Popup 的偏移量仅在渲染时得到尊重,而不是在调整大小/移动期间。
【问题讨论】: