WPF中的焦点数据模板

WPF中的焦点数据模板,wpf,xaml,focus,datatemplate,Wpf,Xaml,Focus,Datatemplate,我正在寻找的行为是,在ListView中选择一个项目会导致聚焦第一个可聚焦的visualchild 问题:ItemsController中的数据模板化数据没有获得初始焦点。 在下面的示例中,有4个字符串,然后通过Datatemplate填充到文本框中 例如: <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;as

我正在寻找的行为是,在ListView中选择一个项目会导致聚焦第一个可聚焦的visualchild

问题:ItemsController中的数据模板化数据没有获得初始焦点。 在下面的示例中,有4个字符串,然后通过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>
毫无意义地说:没有成功。 有人知道我如何在不遍历c#中的可视化树的情况下得到我想要的吗?
应该可以做到这一点,不是吗?

在C#中使用绑定语法是行不通的,因为在XAML中绑定就是这样描述的。创建
System.Windows.Data.Binding
的一个新实例,并将其属性设置为与在XAML中设置的属性相同的属性,可能会起作用,但我不确定为了使其正常工作,您可以绑定到哪个
ElementName

我能想到的唯一其他选择是为
SelectionChanged
事件添加一个处理程序,并手动设置焦点,但这听起来不像是您想要的解决方案

经进一步检查,我认为不可能有一个有约束力的解决方案
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;
}
//ListBox.SelectionChanged事件的事件处理程序
私有无效列表框\u SelectionChanged(对象发送方,SelectionChangedEventArgs e)
{
ListBox ListBox=发送方作为ListBox;
ItemContainerGenerator=generator.listBox.ItemContainerGenerator;
ListBoxItemSelectedItem=
(listBox项)generator.ContainerFromIndex(listBox.SelectedIndex);
IIInputElement firstFocusable=FindFirstFocusableElement(selectedItem);
firstFocusable.Focus();
}
私有IIInputElement FindFirstFocusableElement(DependencyObject obj)
{
IIInputElement firstFocusable=null;
int count=VisualTreeHelper.GetChildrenCount(obj);
对于(int i=0;i
在C#中使用绑定语法是行不通的,因为在XAML中绑定就是这样描述的。创建
System.Windows.Data.Binding
的一个新实例,并将其属性设置为与在XAML中设置的属性相同的属性,可能会起作用,但我不确定为了使其正常工作,您可以绑定到哪个
ElementName

我能想到的唯一其他选择是为
SelectionChanged
事件添加一个处理程序,并手动设置焦点,但这听起来不像是您想要的解决方案

经进一步检查,我认为不可能有一个有约束力的解决方案
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;
}
//ListBox.SelectionChanged事件的事件处理程序
私有无效列表框\u SelectionChanged(对象发送方,SelectionChangedEventArgs e)
{
ListBox ListBox=发送方作为ListBox;
ItemContainerGenerator=generator.listBox.ItemContainerGenerator;
ListBoxItemSelectedItem=
(listBox项)generator.ContainerFromIndex(listBox.SelectedIndex);
IIInputElement firstFocusable=FindFirstFocusableElement(selectedItem);
firstFocusable.Focus();
}
私有IIInputElement FindFirstFocusableElement(DependencyObject obj)
{
IIInputElement firstFocusable=null;
int count=VisualTreeHelper.GetChildrenCount(obj);
对于(int i=0;i
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>

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>


即使我想在c语言中手动执行,我也需要从Datatemplate中获取对文本框的引用,如果运气不好,里面会有多个级联datatemplates,因此我需要搜索它。。。必须能够将焦点放在第一个输入上。奇怪的是,像这样基本的东西并不像WPF的其他部分那么优雅。我仍然希望通过.NET4.0获得一个简单的基于XAML的答案。我希望你能理解为什么我不会把你的帖子标记为答案,即使我可能会使用这种解决方案的变体。我理解。几天前,我正在研究一个潜在的解决方案(FocusManager.FocusedElement是大多数控件的附加属性),但是我仍然无法得到任何东西来工作。即使我想在c#中手动完成,我也需要从Datatemplate中获取对文本框的引用,如果运气不好的话,里面会有多个级联的datatemplates,所以我需要