Windows 8 中,TextBox 獲得焦點時會自動彈出輸入面板 (虛擬鍵盤)。系統會嘗試將頁面上推以確保輸入框可見,但 FlipView 等容器內的 TextBox 往往失效。本文提供基於 InputPane 事件的完整自訂解決方案。
using System;
using System.Collections.Generic;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.Foundation;
using Windows.UI.Xaml.Media.Animation;
namespace HuiZhang212.Keyboard
{
public delegate void InputPaneShowingHandler(object sender, InputPaneVisibilityEventArgs e);
public delegate void InputPaneHidingHandler(InputPane input, InputPaneVisibilityEventArgs e);
public class InputPaneHelper
{
private Dictionary handlerMap;
private UIElement lastFocusedElement = null;
private InputPaneHidingHandler hidingHandlerDelegate = null;
public InputPaneHelper()
{
handlerMap = new Dictionary();
}
public void SubscribeToKeyboard(bool subscribe)
{
InputPane input = InputPane.GetForCurrentView();
if (subscribe)
{
input.Showing += ShowingHandler;
input.Hiding += HidingHandler;
}
else
{
input.Showing -= ShowingHandler;
input.Hiding -= HidingHandler;
}
}
public void AddShowingHandler(UIElement element, InputPaneShowingHandler handler)
{
if (handlerMap.ContainsKey(element))
throw new Exception("A handler is already registered!");
handlerMap.Add(element, handler);
element.GotFocus += GotFocusHandler;
element.LostFocus += LostFocusHandler;
}
private void GotFocusHandler(object sender, RoutedEventArgs e)
{
lastFocusedElement = (UIElement)sender;
}
private void LostFocusHandler(object sender, RoutedEventArgs e)
{
if (lastFocusedElement == (UIElement)sender)
lastFocusedElement = null;
}
private void ShowingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
{
if (lastFocusedElement != null && handlerMap.Count > 0)
{
handlerMap[lastFocusedElement](lastFocusedElement, e);
}
lastFocusedElement = null;
}
private void HidingHandler(InputPane sender, InputPaneVisibilityEventArgs e)
{
if (hidingHandlerDelegate != null)
hidingHandlerDelegate(sender, e);
lastFocusedElement = null;
}
public void SetHidingHandler(InputPaneHidingHandler handler)
{
hidingHandlerDelegate = handler;
}
public void RemoveShowingHandler(UIElement element)
{
handlerMap.Remove(element);
element.GotFocus -= GotFocusHandler;
element.LostFocus -= LostFocusHandler;
}
}
}
<Page.Resources>
<Storyboard x:Name="MoveMiddleOnShowing">
<DoubleAnimationUsingKeyFrames Duration="0:0:0.733"
Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
<SplineDoubleKeyFrame x:Name="ShowingMoveSpline" KeyTime="0:0:0.733" KeySpline="0.10,0.90,0.20,1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Name="MoveMiddleOnHiding">
<DoubleAnimationUsingKeyFrames Duration="0:0:0.367"
Storyboard.TargetName="MiddleTranslate" Storyboard.TargetProperty="Y">
<SplineDoubleKeyFrame KeyTime="0:0:0.367" KeySpline="0.10,0.90,0.20,1" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Grid x:Name="LayoutRoot">
<Grid.RenderTransform>
<TranslateTransform x:Name="MiddleTranslate" />
</Grid.RenderTransform>
<FlipView Margin="100">
<FlipViewItem Background="Yellow">
<TextBox Name="textbox0" Text="自訂監聽鍵盤上推事件" VerticalAlignment="Bottom" Width="300"/>
</FlipViewItem>
<FlipViewItem Background="Blue">
<TextBox Name="textbox1" Text="系統處理鍵盤上推事件" VerticalAlignment="Bottom" Width="300"/>
</FlipViewItem>
<FlipViewItem Background="Green">
<TextBox Name="textbox2" Text="自訂監聽鍵盤上推事件" VerticalAlignment="Top" Width="300"/>
</FlipViewItem>
</FlipView>
</Grid>
private InputPaneHelper _inputPaneHelper;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
_inputPaneHelper = new InputPaneHelper();
_inputPaneHelper.SubscribeToKeyboard(true);
// 為需要自訂處理的 TextBox 註冊處理器
_inputPaneHelper.AddShowingHandler(textbox0, OnInputPaneShowing);
_inputPaneHelper.AddShowingHandler(textbox2, OnInputPaneShowing);
_inputPaneHelper.SetHidingHandler(OnInputPaneHiding);
}
private void OnInputPaneShowing(object sender, InputPaneVisibilityEventArgs e)
{
// 計算需要上推的距離:鍵盤高度 - 元素底部到頁面底部的距離
double offset = e.OccludedRect.Height - (/* 元素底部座標計算 */);
ShowingMoveSpline.Value = -offset; // 負值向上移動
MoveMiddleOnShowing.Begin();
}
private void OnInputPaneHiding(InputPane sender, InputPaneVisibilityEventArgs e)
{
MoveMiddleOnHiding.Begin();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
_inputPaneHelper.SubscribeToKeyboard(false);
_inputPaneHelper.RemoveShowingHandler(textbox0);
_inputPaneHelper.RemoveShowingHandler(textbox2);
}
InputPane.GetForCurrentView():取得當前視圖的輸入面板實例InputPaneVisibilityEventArgs.OccludedRect:鍵盤遮擋區域 (高度即為鍵盤高度)TranslateTransform:整頁位移不影響內部佈局SplineDoubleKeyFrame:緩動動畫曲線,提升使用者體驗Microsoft 官方範例:Responding to the appearance of the on-screen keyboard sample
查看本欄目