10

我已经DataTemplate包含一个TextBox. 我将此模板设置为选择中的列表框项目。

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

我怎样才能访问它?

4

4 回答 4

13

我知道这是旧的,但我今天遇到了这个问题,最后想出了这个解决方案:

由于TextBox仅在选择项目时才加载,即当您希望设置焦点时,您可以简单地处理TextBox.Load事件并调用Focus().

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

1. 将TextBox中的替换DataTemplateAutoFocusTextBox

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

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

DataTemplate2. 在定义的文件的代码隐藏中添加一个处理程序。

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();
    }

使用任一选项,您始终可以在处理程序中添加其他行为,例如选择所有文本。

于 2010-06-25T21:43:31.000 回答
10

由于您知道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我们进入方法时还没有完全初始化。

于 2008-11-30T23:10:04.490 回答
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>
于 2012-08-10T00:33:24.580 回答
2

Jay 的第二个建议很简洁 - 并且可以通过使用UIElement而不是更通用化TextBox,因此可以轻松地将任何控件设为默认值:

private void FocusControlOnLoad(object sender, RoutedEventArgs e)
{
    var uiElement = sender as UiElement;
    if(uiElement == null) return;
    uiElement.Focus();
}
于 2010-09-09T08:21:50.317 回答