Windows 8/Metro UI 中文本框下的自动完成框文本框、自动完成、Windows、Metro

2023-09-06 06:20:32 作者:算命的说的很准。

我想使用 C#/XAML 在 Windows 8 UI/Metro UI 应用程序中的文本框上实现自动完成.

I want to implement auto-complete on a textbox in a Windows 8 UI / Metro UI app using C#/XAML.

目前,当软/触摸键盘显示时,它会遮挡自动完成框.但是,在文本框焦点上,Windows 8 会自动向上滚动整个视图并确保文本框处于焦点中.

At the moment, when the soft / touch keyboard shows, it obscures the auto-complete box. However, on the text box focus, Windows 8 automatically scrolls the entire view up and ensures the text box is in focus.

实际上,我想要的只是将视图向上滚动一点(实际上,按自动完成框的高度).

In reality, all I want is the view to scroll up a little more (in fact, by the height of the auto-complete box).

我意识到我可以拦截 InputPane.GetForCurrentView() 的 Showing 事件

I realise I can intercept the Showing event of InputPane.GetForCurrentView()

我可以在 Showing 事件中将 InputPaneVisibilityEventArgs.EnsuredFocusedElementInView 设置为 true(这样 Windows 不会尝试做任何事情)....但是,我如何调用与 Windows 8 相同的滚动功能,但请询问它再滚动一点!?

I can set InputPaneVisibilityEventArgs.EnsuredFocusedElementInView to true inside the Showing event fine (so Windows won't try to do anything).... however, how can I invoke the same scrolling functionality that Windows 8 would do, but ask it to scroll a little more!?

这是主页的代码:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,200,0,0">
        <TextBlock HorizontalAlignment="Center" FontSize="60">App 1</TextBlock>
        <TextBlock HorizontalAlignment="Center">Enter text below</TextBlock>
        <TextBox HorizontalAlignment="Center" Margin="-10,0,10,0" Width="400" Height="30"/>
        <ListBox HorizontalAlignment="Center" Width="400">
            <ListBoxItem>Auto complete item 1</ListBoxItem>
            <ListBoxItem>Auto complete item 2</ListBoxItem>
            <ListBoxItem>Auto complete item 3</ListBoxItem>
            <ListBoxItem>Auto complete item 4</ListBoxItem>
            <ListBoxItem>Auto complete item 5</ListBoxItem>
        </ListBox>
    </StackPanel>
</Grid>

如果您以最低分辨率启动模拟器,请用手触摸"文本框,这将调出软键盘.在实际应用中,当用户输入文本时,自动完成列表将与项目一起出现.

If you start up the simulator with the lowest resolution, use the hand to "touch" the textbox, this will bring up the soft keyboard. In the real app, the auto complete list will appear with items as the user enters text.

简而言之,我怎样才能将屏幕向上移动一点,以便用户可以看到整个自动完成列表?

So in a nutshell, how can I move the screen up a bit more so the user can see the entire autocomplete list?

请记住,在实际应用中,情况会更糟,因为用户甚至可能没有注意到自动完成列表出现在键盘下方".

Bear in mind, in the real app, it'll be worse, as the user may not even notice the autocomplete list appearing "underneath" the keyboard.

非常感谢您的建议,非常感谢!

I really would appreciate some advice, many thanks!

推荐答案

好的,这就是我将如何解决这个问题,因为我似乎找不到任何方法来根据键盘的外观来控制应用程序的滚动.我将创建一个用户控件,作为自动完成文本框的基础.

Ok, here is how I would tackle this since I cannot seem to find any way to control the scrolling of the app based on the appearance of the keyboard. I would create a user control that would form the basis for the auto-complete textbox.

<UserControl
x:Class="App6.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App6"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">

<Grid>
    <TextBox x:Name="textBox" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top"  GotFocus="textBox_GotFocus" LostFocus="textBox_LostFocus" />
    <ListBox x:Name="listBox" Height="150"  Margin="0,-150,0,0" VerticalAlignment="Top" Visibility="Collapsed"/>
</Grid>

这是一个非常基本的实现,因此您必须进行调整以满足您的需求.

This is an incredibly basic implementation, so you will have to tweak to meet your needs.

然后,我会在用户控件中添加以下代码隐藏

Then, I would add the following code-behind to the user control

public sealed partial class MyUserControl1 : UserControl
{
    // Rect occludedRect;
    bool hasFocus = false;

    public MyUserControl1()
    {
        this.InitializeComponent();
        InputPane.GetForCurrentView().Showing += MyUserControl1_Showing;
    }

    void MyUserControl1_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
    {
        if (hasFocus)
        {
            var occludedRect = args.OccludedRect;

            var element = textBox.TransformToVisual(null);
            var point = element.TransformPoint(new Point(0, 0));

            if (occludedRect.Top < point.Y + textBox.ActualHeight + listBox.ActualHeight)
            {
                listBox.Margin = new Thickness(0, -listBox.ActualHeight, 0, 0);         // Draw above     
            }
            else
            {
                listBox.Margin = new Thickness(0, textBox.ActualHeight, 0, 0); // draw below
            }
        }          
    }

    private void textBox_GotFocus(object sender, RoutedEventArgs e)
    {
        listBox.Visibility = Windows.UI.Xaml.Visibility.Visible;
        hasFocus = true;
    }

    private void textBox_LostFocus(object sender, RoutedEventArgs e)
    {
        listBox.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
        hasFocus = false;
    }        
}

接下来的步骤是公开属性以传递要绑定到 ListBox 的数据.硬核将是 ListBoxItem 模板等等,具体取决于您希望它的可重用程度.

Next steps would be to expose properties to pass data to be bound to the ListBox. Hard core would be ListBoxItem templating and more, depending on how reusable you wanted it to be.