Фокус DataTemplate в WPF - PullRequest
       19

Фокус DataTemplate в WPF

1 голос
/ 20 февраля 2009

Мне нужно поведение, состоящее в том, что выбор элемента в ListView приводит к фокусировке первого фокусируемого визуального ребенка.

Проблема: данные с данными в ItemsControler, который не получает начальный фокус. В приведенном ниже примере есть 4 строки, которые затем вставляются в TextBox через Datatemplate.

Пример:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:sys="clr-namespace:System;assembly=mscorlib" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Grid>
      <ListView>
         <ListView.Resources>
            <DataTemplate DataType="{x:Type sys:String}" >
               <TextBox Width="100" Text="{Binding Mode=OneWay}"/>
            </DataTemplate>
         </ListView.Resources>
         <ListView.ItemsSource>
            <x:Array Type="{x:Type sys:String}">
               <sys:String>test</sys:String>
               <sys:String>test</sys:String>
               <sys:String>test</sys:String>
               <sys:String>test</sys:String>
            </x:Array>
         </ListView.ItemsSource>
      </ListView>
   </Grid>
</Window>

Я уже пробовал некоторые комбинации

FocusManager.FocusedElement="{Binding ElementName=[...]}"

Бессмысленно говорить: без успеха. Кто-нибудь знает, как я могу получить то, что я хочу, не обходя визуальное дерево в C #? Это должно быть возможно, не так ли?

Ответы [ 2 ]

3 голосов
/ 10 августа 2012

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>
1 голос
/ 24 февраля 2009

Использование синтаксиса привязки в C # не будет работать, потому что так описываются привязки в XAML. Это может сработать для создания нового экземпляра System.Windows.Data.Binding и установки его свойств, эквивалентного тому, что вы установили бы в XAML, но я не уверен, к какому ElementName вы сможете привязаться, чтобы получить это работает правильно.

Единственный другой вариант, о котором я могу подумать, - это добавить обработчик для события SelectionChanged и установить фокус вручную, но это не похоже на то решение, которое вам нужно.

При дальнейшем осмотре я не думаю, что решение Binding возможно. FocusManager.FocusedElement - это IInputElement, в котором нет членов, связанных с привязкой. Я думаю, что вам нужно пройти по визуальному дереву, чтобы найти первый объект, который можно сфокусировать. Примерно так должно работать:

// Event handler for the ListBox.SelectionChanged event
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListBox listBox = sender as ListBox;
    ItemContainerGenerator = generator.listBox.ItemContainerGenerator;
    ListBoxItem selectedItem =
        (ListBoxItem)generator.ContainerFromIndex(listBox.SelectedIndex);
    IInputElement firstFocusable = FindFirstFocusableElement(selectedItem);
    firstFocusable.Focus();
}

private IInputElement FindFirstFocusableElement(DependencyObject obj)
{
    IInputElement firstFocusable = null;

    int count = VisualTreeHelper.GetChildrenCount(obj);
    for(int i = 0; i < count && null == firstFocusable; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        IInputElement inputElement = child as IInputElement;
        if(null != inputElement && inputElement.Focusable)
        {
            firstFocusable = inputElement;
        }
        else
        {
            firstFocusable = FindFirstFocusableElement(child);
        }
    }

    return firstFocusable;
}
...