2015-03-13 81 views
1

WPF:當用戶在ItemsControl中的texbox內按下Enter鍵時,我想將焦點移動到ItemsControl中下一項中的文本框中,或者創建一個如果用戶在最後一項中,則爲新的。WPF:將焦點移動到ItemsControl上的下一個項目上輸入

爲了更清楚:

方案1

ItemsControl items: 
[ textbox in item 1 ] <- user is here 
[ textbox in item 2 ] 
[ textbox in item 3 ] 

按下回車鍵後:

[ textbox in item 1 ] 
[ textbox in item 2 ] <- user is here 
[ textbox in item 3 ] 

方案2

ItemsControl的項目:

[ textbox in item 1 ] 
[ textbox in item 2 ] 
[ textbox in item 3 ] <- user is here 

之後按Enter:

[ textbox in item 1 ] 
[ textbox in item 2 ] 
[ textbox in item 3 ] 
[ textbox in item 4 ] <- user is here 

如果有幫助,這裏是項目數據模板的代碼:

<ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Grid Background="White"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="32"/> 
      </Grid.ColumnDefinitions> 
      <TextBox Text="{Binding Path=PartName, FallbackValue='----',TargetNullValue='----', NotifyOnSourceUpdated=True}" KeyDown="TextBox_KeyDown"/> 
      <Button Grid.Column="1" FontSize="10" x:Name="DeletePartButton" Click="DeletePartButton_Click" Height="22">Usuń</Button> 
     </Grid> 
    </DataTemplate> 
</ItemsControl.ItemTemplate> 

編輯2: 我使用ItemsControl的,因爲選擇功能不想要的。

編輯3: 我找到了部分解決方案。它適用於移動焦點到下一個元素,而不是一個新的(這是最重要的功能在這裏)

private void PartNameTextBox_KeyDown(object sender, KeyEventArgs e) 
    { 
     var box = (TextBox)sender; 

     if (e.Key == Key.Enter) 
     { 
      var part = (PiecePart)box.DataContext; 
      int index = part.ParentPiece.Parts.IndexOf(part); 
      if (index == part.ParentPiece.PartCount - 1) 
      { 
       part.ParentPiece.Parts.Add(new PiecePart(GetNewPartName(part.ParentPiece))); 
       bool success = PartListBox.ApplyTemplate(); 
       // try to force wpf to build a visual tree for the new item success = false :(
      } 
// throws out of bounds exception if a new item was added (and wasn't added to a visual tree) 
      var el = ((UIElement)VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(PartListBox, 0),0),1),0),0),++index),0),0)); 
      el.Focus(); 
     } 
    } 

回答

0
Listbox.SelectedIndex = 0; 

private void Listbox_OnKeyUp(object sender, KeyEventArgs e) 
{ 
    if (e.Key== Key.Enter) 
    { 
     if(Listbox.Items.Count-1>Listbox.SelectedIndex) 
      Listbox.SelectedIndex++; 
     else 
      Listbox.SelectedIndex=0; 
    } 
} 

這項工作時,用戶把精力放在你的列表框。

0

C#

private void ListBox_KeyUp(object sender, KeyEventArgs e) 
    { 
     int selectIndex = listBox.SelectedIndex; 
     int listItemCount = listBox.Items.Count; 
     if (e.Key == Key.Enter) 
     { 
      if (selectIndex == listItemCount - 1) 
      { 
       ListBoxItem newItem = new ListBoxItem(); 
       newItem.Content = "Your Content"; 
       listBox.Items.Add(newItem); 
       listBox.SelectedItem = newItem; 
      } 
      else 
      { 
       listBox.SelectedIndex = selectIndex + 1; 
      } 
     } 
    } 

XAML

 <ListBox HorizontalAlignment="Left" Name="listBox" Height="92" KeyUp="ListBox_KeyUp"> 
     <ListBoxItem Content="First"/> 
     <ListBoxItem Content="Second"/> 
     <ListBoxItem Content="Third"/> 
     <ListBoxItem Content="Fourth"/> 
    </ListBox> 

首先我得到的列表框項目算作listItemCount,也是選擇的項目指標爲selectIndex,然後檢查關鍵事件是一個回車然後檢查我們是否到達列表的最後。如果是製作一個新的列表框項目並將其添加到列表中。

+0

這不起作用,因爲如果用戶在TextBox中沒有選擇項目。順便說一下,我已經切換到ItemsControl,因爲我根本不想選擇功能。 – 2015-03-13 09:31:58

+0

即使用戶不關注列表框,您是否需要選擇該項目? – 2015-03-13 09:38:59

+0

我不想選擇一個項目,我想將焦點移動到所需項目中的TextBox。 – 2015-03-13 09:58:42

1

將焦點移動到在WPF的下一個元素的正確方法是使用TraversalRequest表示將焦點移動到另一個控制和一個請求,其指定在用戶界面(UI)中的方向上的FocusNavigationDirection Enumeration其中期望的焦點改變請求被嘗試。此示例取自MSDN上的TraversalRequest類別頁面:

// Creating a FocusNavigationDirection object and setting it to a 
// local field that contains the direction selected. 
FocusNavigationDirection focusDirection = _focusMoveValue; 

// MoveFocus takes a TraveralReqest as its argument. 
TraversalRequest request = new TraversalRequest(focusDirection); 

// Gets the element with keyboard focus. 
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; 

// Change keyboard focus. 
if (elementWithFocus != null) 
{ 
    elementWithFocus.MoveFocus(request); 
} 
+0

謝謝,它用於將焦點移至現有項目,但是當創建新焦點時,焦點消失。 – 2015-03-13 09:46:58

+0

然後在創建新元素之後重新聚焦所需元素,但我建議無論如何都要重點關注新元素。 – Sheridan 2015-03-13 09:56:58

+0

如何?我不在代碼中創建可視元素,所以我沒有對它的引用。我將一個新項目添加到源集合中。之後,它出現在列表中,但同時它不存在於視覺樹中。如果有ItemsControl.ItemAdded事件或者這樣的事情...... – 2015-03-13 10:02:13

1

我明白了。爲了將焦點轉移到下一個元素,我使用謝里登的解決方案。爲了將焦點移至新元素,我使用「添加」標誌和TextBox.Loaded事件。

<ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Grid Background="White" > 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*"/> 
       <ColumnDefinition Width="32"/> 
      </Grid.ColumnDefinitions> 
      <TextBox x:Name="PartNameTextbox" Text="{Binding Path=PartName, FallbackValue='----',TargetNullValue='----', NotifyOnSourceUpdated=True}" KeyDown="PartNameTextBox_KeyDown" 
     Loaded="PartNameTextbox_Loaded"/> 
      <Button Grid.Column="1" FontSize="10" x:Name="DeletePartButton" Click="DeletePartButton_Click" Height="22">Usuń</Button> 
     </Grid> 
    </DataTemplate> 
</ItemsControl.ItemTemplate> 

後臺代碼:

bool partAdding = false; 
private void PartNameTextBox_KeyDown(object sender, KeyEventArgs e) 
{ 
    var box = (TextBox)sender; 

    if (e.Key == Key.Enter) 
    { 
     var part = (PiecePart)box.DataContext; 
     int index = part.ParentPiece.Parts.IndexOf(part); 
     if (index == part.ParentPiece.PartCount - 1) 
     { 
      part.ParentPiece.Parts.Add(new PiecePart(GetNewPartName(part.ParentPiece))); 
      UpdateCurrentLine(part.ParentPiece); 
      partAdding = true; 
     } 
     // Gets the element with keyboard focus. 
     UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; 

     // Creating a FocusNavigationDirection object and setting it to a 
     // local field that contains the direction selected. 
     FocusNavigationDirection focusDirection = FocusNavigationDirection.Down; 

     // MoveFocus takes a TraveralReqest as its argument. 
     TraversalRequest request = new TraversalRequest(focusDirection); 

     // Change keyboard focus. 
     if (elementWithFocus != null) 
     { 
      elementWithFocus.MoveFocus(request); 
     } 
    } 
} 

private void PartNameTextbox_Loaded(object sender, RoutedEventArgs e) 
{ 
    if (partAdding) 
    { 
     var box = ((TextBox)sender);    
     var pp = ((PiecePart) box.DataContext); 
     if (pp.IsLastPart) 
     { 
      box.Focus(); 
      box.SelectionStart = box.Text.Length; 
      partAdding = false; 
     } 
    } 
} 
0

在文本框的PreviewKeyDown

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) 
{ 
if (e.Key == Key.Enter) 
    { 
    var txt= sender as TextBox; 
    var selecteditem=FindParent<ListBoxItem>(txt); 
    int index = ListBox.ItemContainerGenerator.IndexFromContainer(selecteditem); 
    if(index<ListBox.Items.Count) 
    { 
    var afterItem=(ListBoxItem)ListBox.ItemContainerGenerator.ContainerFromIndex(index+1); 
    TextBox tbFind = GetDescendantByType(afterItem, typeof (TextBox), "TextBox") as TextBox; 
    if (tbFind != null) 
    { 
    FocusHelper.Focus(tbFind); 
    } 
    } 
    } 
} 

public static Visual GetDescendantByType(Visual element, Type type, string name) 
{ 
if (element == null) return null; 
if (element.GetType() == type) 
{ 
    FrameworkElement fe = element as FrameworkElement; 
    if (fe != null) 
    { 
    if (fe.Name == name) 
    { 
     return fe; 
    } 
    } 
} 
Visual foundElement = null; 
if (element is FrameworkElement) 
    (element as FrameworkElement).ApplyTemplate(); 
for (int i = 0; 
    i < VisualTreeHelper.GetChildrenCount(element); 
    i++) 
{ 
    Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; 
    foundElement = GetDescendantByType(visual, type, name); 
    if (foundElement != null) 
    break; 
} 
return foundElement; 
} 

public static T FindParent<T>(DependencyObject child) where T : DependencyObject 
{ 
//get parent item 
DependencyObject parentObject = VisualTreeHelper.GetParent(child); 

//we've reached the end of the tree 
if (parentObject == null) return null; 

//check if the parent matches the type we're looking for 
T parent = parentObject as T; 
if (parent != null) 
    return parent; 
else 
    return FindParent<T>(parentObject); 
} 

還有一個幫手,將對焦的文本框:

public static class FocusHelper 
{ 
public static void Focus(UIElement element) 
{ 
element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(delegate() 
{ 
    element.Focus(); 
})); 
} 
} 
0

ar.gorgin的解決方案有些輕微主要是爲了認識到OP需要使用ItemsControl而不是ListBox:

if (e.Key == Key.Enter) 
{ 
    var txt = sender as TextBox; 
    var selecteditem = FindParent<ContentPresenter>(txt); 
    int index = myItemsCtl.ItemContainerGenerator.IndexFromContainer(selecteditem); 

    if (index < myItemsCtl.Items.Count) 
    { 
     var afterItem = myItemsCtl.ItemContainerGenerator.ContainerFromIndex(index + 1) as Visual; 
     TextBox tbFind = GetDescendantByType(afterItem, typeof(TextBox), "txtBoxName") as TextBox; 
     if (tbFind != null) 
     { 
      FocusHelper.Focus(tbFind); 
     } 
    } 
} 
+0

自從我與WPF合作已經很長時間了,我甚至沒有辦法檢查所有這些解決方案......但我很驚訝許多可怕的黑客,你需要寫一個單一的東西,這是不是開箱即用。仍然比在Erlang(ouch)中編寫Web應用程序更好。 – 2018-01-08 09:32:52

相關問題