代码之家  ›  专栏  ›  技术社区  ›  Dusan Kocurek

关注数据模板中的文本框

  •  9
  • Dusan Kocurek  · 技术社区  · 16 年前

    我有 DataTemplate 包含一个 TextBox . 我正在将此模板设置为所选内容的列表框项。

    我无法在模板中将焦点设置为文本框。我试图调用mytemplate.findname,但最后得到一个无效的操作异常:此操作仅对应用了此模板的元素有效。

    如何访问它?

    4 回复  |  直到 11 年前
        1
  •  9
  •   Dave Clemmer manu    11 年前

    因为你知道 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 事件,有时 列表项目 在我们进入方法时还没有完全初始化。

        2
  •  10
  •   Jay    14 年前

    我知道这很古老,但我今天遇到了这个问题,最终得出了这个解决方案:

    自从 TextBox 仅当选中某个项时才加载,也就是当您希望设置焦点时,您可以简单地处理 TextBox.Load 事件与调用 Focus() .

    实现这一点有两种方法。

    1。替换 文本框 DataTemplate 用一个 AutoFocusTextBox .

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

    别忘了,您需要引用在.xaml文件中定义autofocustextbox的命名空间。

    2。在文件的codebehind中添加一个处理程序,其中 数据板 定义。

    someResourceDictionary.xaml

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

    someresourcedictionary.xaml.cs(某些资源字典.xaml.cs)

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

    无论使用哪一个选项,您都可以在处理程序中添加其他行为,例如选择所有文本。

        3
  •  7
  •   Dave Clemmer manu    11 年前

    好啊。所以我认为我有最好的解决办法。不管怎样,它对我很有用。我有一个简单的数据模板,我想把焦点放在文本框上。这个 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>
    
        4
  •  2
  •   Dave Clemmer manu    11 年前

    杰伊的第二个建议很简洁,可以通过使用 UIElement 而不是 TextBox ,以便可以轻松地将任何控件设为默认控件:

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