2
votes

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

3
I know what you mean and I can provide the source code later on. You need to detect that you are editing text and then you need to resize and shift your scroll viewer. It's tedious actually. - Toni Petrina
do you have a example? - John Brush
Not right now, when I get home. - Toni Petrina
perfect, if you send it to me thanks - John Brush

3 Answers

1
votes

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

0
votes

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.

0
votes

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);
    }