WPF中ListBoxItem中包含TextBox的选中问题及解决方法

4 篇文章 0 订阅

为了说明这个选中的问题,先创建了一个界面


  <Window.Resources>
    <Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
      <Setter Property="OverridesDefaultStyle" Value="True" />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ContentControl}">
            <Border Background="{TemplateBinding Background}">
              <ContentPresenter />
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>

      <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Background" Value="LightBlue" />
        </Trigger>
        <Trigger Property="IsMouseOver" Value="False">
          <Setter Property="Background" Value="LightGray" />
        </Trigger>
        <Trigger Property="IsSelected" Value="True">
          <Setter Property="Background" Value="Plum" />
        </Trigger>
      </Style.Triggers>

    </Style>
  </Window.Resources>

  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ListBox
      Grid.Column="0"
      Name="lbNation"
      Margin="2, 2, 4, 2"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch"
      ItemsSource="{Binding Path=Nations}"
      SelectedItem="{Binding Path=SelectedNation}"
      ItemContainerStyle="{StaticResource editableListBoxItemStyle}">
      <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
          <Border 
            BorderThickness="1"
            BorderBrush="Black"
            Background="White">
            <ScrollViewer 
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto"
              Margin="1">
              <ItemsPresenter Margin="10"/>
            </ScrollViewer>
          </Border>
        </ControlTemplate>
      </ItemsControl.Template>

      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>

      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Grid HorizontalAlignment="Stretch">
            <TextBox 
              Margin="4" 
              Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
          </Grid>
        </DataTemplate>
      </ItemsControl.ItemTemplate>

    </ListBox>

    <ListBox
      Grid.Column="1"
      Name="lbPerson"
      Margin="2, 2, 4, 2"
      HorizontalAlignment="Stretch"
      VerticalAlignment="Stretch"
      ItemsSource="{Binding Path=SelectedNation.Members}"
      SelectedItem="{Binding Path=SelectedPerson}"
      ItemContainerStyle="{StaticResource editableListBoxItemStyle}">
      <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
          <Border 
            BorderThickness="1"
            BorderBrush="Black"
            Background="White">
            <ScrollViewer 
              HorizontalScrollBarVisibility="Auto"
              VerticalScrollBarVisibility="Auto"
              Margin="1">
              <ItemsPresenter Margin="10"/>
            </ScrollViewer>
          </Border>
        </ControlTemplate>
      </ItemsControl.Template>

      <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
      </ItemsControl.ItemsPanel>

      <ItemsControl.ItemTemplate>
        <DataTemplate>
          <Grid HorizontalAlignment="Stretch">
            <TextBox 
              Margin="4" 
              Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
          </Grid>
        </DataTemplate>

      </ItemsControl.ItemTemplate>

    </ListBox>
  </Grid>

左边的Listbox中包含一个TextBox,选中左边ListBoxItem某项后右边会出现姓名列表

我想要实现选中TextBox后,同时能选中ListBoxItem这个对象,但是事与愿违,TextBox 具有焦点,但未选择 ListBoxItem。效果如下:

 

 开始行动:

实验一: 在 ListBoxItem 的 Style.Triggers 中添加IsKeyboardFocusWithin


  <Window.Resources>
    <Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
      <Setter Property="OverridesDefaultStyle" Value="True" />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ContentControl}">
            <Border Background="{TemplateBinding Background}">
              <ContentPresenter />
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>

      <Style.Triggers>
        <!--追加-->
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
          <Setter Property="IsSelected" Value="True"/>
        </Trigger>

        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Background" Value="LightBlue" />
        </Trigger>
        <Trigger Property="IsMouseOver" Value="False">
          <Setter Property="Background" Value="LightGray" />
        </Trigger>
        <Trigger Property="IsSelected" Value="True">
          <Setter Property="Background" Value="Plum" />
        </Trigger>
      </Style.Triggers>

    </Style>
  </Window.Resources>

会这种方法可以实现ListBoxItem 与 TexBox 的焦点一起被选中。右侧的成员列表也已更新。

但是当焦点转移到另一个控件时,ListBox 的 SelectedItem 绑定变为空。回顾第一次操作检查。在实现 IsKeyboardFocusWithin 触发器之前,即使焦点丢失,选择信息也会保留。在这种情况下,使用 IsKeyboardFocusWithin 设置标志似乎是不够的。

实验2:Behaviors方法

在stackoverflow上也搜到了类似的问题,发现一个采用Behaviors实现的方法,似乎可以通用所有控件,先创建一个类,代码如下:


using System.Windows;
using System.Windows.Controls.Primitives;

namespace Sample.Behaviors
{
    public class AutoSelectWhenAnyChildGetsFocus
    {
        public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached(
            "Enabled",
            typeof(bool),
            typeof(AutoSelectWhenAnyChildGetsFocus),
            new UIPropertyMetadata(false, Enabled_Changed));

        public static bool GetEnabled( DependencyObject obj ) { return (bool)obj.GetValue(EnabledProperty); }
        public static void SetEnabled( DependencyObject obj, bool value ) { obj.SetValue(EnabledProperty, value); }

        private static void Enabled_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var attachEvents = (bool)e.NewValue;
            var targetUiElement = (UIElement)sender;

            if (attachEvents)
            {
                targetUiElement.IsKeyboardFocusWithinChanged += TargetUiElement_IsKeyboardFocusWithinChanged;
            }
            else
            {
                targetUiElement.IsKeyboardFocusWithinChanged -= TargetUiElement_IsKeyboardFocusWithinChanged;
            }
        }

        static void TargetUiElement_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var targetUiElement = (UIElement)sender;

            if(targetUiElement.IsKeyboardFocusWithin)
            {
                Selector.SetIsSelected(targetUiElement, true);
            }
        }
    }
}

并将 ListBoxItem 的样式更改如下:

  <Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="OverridesDefaultStyle" Value="True" />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ContentControl}">
            <Border Background="{TemplateBinding Background}">
              <ContentPresenter />
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <!--追加-->
      <Setter Property="bh:AutoSelectWhenAnyChildGetsFocus.Enabled" Value="True"></Setter>

      <Style.Triggers>

        <!--废弃-->
        <!--<Trigger Property="IsKeyboardFocusWithin" Value="True">
          <Setter Property="IsSelected" Value="True"/>
        </Trigger>-->

        <Trigger Property="IsMouseOver" Value="True">
          <Setter Property="Background" Value="LightBlue" />
        </Trigger>
        <Trigger Property="IsMouseOver" Value="False">
          <Setter Property="Background" Value="LightGray" />
        </Trigger>
        <Trigger Property="IsSelected" Value="True">
          <Setter Property="Background" Value="Plum" />
        </Trigger>

      </Style.Triggers>

    </Style>

现在运行。ListBoxItem 是与TextBox 的焦点一起选择的。

失去焦点后

完美解决问题!! 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值