我注意到,在一个附加了一些项目源的组合框中,当没有选择项目时,它倾向于滚动到项目的中间,而不是从顶部开始(第一个项目(,当选择一个项目时,有时它会滚动到所选项目。
所以当没有选择项目时,我想滚动到第一个项目。为此,我尝试了以下修复方法。
代码
private void ComboBoxKeyboardSelectionBehavior_DropDownOpened(object sender, object e)
{
var comboBox = (ComboBox) sender;
if(comboBox.SelectedIndex == -1)
{
//var scrollviewer = comboBox.GetScrollViewer();
//scrollviewer.ChangeView(0, 0, null);
//var allItems = comboBox.Items.ToList();
//var cccc = comboBox.Items.Count;
//var firstItem = allItems.First();
var ci = comboBox.ContainerFromIndex(0) as ComboBoxItem;
if (ci != null)
{
ci.StartBringIntoView();
}
}
else
{
var ci = comboBox.ContainerFromIndex(comboBox.SelectedIndex) as ComboBoxItem;
if (ci != null)
{
ci.StartBringIntoView();
}
}
}
WinRTXamlToolkit。控件。扩展让我可以选择获取滚动查看器,然后尝试ChangeView方法,但这不起作用。我成功地从列表中获得了第一个项目,并使用了ContainerFromItem方法,但它返回了null。因此,我还尝试了ContainerFromIndex方法,并将索引提供为0,因为这应该是第一项,但也不起作用。
在所选项(else语句(的情况下,它在ContainerFromIndex(comboBox.SelectedIndex)
中运行良好,但只是为了测试当我使用ContainerFromItem时,它返回了null。
仅供参考,此事件是组合框样式的附加行为,但这并不重要,因为行为器在所选项目场景中完美工作。
如果您想在没有选定项目的情况下滚动到第一个项目,则需要更改ComboBox
的DropDown
而不是ComboBox
的ScrollViewer
的行为。
ComboBox
的DropDown
实际上是Popup
,显示Popup
的位置在后面的代码中定义,我们无法访问它。一种解决方法是找到Popup
,并在打开时重新定位它,但使用这种方法,我们需要在每次打开时计算VerticalOffset
的属性,VerticalOffset
的值不同的情况有很多。
因此,我们建议您自定义一个控件,该控件的行为类似于ComboBox
,并且在未选择任何项目时定位到第一个项目。例如:
创建UserControl
:
<Button x:Name="rootButton" BorderBrush="Gray" BorderThickness="2" Click="Button_Click" MinWidth="80" Background="Transparent" Padding="0">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="{Binding ElementName=rootButton, Path=ActualWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="32" />
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind selectedItem, Mode=OneWay}" Grid.Column="0" VerticalAlignment="Center" FontSize="15" HorizontalAlignment="Center" />
<FontIcon Grid.Column="1" FontSize="12" FontFamily="Segoe MDL2 Assets" Glyph="" HorizontalAlignment="Right"
Margin="0,10,10,10" VerticalAlignment="Center" />
</Grid>
<FlyoutBase.AttachedFlyout>
<MenuFlyout Placement="Bottom" x:Name="menuFlyout">
<MenuFlyoutItem Text="Item 1" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 2" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 3" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 4" Click="MenuFlyoutItem_Click" />
<MenuFlyoutItem Text="Item 5" Click="MenuFlyoutItem_Click" />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
这个UserControl中的代码:
public sealed partial class CustomComboBox : UserControl, INotifyPropertyChanged
{
public CustomComboBox()
{
this.InitializeComponent();
selectedItem = "";
}
private string _selectedItem;
public string selectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("selectedItem"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void MenuFlyoutItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuFlyoutItem;
selectedItem = item.Text;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as Button);
}
}
您可以在其他页面中使用CustomComboBox
,如下所示:
<local:CustomComboBox VerticalAlignment="Center" HorizontalAlignment="Center" />
默认情况下,此CustomComboBox
将在其下显示其DropDown
列表
此外,您还可以考虑使用其他控件,如ListBox
来直接替换ComboBox
,以避免出现这种情况。
更新:
目前,ComboBox
控件没有提供相关的API来设置DropDown
在Style
中的起始位置,但我们有一个变通方法,可以在DropDown
中获取ScrollViewer
,然后调用ChangeView
方法来更改位置。例如:
- 定义从
ComboBox
类继承的自定义组合框以获得ScrollViewer
:
public class TestComboBox : ComboBox
{
public ScrollViewer InternalScrollViewer;
protected override void OnApplyTemplate()
{
InternalScrollViewer = GetTemplateChild("ScrollViewer") as ScrollViewer;
base.OnApplyTemplate();
}
}
- 在
ComboBoxKeyboardSelectionBehavior_DropDownOpened
事件处理程序中使用Task.Delay()
初始化项目后,调用ChangeView
方法更改位置:
await Task.Delay(50);
comboBox.InternalScrollViewer.ChangeView(0, 0, 1);
请注意,在XAML中使用TestComboBox
而不是ComboBox
。