当子TextBox为Focused时设置ListBoxItem.IsSelected

jps*_*res 13 wpf binding textbox mvvm listboxitem

我有一个典型的MVVM场景:我有一个ListBox绑定到一个StepsViewModel列表.我定义了一个DataTemplate,以便StepViewModel呈现为StepViews.StepView UserControl有一组标签和TextBox.

我想要做的是选择在关注textBox时包装StepView的ListBoxItem.我尝试使用以下触发器为我的TextBox创建一个样式:

<Trigger Property="IsFocused" Value="true">
    <Setter TargetName="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Property="IsSelected" Value="True"/>
</Trigger>
Run Code Online (Sandbox Code Playgroud)

但是我收到一个错误,告诉我TextBox没有IsSelected属性.我现在,但Target是一个ListBoxItem.我怎样才能使它工作?

Joh*_*wen 30

有一个只读属性IsKeyboardFocusWithin,如果有任何子节点聚焦,它将被设置为true.您可以使用它在Trigger中设置ListBoxItem.IsSelected:

<ListBox ItemsSource="{Binding SomeCollection}" HorizontalAlignment="Left">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter Property="IsSelected" Value="True" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBox Width="100" Margin="5" Text="{Binding Name}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

  • 这种方法有一个非常大的"问题" - 当你的应用程序本身失去焦点时,IsSelected将设置为false.也就是说,我点击文本框列表框的项目里面,但切换到另一个应用程序(比如回答在我的浏览器中的StackOverflow的问题),然后切换回您的应用程序... IsSelected属性将被设置为真,假,真实,而不是一直保持真实.如果您从ListBox的SelectedItem属性中驱动行为,这可能会造成很大的问题. (13认同)

小智 5

正如Jordan0Day正确指出的那样,使用IsKeyboardFocusWithin解决方案确实存在很大的问题.在我的情况下,工具栏中关于ListBox的按钮也不再起作用.焦点同样的问题.单击按钮时,ListBoxItem会松开Focus并且Button会更新其CanExecute方法,这会导致在执行按钮单击命令之前暂停按钮.

对我来说,更好的解决方案是使用ItemContainerStyle EventSetter,如本文所述:当使用内部控件时,ListboxItem选择

XAML:

<Style x:Key="MyItemContainer.Style" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Background" Value="LightGray"/>
    <EventSetter Event="GotKeyboardFocus" Handler="OnListBoxItemContainerFocused" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border x:Name="backgroundBorder" Background="White">
                    <ContentPresenter Content="{TemplateBinding Content}"/>
                </Border>
            <ControlTemplate.Triggers>
                 <Trigger Property="IsSelected" Value="True">
                     <Setter TargetName="backgroundBorder" Property="Background" Value="#FFD7E6FC"/>
                 </Trigger>
             </ControlTemplate.Triggers>
         </ControlTemplate>
     </Setter.Value>
 </Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)

在视图后面的代码中的EventHandler:

private void OnListBoxItemContainerFocused(object sender, RoutedEventArgs e)
{
    (sender as ListBoxItem).IsSelected = true;
}
Run Code Online (Sandbox Code Playgroud)