2014-07-22 47 views
2

很久以前,我問了一個類似的問題:Scrollable TextBox in WP7 (ala Skype and Facebook) - 我想在Windows Phone 8.1上有相同的行爲。在Windows Phone 8.1(WinRT)中的完全滾動文本框

我有一個TextBox,用戶可以在其中鍵入一個音符,當鍵盤出現時,它將TextBox向上移動,以便它始終處於視圖中。問題是如果紙幣太大,用戶無法輕鬆地滾動整個紙幣。

而不是移動文本框,我想調整頁面的大小,以便其他元素(如應用程序標題)也始終可見。顯然,即使筆記很大,文本框也應該很容易滾動。

這是我的XAML:

<Page 
    x:Class="ScrollableTextBox.MainPage" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:ScrollableTextBox" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

<!--LayoutRoot--> 
<Grid x:Name="LayoutRoot" 
     Margin="21,-6.5,19,0"> 

    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="*"/> 
    </Grid.RowDefinitions> 

    <!--Title--> 
    <TextBlock Margin="0,19,0,24" 
       Style="{ThemeResource TitleTextBlockStyle}" 
       Text="APP TITLE" /> 

    <!--ContentPanel--> 
    <Grid Grid.Row="1"> 

     <ScrollViewer x:Name="NoteContentScrollViewer"> 

      <TextBox x:Name="NoteContentTextBox" 
        AcceptsReturn="True" 
        ScrollViewer.VerticalScrollMode="Disabled" 
        VerticalAlignment="Stretch" 
        GotFocus="NoteContentTextBox_GotFocus" /> 

     </ScrollViewer> 

    </Grid> 

</Grid> 

這是後臺代碼:

using Windows.UI.ViewManagement; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls; 
using Windows.UI.Xaml.Navigation; 

namespace ScrollableTextBox 
{ 
    public sealed partial class MainPage : Page 
    { 
     // Handle InputPane manually so the UI doesn't scroll when the keyboard appears 
     InputPane inputPane = InputPane.GetForCurrentView(); 

     public MainPage() 
     { 
      this.InitializeComponent(); 
      this.NavigationCacheMode = NavigationCacheMode.Required; 
     } 

     private void NoteContentTextBox_GotFocus(object sender, RoutedEventArgs e) 
     { 
      // Subscribe InputPane events to handle UI scrolling 
      inputPane.Showing += this.InputPaneShowing; 
      inputPane.Hiding += this.InputPaneHiding; 
     } 

     private void InputPaneShowing(InputPane sender, InputPaneVisibilityEventArgs e) 
     { 
      // Set EnsuredFocusedElementInView to true so the UI doesn't scroll 
      e.EnsuredFocusedElementInView = true; 

      // Set new margins to LayoutRoot (to compensate keyboard) 
      LayoutRoot.Margin = new Thickness(21, -6.5, 19, e.OccludedRect.Height); 

      // Unsubscribe InputPane Showing event 
      inputPane.Showing -= this.InputPaneShowing; 
     } 

     private void InputPaneHiding(InputPane sender, InputPaneVisibilityEventArgs e) 
     { 
      // Set EnsuredFocusedElementInView to false so the UI scrolls 
      e.EnsuredFocusedElementInView = false; 

      // Reset LayoutRoot margins 
      LayoutRoot.Margin = new Thickness(21, -6.5, 19, 0); 

      // Unsubscribe InputPane Hiding event to handle UI scrolling 
      inputPane.Hiding -= this.InputPaneHiding; 
     } 
    } 
} 

這精美的作品,因爲當鍵盤出現時,該頁面被調整用戶可以在編輯筆記時輕鬆滾動,而其他UI元素不會移出視圖。但是,有一種行爲會丟失:當用戶點擊TextBox時,它應該滾動到插入位置,但現在它不會滾動(正如我們所期望的那樣)。

在Windows Phone 7上,我使用ScrollViewer.ScrollToVerticalOffset()來實現這一目標,但它在WinRT上無法使用。我們應該使用ScrollViewer.ChangeView(),但我無法使它工作。

所以,簡而言之,我希望TextBox在用戶點擊時滾動到插入位置,這樣他就可以立即開始輸入,而不必手動滾動(或按Enter鍵進入位置)。有任何想法嗎?

回答

0

我能夠通過使用DispatcherTimer來解決問題,正如Bryan Stump所建議的那樣。下面是遺漏碼:

// DispatcherTimer to ChangeView() of NoteContentScrollViewer 
DispatcherTimer keyboardTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(50) }; 

裏面的MainPage():

// Subscribe keyboardTimer Tick event 
keyboardTimer.Tick += keyboardTimer_Tick; 

內InputPaneShowing():

// Start() keyboardTimer to scroll to caret 
keyboardTimer.Start(); 

最後,keyboardTimer Tick事件:

private void keyboardTimer_Tick(object sender, object e) 
{ 
    // Stop timer so it doesn't repeat 
    keyboardTimer.Stop(); 

    // Invoke ChangeView() on NoteContentScrollViewer, and use GetRectFromCharacterIndex to scroll to caret position 
    if (NoteContentTextBox.Text != "") 
     NoteContentScrollViewer.ChangeView(0, NoteContentTextBox.GetRectFromCharacterIndex(NoteContentTextBox.SelectionStart - 1, true).Y, null); 
} 

他們的關鍵是GetRe用於定位插入符號位置的TextBox的ctFromCharacterIndex方法。這始終確保插入符號在視圖中,至少在我的測試中。

1

滾動查看器和更改視圖不工作?我問了一個關於MSDN上的相關內容的帖子,我可以稍後鏈接(我在手機上)。 要解釋滾動查看器無法工作的原因,需要深入瞭解如何在UI中優先考慮垂直偏移等相關屬性。 任何動畫都將覆蓋代碼中設置的值,並且在嘗試設置新高度時輸入窗格打開。輸入窗格動畫完成後,必須調用更改視圖。嘗試設置一個調度器計時器,時間間隔爲半秒,並在tick事件處理程序中調用change view。這有效地等待UI動畫結束,因此您的新值將被正確設置。

您是否嘗試過使用textbox.select方法?可能會有內置的機制來集中選定的位置。

+0

真棒-setting一個DispatcherTimer調用ChangeView前()的作品,至少。我現在試圖獲取插入符的確切位置,所以我可以滾動到它。如果您有解決方案,請將其包含在您的答案中;否則,我會看看我是否可以自己發佈。 –

+0

你可以使用RichEditTextBox嗎?這可能有一個遊標位置的API,類似於Silverlight API。 http://social.msdn.microsoft.com/Forums/silverlight/en-US/b5c4bc69-94cc-4e86-bd72-38e718cd8d73/getting-coordinates-of-caret-position-from-a-textbox?forum=silverlightcontrols –

+0

我無法使用RichEditTextBox,但我發現了一個非常有用的TextBox方法:GetRectFromCharacterIndex。我接近一個工作解決方案,至少對於我一直在測試的內容。 –

0

XAML:

<TextBox 
    AcceptsReturn="True" 
    Name="textBox" 
    ScrollViewer.VerticalScrollBarVisibility="Auto" 
    ScrollViewer.VerticalScrollMode="Auto" 
    TextChanged="TextBox_TextChanged" 
/> 

C#:

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    var grid = (Grid)VisualTreeHelper.GetChild(textBox, 0); 
    for (var i = 0; i <= VisualTreeHelper.GetChildrenCount(grid) - 1; i++) 
    { 
     object obj = VisualTreeHelper.GetChild(grid, i); 
     if (!(obj is ScrollViewer)) continue; 
     ((ScrollViewer)obj).ChangeView(null, ((ScrollViewer)obj).ExtentHeight, null); 
     break; 
    } 
} 
相關問題