WP7中的可滚动文本框(ala Skype和Facebook)

时间:2012-05-25 17:05:56

标签: c# silverlight windows-phone-7 textbox scroll

基本上,我正在开发一个笔记记录应用程序,用户可以根据需要打字(有点像Scrollable TextBox in WP7)。我把TextBox放在ScrollViewer中,一切都很好;我在TextBox获得焦点时禁用ScrollViewer,因此在用户输入时它会自动滚动。

我的问题是,我希望用户能够在编辑音符时滚动,就像他能够在阅读音符时滚动一样。我认为唯一的方法是按住直到超大插入符号出现,然后移动它,但我发现,事实上,第三方应用程序支持这种类型的滚动。

我想要实现的是手机上的Word / OneNote,用户可以在编辑文档时轻松滚动(here's a video演示文档)。在Skype和Facebook应用程序中也可以看到相同的效果,在编写消息时,您可以滚动它以查看更多消息。

我想知道这是一个自定义控件,还是布局是以特定方式设计的,因为ScrollViewer中的TextBox根本不起作用。

我很感激任何帮助。提前谢谢。

2 个答案:

答案 0 :(得分:3)

根据Ku6opr给出的答案,我调整了代码,以便在我的情况下运行。现在,TextBox具有常规行为,但是可滚动,并且RootFrame不会自动上升。

XAML:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <ScrollViewer x:Name="InputScrollViewer">
        <TextBox x:Name="MessageText" TextWrapping="Wrap" Text="" AcceptsReturn="True" TextChanged="inputText_TextChanged" GotFocus="MessageText_GotFocus" Padding="0,0,0,400" Tap="MessageText_Tap" />
    </ScrollViewer>
</Grid>

C#:

public partial class MainPage : PhoneApplicationPage
{
    double InputHeight = 0.0;

    // Constructor
    public MainPage()
    {
        InitializeComponent();
    }

    private void MessageText_GotFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        (App.Current as App).RootFrame.RenderTransform = new CompositeTransform();
    }

    private void inputText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        Dispatcher.BeginInvoke(() =>
        {
            double CurrentInputHeight = MessageText.ActualHeight;

            if (CurrentInputHeight > InputHeight)
            {
                InputScrollViewer.ScrollToVerticalOffset(InputScrollViewer.VerticalOffset + CurrentInputHeight - InputHeight);
            }

            InputHeight = CurrentInputHeight;
        });
    }

    public void MessageText_Tap(object sender, GestureEventArgs e)
    {
        InputScrollViewer.ScrollToVerticalOffset(e.GetPosition(MessageText).Y - 80);
    }
}

Tap事件处理程序检测点击的垂直位置,并滚动ScrollViewer,以便在TextBox获得焦点时插入符号。

答案 1 :(得分:1)

也许这不是最佳解决方案,但它的工作原理:

XAML:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <ScrollViewer x:Name="InputScrollViewer" Margin="12,0" Height="800" VerticalAlignment="Top">
        <StackPanel Orientation="Vertical" Margin="0,12">
            <TextBlock TextWrapping="Wrap" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed in ligula augue. Morbi facilisis varius enim in congue. Nam vehicula imperdiet ipsum in ullamcorper. Integer quis augue in dui tincidunt elementum. Nulla in mi mauris, eu laoreet leo. Sed vehicula quam nec leo imperdiet a rutrum felis viverra." Style="{StaticResource PhoneTextNormalStyle}" Margin="12,12,12,0"/>
            <TextBlock TextWrapping="Wrap" Text="Morbi molestie facilisis eleifend. Cras volutpat, lectus nec tincidunt accumsan, mi purus faucibus purus, vitae semper mauris lacus id mauris. Fusce eget massa ut magna lacinia gravida. Ut id velit purus. Nullam eu mi ac justo imperdiet pretium. Curabitur vehicula congue purus vitae sollicitudin." Style="{StaticResource PhoneTextNormalStyle}" Margin="12,12,12,0"/>
            <TextBlock TextWrapping="Wrap" Text="Aenean eget dui a urna commodo faucibus sit amet nec eros. Nam tempus facilisis urna, ut varius justo euismod sit amet. Vivamus ultrices volutpat tortor in viverra. Vestibulum laoreet odio at tellus consectetur ut convallis quam semper. Duis in iaculis lectus. Aliquam erat volutpat. Nulla facilisi. Quisque vitae metus lorem. Fusce et erat nisl, sit amet gravida libero. Cras elementum eros vitae tellus sollicitudin accumsan. Pellentesque egestas luctus bibendum. Duis eros ipsum, mollis ut laoreet eu, consectetur id lectus. Maecenas viverra risus urna." Style="{StaticResource PhoneTextNormalStyle}" Margin="12,12,12,0"/>
            <TextBox x:Name="MessageText" TextWrapping="Wrap" Text="" AcceptsReturn="True" TextChanged="inputText_TextChanged" GotFocus="MessageText_GotFocus" LostFocus="MessageText_LostFocus"/>
        </StackPanel>
    </ScrollViewer>
</Grid>

代码隐藏:

public partial class MainPage : PhoneApplicationPage
{
    bool IsInputFocused = false;
    double InputHeight = 0.0;
    double KeyboardHeight = 338;
    double KeyboardClipboardHeight = 72;
    double RootHeight = 800;

    public MainPage()
    {
        InitializeComponent();

        DeviceStatus.KeyboardDeployedChanged += new EventHandler(DeviceStatus_KeyboardDeployedChanged);
    }

    void DeviceStatus_KeyboardDeployedChanged(object sender, EventArgs e)
    {
        if (IsInputFocused)
        {
            UpdateKeyboard();
        }
    }

    private void inputText_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
    {
        Dispatcher.BeginInvoke(() =>
        {
            double CurrentInputHeight = MessageText.ActualHeight;

            if (CurrentInputHeight > InputHeight)
            {
                InputScrollViewer.ScrollToVerticalOffset(InputScrollViewer.VerticalOffset + CurrentInputHeight - InputHeight);
            }

            InputHeight = CurrentInputHeight;
        });
    }

    private void UpdateKeyboard()
    {
        (App.Current as App).RootFrame.RenderTransform = new CompositeTransform();

        if (!DeviceStatus.IsKeyboardDeployed)
        {
            InputScrollViewer.Height = RootHeight - (KeyboardHeight + GetClipboardHeight());
        }
        else
        {
            InputScrollViewer.Height = RootHeight;
        }
    }

    private double GetClipboardHeight()
    {
        return (Clipboard.ContainsText()) ? KeyboardClipboardHeight : 0;
    }

    private void MessageText_GotFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        IsInputFocused = true;

        (App.Current as App).RootFrame.RenderTransform = new CompositeTransform();

        UpdateKeyboard();

        Dispatcher.BeginInvoke(() =>
        {
            InputScrollViewer.ScrollToVerticalOffset(InputScrollViewer.VerticalOffset + 338 + GetClipboardHeight());
        });
    }

    private void MessageText_LostFocus(object sender, System.Windows.RoutedEventArgs e)
    {
        IsInputFocused = false;

        InputScrollViewer.Height = RootHeight;
    }
}

首先,当Frame获得焦点时,此代码会禁用TextBox(向上移动)的转换。此外,当键盘在屏幕上时,此代码执行新的自由屏幕高度管理。