WPF中如何使ListView中能通过点击数据行中的任何控件比如TextBox而进行行的选中

在WPF的ListView中,有时候对数据行的数据模板进行了自定义使用了TextBox等控件,在默认点中TextBox进行编辑时,其所在数据行并不会被选中,这时候我们只需要给ListView添加一个PreviewMouseDown事件,并添加下面的代码,即可实现可以通过点击自定义的数据模板中的控件进行数据行的选择,包括单选及多选。


        #region Make the row be selected when click on it
        private T FindAncestor<T>(DependencyObject obj) where T : DependencyObject
        {
            while (obj != null)
            {
                var ancestor = obj as T;
                if (ancestor != null)
                {
                    return ancestor;
                }
                obj = VisualTreeHelper.GetParent(obj);
            }
            return null;
        }

        private void ListView_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var listView = sender as ListView;
            if (listView == null) return;

            var hitTestResult = VisualTreeHelper.HitTest(listView, e.GetPosition(listView));
            if (hitTestResult != null)
            {
                var listViewItem = FindAncestor<ListViewItem>(hitTestResult.VisualHit);
                if (listViewItem != null)
                {
                    // 获取当前点击的项
                    var clickedItem = listView.ItemContainerGenerator.ItemFromContainer(listViewItem);

                    // 检查 SelectionMode
                    if (listView.SelectionMode == SelectionMode.Single)
                    {
                        // 在 Single 模式下,直接选中当前点击的项
                        listView.SelectedItem = clickedItem;
                    }
                    else if (listView.SelectionMode == SelectionMode.Multiple || listView.SelectionMode == SelectionMode.Extended)
                    {
                        // 检查是否按下了 Shift 键
                        if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                        {
                            // 获取第一个选中的项
                            var firstSelectedItem = listView.SelectedItems.Cast<object>().FirstOrDefault();

                            if (firstSelectedItem != null)
                            {
                                // 获取第一个选中项和当前点击项的索引
                                int firstIndex = listView.Items.IndexOf(firstSelectedItem);
                                int clickedIndex = listView.Items.IndexOf(clickedItem);

                                // 确定范围的起始和结束索引
                                int startIndex = Math.Min(firstIndex, clickedIndex);
                                int endIndex = Math.Max(firstIndex, clickedIndex);

                                // 清除所有选中项
                                listView.SelectedItems.Clear();

                                // 选中范围内的所有项
                                for (int i = startIndex; i <= endIndex; i++)
                                {
                                    listView.SelectedItems.Add(listView.Items[i]);
                                }
                            }
                            else
                            {
                                // 如果没有第一个选中的项,则只选中当前点击的项
                                listView.SelectedItems.Clear();
                                listViewItem.IsSelected = true;
                            }
                        }
                        // 检查是否按下了 Ctrl 键
                        else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                        {
                            // 如果按下了 Ctrl 键,则切换当前点击项的选中状态
                            listViewItem.IsSelected = !listViewItem.IsSelected;
                        }
                        else
                        {
                            // 如果没有按下 Ctrl 或 Shift,则只选中当前点击的项
                            listView.SelectedItems.Clear();
                            listViewItem.IsSelected = true;
                        }
                    }
                }
            }
        }
        #endregion

XAML中的实现如下,关键代码是第一行的PreviewMouseDown="ListView_PreviewMouseDown"

    <ListView x:Name="lvDBUsers" ItemsSource="{Binding Path=SelectedEntity.SelectedDepartment.Users}" SelectedItem="{Binding Path=SelectedEntity.SelectedDepartment.SelectedUser}" PreviewMouseDown="ListView_PreviewMouseDown">
        <ListView.View>
            <GridView AllowsColumnReorder="False">
                <GridViewColumn Header="Enroll Number" x:Name="colEnrollNumber">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding ElementName=colEnrollNumber, Path=ActualWidth}">
                                <TextBox Text="{Binding Path=UIEnrollNumber,  UpdateSourceTrigger=Default , NotifyOnValidationError=True , ValidatesOnDataErrors=True}" Margin="0,0,12,0"/>
                            </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 总览: 按钮 (Buttons) Button:基本按钮控件,用户点击时触发操作或事件。 RepeatButton...
    c624ef3ffb3f阅读 1,279评论 0 0
  • 一、样式(Style)与模板(Template)二、资源字典ResourceDictionary三、数据绑定四、特...
    李姗姗_8ef1阅读 3,811评论 0 0
  • 控件介绍 教程数据 NoesisGUI包含一组标准控件,使您能够快速组装传统用户界面。它们可以分为四个主要类别,这...
    YottaYuan阅读 3,169评论 0 1
  • 1. 什么是Validaion.ErrorTemplate 数据绑定模型允许您将与您Binding的对象相关联Va...
    dino_chan阅读 1,058评论 0 0
  • 数据绑定 教程数据 NoesisGUI提供了一种简单而强大的方法来自动更新业务模型和用户界面之间的数据。这种机制称...
    YottaYuan阅读 4,059评论 0 1

友情链接更多精彩内容