我DataTemplate
包含TextBox
。我将此模板设置为选择的列表框项目。
我无法将焦点设置到模板中的文本框中。我试图调用MyTemplate.FindName,但最终会出现无效的操作异常:此操作仅对应用了此模板的元素有效。
我如何访问它?
答案 0 :(得分:12)
我知道这已经过时了,但今天我遇到了这个问题,最终提出了这个决议:
由于TextBox
仅在选择项目时加载,并且您希望设置焦点,因此您只需处理TextBox.Load
事件并调用Focus()
即可。
有两种方法可以实现这一目标。
<强> 1。将TextBox
中的DataTemplate
替换为AutoFocusTextBox
。
public class AutoFocusTextBox : TextBox
{
public AutoFocusTextBox()
{
Loaded += delegate { Focus(); };
}
}
不要忘记您需要引用在.xaml文件中定义AutoFocusTextBox的命名空间。
<强> 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();
}
使用任一选项,您始终可以在处理程序中添加其他行为,例如选择所有文本。
答案 1 :(得分: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
尚未完全初始化。
答案 2 :(得分: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>
答案 3 :(得分:2)
Jay的第二个建议很简洁 - 使用UIElement
而不是TextBox
可以更加概括,以便可以轻松地将任何控件设为默认值:
private void FocusControlOnLoad(object sender, RoutedEventArgs e)
{
var uiElement = sender as UiElement;
if(uiElement == null) return;
uiElement.Focus();
}