2017-06-13 141 views
1

我做了一個用戶控件,我把它叫做InputTextBox,用戶可以點擊控件後所編輯現有案文:用戶控件失去鍵盤焦點

<Grid> 
    <TextBox Name="box" 
      Text="{Binding RelativeSource={RelativeSource AncestorType=local:InputTextBlock}, Path=Text, Mode=TwoWay}" 
      Visibility="Hidden" 
      LostKeyboardFocus="box_LostKeyboardFocus" 
      KeyDown="box_KeyDown"/> 
    <Button Name="block" 
      Background="Transparent" 
      BorderThickness="0" 
      Click="block_Click"> 
     <Button.Content> 
      <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=local:InputTextBlock}, Path=Text}" /> 
     </Button.Content> 
    </Button> 
</Grid> 

當用戶單擊該按鈕下面callack是使用:

private void block_Click(object sender, RoutedEventArgs e) 
    { 
     StartEdit(); 
    } 

    public void StartEdit() 
    { 
     box.Visibility = Visibility.Visible; 
     block.Visibility = Visibility.Hidden; 

     box.CaretIndex = box.Text.Length; 

     Keyboard.Focus(box); 
    } 

在控件中處理了兩個更重要的事件。第一種是當控件失去鍵盤焦點:

private void box_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 
    { 
     box.Visibility = Visibility.Hidden; 
     block.Visibility = Visibility.Visible; 
    } 

,另一種是當用戶按下TAB或ENTER鍵:

private void box_KeyDown(object sender, KeyEventArgs e) 
    { 
     Key key = e.Key; 

     if (key == Key.Enter || key == Key.Tab) 
     { 
      RoutedEventArgs args = new RoutedEventArgs(KeyExitEvent, this, e.Key); 

      RaiseEvent(args); 
     } 
    } 

這引起了我註冊這個控件調用一個簡單的路由事件KeyExit。

因此,基本上,它就像這個控件有兩個「模式」:用戶可以通過簡單地點擊控件就可以激活的「編輯模式」,以及用戶可以通過給予任何其他模式返回的「查看模式」控制UI鍵盤焦點。

在我的UI中,我有一堆堆棧面板,裏面有一堆這些控件 - 每一個都被包裝在我創建的類中,與概念類似於ListViewItem。這個想法是,當用戶在堆棧面板中的某個項目內處於編輯模式時,單擊TAB或ENTER鍵,面板中的下一個控件將進入編輯模式。

所以,我有以下事件的回調:

private void item_KeyExit(object sender, RoutedEventArgs e) 
    { 
     FrameworkElement obj = e.OriginalSource as FrameworkElement; 

     if (obj != null) 
     { 
      var listItem = VisualTreeHelperUtils.FindFirstAncestorOfType<MyListItem>(obj); 

      if (listItem != null) 
      { 
       int itemIndex = stackPanelList.Children.IndexOf(listItem); 

       MyListItem nextItem = null; 

       if (itemIndex == ucSortableList.Children.Count - 1) 
       { 
        nextItem = stackPanelList.Children[itemIndex+1] as MyListItem; 
       } 

       if (nextItem != null) 
       { 
        var item = nextItem.DataContent; // property I made in MyListItem that gives access to the class it wraps 

        InputTextBlock block = item as InputTextBlock; 
        if (block != null) 
        { 
         block.StartEdit(); 
        } 
       } 

      } 
     } 
    } 

一切正常調用,但馬上這一切完成後,原來的項目,這是我標籤出來的,獲取鍵盤焦點回來,導致堆棧中的項目不處於編輯模式。因此,例如,如果堆棧中的第一項處於編輯模式,則一旦用戶點擊Tab鍵,堆棧中的第二項進入編輯模式,但第一項立即返回鍵盤焦點。任何人都可以理解爲什麼發生這種情況?

回答

0

StackPanel Focusable默認爲false。建議確保它是真實的。

也用於檢查indeces,通常希望索引是<計數。所以,你的指數+ 1可以指望==如果是==計數 - 1.你不想要的:

if (itemIndex < ...Count - 1)
這樣,項指數+ 1永遠是< =計數 - 1?你

if (itemIndex == ucSortableList.Children.Count - 1) { nextItem = stackPanelList.Children[itemIndex+1] as MyListItem; }

也可以用box.Focus()而不是Keyboard.Focus(box)但可能沒有必要。