をDataTemplate
含んでいTextBox
ます。このテンプレートを選択範囲のリストボックス項目に設定しています。
テンプレートのテキスト ボックスにフォーカスを設定できません。MyTemplate.FindName を呼び出そうとしましたが、無効な操作の例外で終わります: この操作は、このテンプレートが適用されている要素に対してのみ有効です。
どうすればアクセスできますか?
をDataTemplate
含んでいTextBox
ます。このテンプレートを選択範囲のリストボックス項目に設定しています。
テンプレートのテキスト ボックスにフォーカスを設定できません。MyTemplate.FindName を呼び出そうとしましたが、無効な操作の例外で終わります: この操作は、このテンプレートが適用されている要素に対してのみ有効です。
どうすればアクセスできますか?
これが古いことは知っていますが、今日この問題に遭遇し、最終的にこの解決策を思いつきました:
はアイテムが選択されたときにのみロードされ、フォーカスを設定するときにのみロードされるため、単純にイベントをTextBox
処理して を呼び出すことができます。TextBox.Load
Focus()
これを実現するには 2 つの方法があります。
TextBox
1.の を にDataTemplate
置き換えますAutoFocusTextBox
。
public class AutoFocusTextBox : TextBox
{
public AutoFocusTextBox()
{
Loaded += delegate { Focus(); };
}
}
.xaml ファイルで AutoFocusTextBox が定義されている名前空間を参照する必要があることを忘れないでください。
DataTemplate
2.が定義されているファイルの分離コードにハンドラーを追加します。
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();
}
いずれのオプションでも、すべてのテキストを選択するなど、ハンドラーに他の動作をいつでも追加できます。
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
あり、メソッドに入るまでに完全に初期化されていない場合がありました。
Ok。だから私は最善の解決策を持っていると思います。とにかくそれは私のために働いた。テキスト ボックスにフォーカスを当てたい単純なデータ テンプレートがあります。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>
Jay の 2 番目の提案はきちんとしていて、UIElement
ではなくを使用することでより一般化できるTextBox
ため、任意のコントロールを簡単にデフォルトにすることができます。
private void FocusControlOnLoad(object sender, RoutedEventArgs e)
{
var uiElement = sender as UiElement;
if(uiElement == null) return;
uiElement.Focus();
}