2008-11-30 29 views
9

我有DataTemplate,其中包含TextBox。我将此模板设置为选择上的列表框项目。专注于DataTemplate中的TextBox

我无法将焦点设置为模板中的文本框。我试图调用MyTemplate.FindName,但它以无效的操作异常结束:此操作仅对应用此模板的元素有效。

我该如何访问它?

回答

9

既然你知道你想要关注的TextBox的名字,这就变得相对容易了。这个想法是把它应用于ListBoxItem本身的模板。

你想要做的就是所选择的项目

第一件事:

var item = listBox1.ItemContainerGenerator.ContainerFromItem(listBox1.SelectedItem) as ListBoxItem; 

然后可以传递到侧重基于它的名字控制这个小助手功能:

public void FocusItem(ListBoxItem item, string name) 
{ 
    if (!item.IsLoaded) 
    { 
     // wait for the item to load so we can find the control to focus 
     RoutedEventHandler onload = null; 
     onload = delegate 
     { 
      item.Loaded -= onload; 
      FocusItem(item, name); 
     }; 
     item.Loaded += onload; 
     return; 
    } 

    try 
    { 
     var myTemplate = FindResource("MyTemplateKey") as FrameworkTemplate; // or however you get your template right now 

     var ctl = myTemplate.FindName(name, item) as FrameworkElement; 
     ctl.Focus(); 
    } 
    catch 
    { 
     // focus something else if the template/item wasn't found? 
    } 
} 

我猜测棘手的一点是确保你等待物品加载。我不得不添加该代码,因为我从ItemContainerGenerator.StatusChanged事件中调用了该代码,并且有时ListBoxItem在我们输入方法时尚未完全初始化。

+1

FindResource返回一个对象,所以一定要把它转换成一个FrameworkTemplate。 – Michael 2011-11-22 23:33:04

10

我知道这是老了,但我今天碰到这个问题跑,并最终想出了这个解决:

由于TextBox当选择一个项目只被加载,那就是当你想您可以简单地处理TextBox.Load事件并致电Focus()

有两种方法可以实现这一点。

1.用AutoFocusTextBox替换DataTemplate中的TextBox

public class AutoFocusTextBox : TextBox 
{ 
    public AutoFocusTextBox() 
    { 
     Loaded += delegate { Focus(); }; 
    } 
} 

不要忘记你需要引用其中AutoFocusTextBox在您的.xaml文件中定义的命名空间。

2.在定义了DataTemplate的文件的代码隐藏处添加处理程序。

SomeResourceDictionary.xaml

<TextBox Text="{Binding Something, Mode=TwoWay}" Style={StaticResource ... 
     Loaded="FocusTextBoxOnLoad" /> 

SomeResourceDictionary.xaml.cs

private void FocusTextBoxOnLoad(object sender, RoutedEventArgs e) 
    { 
     var textbox = sender as TextBox; 
     if(textbox == null) return; 
     textbox.Focus(); 
    } 

无论使用哪种方法,你可以随时添加其他行为的处理程序,如选择所有文本。

2

周杰伦的第二个建议是整齐的 - 并且可以使用UIElement而不是TextBox,使任何控制可以很容易地成为默认被更广义的:

private void FocusControlOnLoad(object sender, RoutedEventArgs e) 
{ 
    var uiElement = sender as UiElement; 
    if(uiElement == null) return; 
    uiElement.Focus(); 
} 
7

确定。所以我认为我有最好的解决方案。反正它适合我。我有一个简单的数据模板,我想把焦点放在文本框上。 FocusManager将焦点移交给文本框。

<DataTemplate x:Key="MyDataTemplate" DataType="ListBoxItem"> 
    <Grid> 
     <WrapPanel Orientation="Horizontal" FocusManager.FocusedElement="{Binding ElementName=tbText}"> 
      <CheckBox IsChecked="{Binding Path=Completed}" Margin="5" /> 
      <Button Style="{StaticResource ResourceKey=DeleteButtonTemplate}" Margin="5" Click="btnDeleteItem_Click" /> 
      <TextBox Name="tbText" 
        Text="{Binding Path=Text}" 
        Width="200" 
        TextWrapping="Wrap" 
        AcceptsReturn="True" 
        Margin="5" 
        Focusable="True"/> 
      <DatePicker Text="{Binding Path=Date}" Margin="5"/> 
     </WrapPanel> 
    </Grid> 
</DataTemplate> 
+0

不错,干净,也适合我,我喜欢它 – veljkoz 2014-06-01 10:08:19