2

How I can get behavior of form in windows Phone like Contacts >> New contacts >> Name. In this page it have many textboxes in scrollviewer. When user taps on any textbox and its get focus then the page scrolls up and header remains constant and SIP keyboard shown. This is a my example but not it works

https://app.box.com/s/lxxcmxp8ckuottrweg52

Why? thank you

John Brush
  • 177
  • 11

3 Answers3

1

I have modified the above code that works fine for as below.

    public double OldHeight;
    private TranslateTransform _translateTransform;

    #region TranslateY dependency property
    public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register(
        "TranslateYProperty", typeof(double), typeof(Chat), new PropertyMetadata(default(double), PropertyChangedCallback));

    private static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var chat = o as Chat;
   #if DEBUG
        Debug.WriteLine("New value:" + e.NewValue);
        Debug.WriteLine("Old value:" + e.OldValue);
   #endif
        if (chat != null)
        {
            chat.UpdateTopMargin((double)e.NewValue);
        }
    }

    public double TranslateY
    {
        get { return (double)GetValue(TranslateYProperty); }
        set { SetValue(TranslateYProperty, value); }
    }
    #endregion

    private void ChatPage_OnLoaded(object sender, RoutedEventArgs e)
    {
        var transform = ((Application.Current).RootVisual).RenderTransform as TransformGroup;
        if (transform != null)
        {
            _translateTransform = transform.Children.OfType<TranslateTransform>().FirstOrDefault();
            if (_translateTransform != null)
            {
                var binding = new Binding("Y")
                {
                    Source = _translateTransform
                };
                BindingOperations.SetBinding(this, TranslateYProperty, binding);
            }
        }
    }

    private void UpdateTopMargin(double translateY)
    {
        LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
    }

Thanks

Vinoth Kumar J
  • 167
  • 1
  • 10
  • Check the above modified code which works great for me – Vinoth Kumar J Apr 15 '14 at 12:16
  • Does it go into the class? could you post the whole class + XAML on pastebin or something? it would be of great help. there's literally no solution to this on the internet – Jay Kannan Apr 15 '14 at 12:17
  • Thank you, or should I say நன்றி :) I'll check it out and mark it as an answer. if you put this up as an answer in my original post, I'll mark it as an answer and that should help with your stackoverflow profile. – Jay Kannan Apr 15 '14 at 12:38
0

First, name your scroll viewer ScrollViewer. After that add the GotFocus and LostFocus event handlers for each text box control on the page and write the following code inside:

private void txt_LostFocus(object sender, RoutedEventArgs routedEventArgs)
{
    ScrollViewer.Height = _oldHeight;
}

void txt_GotFocus(object sender, RoutedEventArgs e)
{
    var transform = ((Application.Current).RootVisual).RenderTransform as TransformGroup;
    if (transform != null)
    {
        _translateTransform = transform.Children.OfType<TranslateTransform>().FirstOrDefault();
        if (_translateTransform != null)
        {
            var binding = new Binding("Y")
            {
                Source = _translateTransform
            };
            BindingOperations.SetBinding(this, TranslateYProperty, binding);
        }
    }
    var clipboardVisible = false;
    try
    {
        clipboardVisible = Clipboard.ContainsText();
    }
    // ReSharper disable once EmptyGeneralCatchClause
    catch
    {
    }
    ScrollViewer.Height = _oldHeight - (clipboardVisible ? 407 : 338);
}

You will need to add the following dependency property to the page:

#region TranslateY dependency property
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register(
    "TranslateYProperty", typeof(double), typeof(OrderContactPage), new PropertyMetadata(default(double), PropertyChangedCallback));

private static void PropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    ((OrderContactPage)o)._translateTransform.Y = 0;
}

public double TranslateY
{
    get { return (double)GetValue(TranslateYProperty); }
    set { SetValue(TranslateYProperty, value); }
} 
#endregion

And also helper fields:

private double _oldHeight;
private TranslateTransform _translateTransform;

You also need to handle some events for your scroll viewer, add this to the page's constructor:

ScrollViewer.Loaded += ScrollViewerOnLoaded;
ScrollViewer.SizeChanged += ScrollViewer_OnSizeChanged;

Implement those event handlers: private void ScrollViewerOnLoaded(object sender, RoutedEventArgs routedEventArgs) { ScrollViewer.Loaded -= ScrollViewerOnLoaded; _oldHeight = ScrollViewer.ActualHeight; }

private async void ScrollViewer_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
    await ScrollToFocusedElement();
}

private async Task ScrollToFocusedElement()
{
    await Task.Yield();
    var focusedElement = FocusManager.GetFocusedElement() as PhoneTextBox;
    if (focusedElement != null)
    {
        // http://stackoverflow.com/questions/1225318/how-can-i-make-the-silverlight-scrollviewer-scroll-to-show-a-child-control-with
        var focusedVisualTransform = focusedElement.TransformToVisual(ScrollViewer);
        var rectangle =
            focusedVisualTransform.TransformBounds(
                new Rect(new Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize));
        var offset = ScrollViewer.VerticalOffset + (rectangle.Bottom - ScrollViewer.ViewportHeight);
        ScrollViewer.ScrollToVerticalOffset(offset);
    }
}

Wow, there is a lot of code there. I am working on creating something reusable, but I am not there yet. Once I do it, I will publish it on NuGet.

Note that this only works in Portrait mode and will not work perfectly if you have the auto suggestion bar open. I didn't need to handle that in my app so I skipped it :)

Enjoy.

Toni Petrina
  • 7,014
  • 1
  • 25
  • 34
  • hello, thank you for response but in my page not it works correct. a have problem with HEIGHT of ScrollViewer and with focus. i have updated my project with your code, can you give us a look. Thank you – John Brush Feb 27 '14 at 11:32
0

you can try this sample sample project

<Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
        <RowDefinition Height="60" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Grid Grid.Row="0"
          Background="#002080">
        <TextBlock  Text="PAGE HEADER" HorizontalAlignment="Center" VerticalAlignment="Center" />
    </Grid>

    <Grid Grid.Row="1" />


    <TextBox Grid.Row="2"
             Text=""
             x:Name="messageBox"
             Background="White" LostFocus="MessageBox_OnLostFocus" />
  </Grid>


    public MainPage()
    {
        InitializeComponent();
        this.Loaded += MainPage_Loaded;
    }

private static double _newValue;

    private static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register("TranslateY", typeof(double), typeof(MainPage), new PropertyMetadata(0d, OnRenderXPropertyChanged));

    private double TranslateY
    {
        get { return (double)GetValue(TranslateYProperty); }
    }

    private static void OnRenderXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if ((double)e.NewValue <= _newValue)
            ((MainPage)d).UpdateTopMargin((double)e.NewValue);
        _newValue = (double)e.NewValue;
    }

    private void BindToKeyboardFocus()
    {
        var frame = Application.Current.RootVisual as PhoneApplicationFrame;
        if (frame == null) return;
        var group = frame.RenderTransform as TransformGroup;
        if (@group == null) return;
        var translate = @group.Children[0] as TranslateTransform;
        var translateYBinding = new Binding("Y") { Source = translate };
        SetBinding(TranslateYProperty, translateYBinding);
    }

    private void UpdateTopMargin(double translateY)
    {
        double prevTopMargin = LayoutRoot.Margin.Top;
        LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
    }
reza.cse08
  • 5,938
  • 48
  • 39