让WPF中的DataGrid像Excel一样可以筛选

news2025/1/18 17:12:25

在默认情况下,WPF提供的DataGrid仅拥有数据展示等简单功能,如果要实现像Excel一样复杂的筛选过滤功能,则相对比较麻烦。本文以一个简单的小例子,简述如何通过WPF实话DataGrid的筛选功能,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点


在本示例中,从数据绑定,到数据展示,涉及知识点如下所示:

  • DataGrid,要WPF提供的进行二维数据展示在列表控件,默认功能非常简单,但是可以通过数据模板或者控件模板进行扩展和美化,可伸缩性很强。
  • MVVM,是Model-View-ViewModel的简写,主要进行数据和UI进行前后端分离,在本示例中,主要用到的MVVM第三方库为CommunityToolkit.Mvvm,大大简化原生MVVM的实现方式。
  • 集合视图, 要对 DataGrid 中的数据进行分组、排序和筛选,可以将其绑定到支持这些函数的 CollectionView。 然后,可以在不影响基础源数据的情况下处理 CollectionView 中的数据。 集合视图中的更改反映在 DataGrid 用户界面 (UI) 中。
  • Popup控件,直接继承FrameworkElement,提供了一种在单独的窗口中显示内容的方法,该窗口相对于指定的元素或屏幕坐标,浮动在当前Popup应用程序窗口上,可用于悬浮窗口。

示例截图


本示例主要模仿Excel的筛选功能进行实现,右键标题栏打开浮动窗口,悬浮于标题栏下方,既可以通过文本框进行筛选,也可以通过筛选按钮弹出右键菜单,选择具体筛选方式,截图如下所示:

选择筛选方式,弹出窗口,如下所示:

 输入筛选条件,点击确定,或者取消筛选。如筛选学号里面包含2的,效果如下所示:

 注意:以上筛选都是客户端筛选,不会修改数据源,也不会重连数据库。

核心源码


在本示例中,核心源码主要包含以下几个部分:

1. 前端视图【MainWindow.xaml】源码

主要实现了按学号,姓名,年龄三列进行筛选,既可以单列筛选,又可以组合筛选。且三列的筛选实现方式一致,仅是绑定列有差异。

<Window x:Class="DemoDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DemoDataGrid"
        mc:Ignorable="d"
        Title="DataGrid筛选示例" Height="650" Width="800">
    <Window.Resources>
        <ResourceDictionary>
            <CollectionViewSource x:Key="ItemsSource" Source="{Binding Path=Students}"></CollectionViewSource>
            <CollectionViewSource x:Key="Names" Source="{Binding Path=Names}"></CollectionViewSource>
            <CollectionViewSource x:Key="Nos" Source="{Binding Path=Nos}"></CollectionViewSource>
            <CollectionViewSource x:Key="Ages" Source="{Binding Path=Ages}"></CollectionViewSource>
            <Style x:Key="ListBoxStyle" TargetType="{x:Type ListBox}">
                <Setter Property="ScrollViewer.CanContentScroll" Value="True"></Setter>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBox}">
                            <ScrollViewer x:Name="ScrollViewer" CanContentScroll="True">
                                <ItemsPresenter></ItemsPresenter>
                            </ScrollViewer>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Geometry x:Key="Icon_Filter">
                M608 864C588.8 864 576 851.2 576 832L576 448c0-6.4 6.4-19.2 12.8-25.6L787.2 256c6.4-6.4 6.4-19.2 0-19.2 0-6.4-6.4-12.8-19.2-12.8L256 224c-12.8 0-19.2 6.4-19.2 12.8 0 6.4-6.4 12.8 6.4 19.2l198.4 166.4C441.6 428.8 448 441.6 448 448l0 256c0 19.2-12.8 32-32 32S384 723.2 384 704L384 460.8 198.4 307.2c-25.6-25.6-32-64-19.2-96C185.6 179.2 217.6 160 256 160L768 160c32 0 64 19.2 76.8 51.2 12.8 32 6.4 70.4-19.2 89.6l-192 160L633.6 832C640 851.2 627.2 864 608 864z
            </Geometry>
            <ContextMenu x:Key="queryConditionMenu" MouseLeave="ContextMenu_MouseLeave" MenuItem.Click="ContextMenu_Click">
                <MenuItem FontSize="12" Header="等于" Tag="Equal"></MenuItem>
                <MenuItem FontSize="12" Header="不等于"  Tag="NotEqual"></MenuItem>
                <MenuItem FontSize="12" Header="开头"  Tag="Begin"></MenuItem>
                <MenuItem FontSize="12" Header="结尾"  Tag="End"></MenuItem>
                <MenuItem FontSize="12" Header="包含"  Tag="In"></MenuItem>
                <MenuItem FontSize="12" Header="不包含"  Tag="NotIn"></MenuItem>
            </ContextMenu>
        </ResourceDictionary>

    </Window.Resources>
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <DataGrid Grid.Row="1" x:Name="dgStudents" ItemsSource="{Binding Source={StaticResource ItemsSource} }" AutoGenerateColumns="False"
                              CanUserReorderColumns="True" CanUserDeleteRows="False" CanUserAddRows="False" HeadersVisibility="Column"
                              CanUserSortColumns="True"
                              VirtualizingPanel.VirtualizationMode="Recycling"
                              EnableColumnVirtualization="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True" GridLinesVisibility="All" RowHeight="25"
                              SelectionUnit="FullRow" SelectionMode="Single" IsReadOnly="True" FontSize="12"
                              SelectedIndex="{Binding SelectTaskItemIndex}" SelectedItem="{Binding SelectTaskItem}"
                              CanUserResizeColumns="True">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Id}" Header="Id" Width="*">

                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding No}" Width="*">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="学号" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="No"></TextBlock>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Name}" Width="*">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="姓名" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="Name"></TextBlock>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <DataGridTextColumn Binding="{Binding Age}" Width="*">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="年龄" FontWeight="Regular" MouseRightButtonDown="TextBlock_MouseRightButtonDown" Tag="Age"></TextBlock>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Popup x:Name="popupNo" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
            <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
                        <TextBox Height="25" x:Name="txtNo" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="No" TextChanged="TextBox_TextChanged"></TextBox>
                        <Button x:Name="btnNoFilter"  Tag="No" ClickMode="Press" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                                <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
                       Height="12" Width="12" Stretch="Fill"></Path>
                                <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
                            </StackPanel>
                        </Button>
                    </StackPanel>
                    <ListBox x:Name="lbNos" ItemsSource="{Binding Source={StaticResource Nos}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

                    <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
                    <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
                </Grid>
            </Border>
        </Popup>
        <Popup x:Name="popupName" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
            <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
                        <TextBox Height="25" x:Name="txtName" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="Name" TextChanged="TextBox_TextChanged"></TextBox>
                        <Button x:Name="btnNameFilter"  Tag="Name" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                                <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
                       Height="12" Width="12" Stretch="Fill"></Path>
                                <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
                            </StackPanel>
                        </Button>
                    </StackPanel>
                    <ListBox x:Name="lbNames" ItemsSource="{Binding Source={StaticResource Names}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

                    <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
                    <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
                </Grid>
            </Border>
        </Popup>
        <Popup x:Name="popupAge" Width="135" MaxHeight="500" Height="Auto" PopupAnimation="Slide" AllowsTransparency="False" MouseLeave="popup_MouseLeave">
            <Border BorderBrush="LightBlue" BorderThickness="1" Padding="5" Background="AliceBlue">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Orientation="Horizontal">
                        <TextBox Height="25" x:Name="txtAge" MinWidth="60" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Tag="Age" TextChanged="TextBox_TextChanged"></TextBox>
                        <Button x:Name="btnAgeFilter"  Tag="Age" Click="ButtonFilter_Click" ContextMenu="{StaticResource queryConditionMenu}">
                            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                                <Path Data="{StaticResource Icon_Filter}" Stroke="Gray" StrokeThickness="1"
                       Height="12" Width="12" Stretch="Fill"></Path>
                                <TextBlock Margin="2,0" Text="筛选" FontSize="12"></TextBlock>
                            </StackPanel>
                        </Button>
                    </StackPanel>
                    <ListBox x:Name="lbAges" ItemsSource="{Binding Source={StaticResource Ages}}" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.IsVirtualizing="True" Style="{StaticResource ListBoxStyle}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <CheckBox Content="{Binding FilterText}" IsChecked="{Binding IsChecked}"></CheckBox>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>

                    <Button Tag="No" Content="取消" Width="60" HorizontalAlignment="Left" Grid.Row="2" Grid.Column="0" Click="btnCancel_Click"></Button>
                    <Button Content="确定" Width="60" HorizontalAlignment="Right" Grid.Row="2" Grid.Column="1" Click="btnOk_Click"></Button>
                </Grid>
            </Border>
        </Popup>

        <Popup x:Name="popupNoMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
            <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition></ColumnDefinition>
                        <ColumnDefinition></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
                        <TextBlock Text="学号" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combNoMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtNoMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0"  Grid.ColumnSpan="2">
                        <RadioButton x:Name="rbNoAnd" Content="与" IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                        <RadioButton x:Name="rbNoOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0"  Grid.ColumnSpan="2">
                        <TextBlock Text="学号" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combNoMenu2" Height="28" Margin="4" Width="100" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtNoMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <Button Tag="No" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
                    <Button Tag="No" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
                </Grid>
            </Border>
        </Popup>
        <Popup x:Name="popupNameMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
            <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
                        <TextBlock Text="姓名" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combNameMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtNameMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
                        <RadioButton x:Name="rbNameAnd" Content="与" IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                        <RadioButton x:Name="rbNameOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
                        <TextBlock Text="姓名" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combNameMenu2" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtNameMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <Button Tag="Name" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
                    <Button Tag="Name" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
                </Grid>
            </Border>
        </Popup>
        <Popup x:Name="popupAgeMenu" Width="300" MaxHeight="500" Height="200" PopupAnimation="Slide" AllowsTransparency="False" Tag="">
            <Border BorderThickness="1" BorderBrush="Beige" Padding="15" Background="AliceBlue">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                        <RowDefinition Height="Auto"></RowDefinition>
                    </Grid.RowDefinitions>
                    <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
                        <TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combAgeMenu1" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtAgeMenu1" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="0">
                        <RadioButton x:Name="rbAgeAnd" Content="与"  IsChecked="True" Margin="4" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                        <RadioButton x:Name="rbAgeOr" Content="或" Background="AliceBlue" VerticalAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Row="2" Grid.Column="0">
                        <TextBlock Text="年龄" VerticalAlignment="Center"></TextBlock>
                        <ComboBox x:Name="combAgeMenu2" Height="28" Width="100" Margin="4" VerticalContentAlignment="Center">
                            <ComboBoxItem Content="等于" ></ComboBoxItem>
                            <ComboBoxItem Content="不等于"></ComboBoxItem>
                            <ComboBoxItem Content="开头"></ComboBoxItem>
                            <ComboBoxItem Content="结尾"></ComboBoxItem>
                            <ComboBoxItem Content="包含"></ComboBoxItem>
                            <ComboBoxItem Content="不包含"></ComboBoxItem>
                        </ComboBox>
                        <TextBox x:Name="txtAgeMenu2" Height="28" Width="100" VerticalContentAlignment="Center"></TextBox>
                    </StackPanel>
                    <Button Tag="Age" Content="取消" Width="100" Height="28" HorizontalAlignment="Left" Grid.Row="3" Grid.Column="0" Click="btnCancelFilter_Click"></Button>
                    <Button Tag="Age" Content="确定" Width="100" Height="28" HorizontalAlignment="Right" Grid.Row="3" Grid.Column="1" Click="btnOkFilter_Click"></Button>
                </Grid>
            </Border>
        </Popup>
    </Grid>
</Window>

2. 业务逻辑【MainWindowViewModel】

业务逻辑处理主要复责数据初始化等业务相关内容,和UI无关,如下所示:

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DemoDataGrid
{
    public class MainWindowViewModel:ObservableObject
    {
        #region 属性及构造函数

        private List<Student> students;

        public List<Student> Students
        {
            get { return students; }
            set { SetProperty(ref students, value); }
        }

        private List<FilterInfo> names;

        public List<FilterInfo> Names
        {
            get { return names; }
            set { SetProperty(ref names, value); }
        }

        private List<FilterInfo> nos;

        public List<FilterInfo> Nos
        {
            get { return nos; }
            set {SetProperty(ref nos , value); }
        }

        private List<FilterInfo> ages;

        public List<FilterInfo> Ages
        {
            get { return ages; }
            set {SetProperty(ref ages , value); }
        }



        public MainWindowViewModel()
        {
            this.Students= new List<Student>();
            for (int i = 0; i < 20; i++) {
                this.Students.Add(new Student()
                {
                    Id = i,
                    Name = $"张{i}牛",
                    Age = (i % 10) + 10,
                    No = i.ToString().PadLeft(4, '0'),
                });
            }
            this.Nos= new List<FilterInfo>();
            this.Names= new List<FilterInfo>();
            this.Ages= new List<FilterInfo>();
            this.Students.ForEach(s => {
                this.Nos.Add(new FilterInfo() { FilterText=s.No,IsChecked=false });
                this.Names.Add(new FilterInfo() { FilterText = s.Name, IsChecked = false });
                this.Ages.Add(new FilterInfo() { FilterText = s.Age.ToString(), IsChecked = false });
            });
            this.Ages=this.Ages.Distinct().ToList();//去重
        }

        #endregion


    }
}

3. 筛选功能实现【MainWindow.xaml.cs】

本示例为了简化实现,筛选功能处理主要在cs后端实现,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DemoDataGrid
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowViewModel viewModel;

        public MainWindow()
        {
            InitializeComponent();
            viewModel = new MainWindowViewModel();
            this.DataContext = viewModel;
        }


        #region 筛选

        private void TextBlock_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (sender != null && sender is TextBlock)
            {
                var textBlock = sender as TextBlock;
                var tag = textBlock.Tag.ToString();
                var pop = this.FindName($"popup{tag}");
                if (pop != null)
                {
                    var popup = pop as System.Windows.Controls.Primitives.Popup;
                    if (popup != null)
                    {
                        popup.IsOpen = true;
                        popup.PlacementTarget = textBlock;
                        popup.Placement = System.Windows.Controls.Primitives.PlacementMode.RelativePoint;
                        popup.VerticalOffset = 10;
                        popup.HorizontalOffset = 10;
                    }
                }
            }
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox textBox = e.OriginalSource as TextBox;
            var tag = textBox.Tag;//条件
            var text = textBox.Text;
            if (tag != null)
            {
                if (tag.ToString() == "No")
                {
                    Filter(this.lbNos.ItemsSource, this.txtNo.Text);
                }
                if (tag.ToString() == "Name")
                {
                    Filter(this.lbNames.ItemsSource, this.txtName.Text);
                }
                if (tag.ToString() == "Age")
                {
                    Filter(this.lbAges.ItemsSource, this.txtAge.Text);
                }
            }

        }

        private void Filter(object source, string filter)
        {
            var cv = CollectionViewSource.GetDefaultView(source);
            if (cv != null && cv.CanFilter)
            {
                cv.Filter = new Predicate<object>((obj) => {
                    bool flag = true;
                    var t = obj as FilterInfo;
                    if (t != null)
                    {
                        flag = t.FilterText.Contains(filter);
                    }
                    return flag;
                });
            }
        }

        private void popup_MouseLeave(object sender, MouseEventArgs e)
        {
            var popup = e.OriginalSource as System.Windows.Controls.Primitives.Popup;
            var showContext = (this.FindResource("queryConditionMenu") as ContextMenu)?.IsOpen;
            if (popup != null && showContext==false)
            {
                popup.IsOpen = false;
            }
        }

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            var btn = e.OriginalSource as Button;
            if (btn != null)
            {
                var tag = btn.Tag;
                if (tag.ToString() == "No")
                {
                    ClearFilter(this.txtNo, this.viewModel.Nos);
                }
                if (tag.ToString() == "Name")
                {
                    ClearFilter(this.txtName, this.viewModel.Names);

                }
                if (tag.ToString() == "Age")
                {
                    ClearFilter(this.txtAge, this.viewModel.Ages);
                }
                FilterTask();//清除以后,重新刷新
            }
        }

        private void ClearFilter(TextBox textBox, List<FilterInfo> collection)
        {
            textBox.Clear();
            foreach (var f in collection)
            {
                f.IsChecked = false;
            }
        }

        private void btnOk_Click(object sender, RoutedEventArgs e)
        {
            //
            FilterTask();
        }


        private void FilterTask()
        {
            var cv = CollectionViewSource.GetDefaultView(this.dgStudents.ItemsSource);
            if (cv != null && cv.CanFilter)
            {
                cv.Filter = new Predicate<object>((obj) =>
                {
                    bool flag = true;
                    var t = obj as Student;
                    if (t != null)
                    {
                        var nos = this.viewModel.Nos.Where(r => r.IsChecked == true).ToList();
                        var names = this.viewModel.Names.Where(r => r.IsChecked == true).ToList();
                        var ages = this.viewModel.Ages.Where(r => r.IsChecked == true).ToList();
                        if (nos.Count() > 0)
                        {
                            flag = flag && nos.Select(r => r.FilterText).Contains(t.No);
                        }
                        if (names.Count() > 0)
                        {
                            flag = flag && names.Select(r => r.FilterText).Contains(t.Name);
                        }
                        if (ages.Count() > 0)
                        {
                            flag = flag && ages.Select(r => r.FilterText).Contains(t.Age.ToString());
                        }
                    }
                    return flag;
                });
            }
        }

        #endregion

        private List<string> condition = new List<string>() { "Equal", "NotEqual", "Begin", "End", "In", "NotIn" };

        private void ButtonFilter_Click(object sender, RoutedEventArgs e)
        {
            var btn = e.OriginalSource as Button;
            if (btn != null)
            {
                var tag = btn.Tag;
                var popup = this.FindName($"popup{tag}") as System.Windows.Controls.Primitives.Popup;
                if (popup != null)
                {
                    popup.IsOpen = true;
                }
                if (btn.ContextMenu.IsOpen)
                {
                    btn.ContextMenu.IsOpen = false;
                }
                else
                {
                    btn.ContextMenu.Tag = tag;
                    btn.ContextMenu.Width = 100;
                    btn.ContextMenu.Height = 150;
                    btn.ContextMenu.IsOpen = true;
                    btn.ContextMenu.PlacementTarget = btn;
                    btn.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
                }
            }
        }

        private void ContextMenu_MouseLeave(object sender, MouseEventArgs e)
        {
            var menu = e.OriginalSource as ContextMenu;
            if (menu != null)
            {
                menu.IsOpen = false;
            }
        }

        private void ContextMenu_Click(object sender, RoutedEventArgs e)
        {
            var contextMenu = sender as ContextMenu;
            if (contextMenu == null)
            {
                return;
            }
            var menuItem = e.OriginalSource as MenuItem;
            if (menuItem == null)
            {
                return;
            }
            var tag1 = contextMenu.Tag.ToString();//点击的哪一个按钮
            var tag2 = menuItem.Tag.ToString();//点击的是哪一个菜单
            var pop = this.FindName($"popup{tag1}Menu");
            var comb = this.FindName($"comb{tag1}Menu1");
            HideParentPopup(tag1);//隐藏父Popup
            if (comb != null)
            {
                var combMenu = comb as ComboBox;
                combMenu.SelectedIndex = condition.IndexOf(tag2);
            }
            if (pop != null)
            {
                var popup = pop as System.Windows.Controls.Primitives.Popup;
                popup.IsOpen = true;
                popup.PlacementTarget = dgStudents;
                popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Center;
            }
        }

        private void btnCancelFilter_Click(object sender, RoutedEventArgs e)
        {
            if (sender == null)
            {
                return;
            }
            var btn = sender as System.Windows.Controls.Button;
            if (btn != null)
            {
                var tag = btn.Tag.ToString();
                HidePopupMenu(tag);//隐藏Popup控件
                if (tag == "No")
                {
                    ClearMenuFilter(this.txtNoMenu1, this.txtNoMenu2);
                }
                if (tag == "Name")
                {
                    ClearMenuFilter(this.txtNameMenu1, this.txtNameMenu2);
                }
                if (tag == "Age")
                {
                    ClearMenuFilter(this.txtAgeMenu1, this.txtAgeMenu2);
                }
                FilterMenuTask();
            }
        }


        private void btnOkFilter_Click(object sender, RoutedEventArgs e)
        {
            if (sender == null)
            {
                return;
            }
            var btn = sender as System.Windows.Controls.Button;
            if (btn != null)
            {
                var tag = btn.Tag.ToString();
                HidePopupMenu(tag);
                FilterMenuTask();
            }
        }

        /// <summary>
        /// 隐藏父Popup
        /// </summary>
        /// <param name="tag"></param>
        private void HideParentPopup(string tag)
        {
            //点击右键菜单时,隐藏父Popup控件
            if (tag == "No")
            {
                this.popupNo.IsOpen = false;
            }
            if (tag == "Name")
            {
                this.popupName.IsOpen = false;
            }
            if (tag == "Age")
            {
                this.popupAge.IsOpen = false;
            }
        }

        /// <summary>
        /// 隐藏菜单弹出的Popup控件
        /// </summary>
        /// <param name="tag"></param>
        private void HidePopupMenu(string tag)
        {
            var pop = this.FindName($"popup{tag}Menu");
            if (pop != null)
            {
                var popup = pop as System.Windows.Controls.Primitives.Popup;
                popup.IsOpen = false;
            }
        }

        /// <summary>
        /// 清除菜单中的文本过滤条件
        /// </summary>
        /// <param name="txt1"></param>
        /// <param name="txt2"></param>
        private void ClearMenuFilter(TextBox txt1, TextBox txt2)
        {
            txt1?.Clear();
            txt2?.Clear();
        }

        /// <summary>
        ///
        /// </summary>
        private void FilterMenuTask()
        {
            var cv = CollectionViewSource.GetDefaultView(this.dgStudents.ItemsSource);
            if (cv != null && cv.CanFilter)
            {
                cv.Filter = new Predicate<object>((obj) =>
                {
                    bool flag = true;
                    var t = obj as Student;
                    if (t != null)
                    {
                        string noText1 = this.txtNoMenu1.Text.Trim();
                        string noText2 = this.txtNoMenu2.Text.Trim();
                        int noConditionType1 = this.combNoMenu1.SelectedIndex;
                        int noConditionType2 = this.combNoMenu2.SelectedIndex;
                        string nameText1 = this.txtNameMenu1.Text.Trim();
                        string nameText2 = this.txtNameMenu2.Text.Trim();
                        int nameConditionType1 = this.combNameMenu1.SelectedIndex;
                        int nameConditionType2 = this.combNameMenu2.SelectedIndex;
                        string ageText1 = this.txtAgeMenu1.Text.Trim();
                        string ageText2 = this.txtAgeMenu2.Text.Trim();
                        int ageConditionType1 = this.combAgeMenu1.SelectedIndex;
                        int ageConditionType2 = this.combAgeMenu2.SelectedIndex;
                        bool? isNoAnd = this.rbNoAnd.IsChecked;
                        bool? isNoOr = this.rbNoOr.IsChecked;
                        bool? isNameAnd = this.rbNameAnd.IsChecked;
                        bool? isNameOr = this.rbNameOr.IsChecked;
                        bool? isAgeAnd = this.rbAgeAnd.IsChecked;
                        bool? isAgeOr = this.rbAgeOr.IsChecked;
                        bool flagNo = true;
                        bool flagName = true;
                        bool flagAge = true;
                        flagNo = CheckConditions(noConditionType1, noConditionType2, t.No, noText1, noText2, isNoAnd, isNoOr);
                        flagName = CheckConditions(nameConditionType1, nameConditionType2, t.Name, nameText1, nameText2, isNameAnd, isNameOr);
                        flagAge = CheckConditions(ageConditionType1, ageConditionType2, t.Age.ToString(), ageText1, ageText2, isAgeAnd, isAgeOr);
                        flag = flag && flagNo && flagName && flagAge;
                    }
                    return flag;
                });
            }
        }

        private bool CheckConditions(int conditionIndex1, int conditionIndex2, string source, string condition1, string condition2, bool? isAnd, bool? isOr)
        {
            bool flag = true;
            bool flag1 = true;
            bool flag2 = true;
            if (!string.IsNullOrEmpty(condition1) && !string.IsNullOrWhiteSpace(condition1) && conditionIndex1 != -1)
            {
                flag1 = CheckCondition(conditionIndex1, source, condition1);
            }
            if (!string.IsNullOrEmpty(condition2) && !string.IsNullOrWhiteSpace(condition2) && conditionIndex2 != -1)
            {
                flag2 = CheckCondition(conditionIndex2, source, condition2);
            }
            if (isAnd == true)
            {
                flag = flag1 && flag2;
            }
            if (isOr == true)
            {
                flag = flag1 || flag2;
            }
            return flag;
        }

        private bool CheckCondition(int condtionIndex, string source, string condition)
        {
            bool flag = true;
            if (condtionIndex == 0)
            {
                flag = flag && source == condition;
            }
            if (condtionIndex == 1)
            {
                flag = flag && source != condition;
            }
            if (condtionIndex == 2)
            {
                flag = flag && source.StartsWith(condition);
            }
            if (condtionIndex == 3)
            {
                flag = flag && source.EndsWith(condition);
            }
            if (condtionIndex == 4)
            {
                flag = flag && source.Contains(condition);
            }
            if (condtionIndex == 5)
            {
                flag = flag && !source.Contains(condition);
            }
            return flag;
        }
    }
}

学号,姓名,年龄三列过滤列表绑定内容模型一致,为FilterInfo,如下所示:

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DemoDataGrid
{
    public class FilterInfo : ObservableObject
    {
        private string filterText;

        public string FilterText
        {
            get { return filterText; }
            set { SetProperty(ref filterText, value); }
        }

        private bool isChecked;

        public bool IsChecked
        {
            get { return isChecked; }
            set { SetProperty(ref isChecked, value); }
        }
    }
}

不足与思考

上述筛选实现方式,并非唯一实现,也并非最优实现,同样存在许多可以优化的地方。

在本示例中,存在许多冗余代码,如视图页面,对三列的弹出窗口,内容虽然相对统一,只是列名和绑定内容不同而已,却堆积了三大段代码,是否可以从控件模块或者数据模板的角度,进行简化呢?

筛选功能实现上,同样存在许多冗余代码,是否可以进行简化呢?以上是我们需要思考的地方,希望可以集思广益,共同学习,一起进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/378514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

唯品会财报:一面骄阳,一面寒霜

配图来自Canva可画 在互联网技术飞速发展、物流基础设施日益完善&#xff0c;以及消费者购物习惯不断改变等多重因素的共同影响下&#xff0c;电商行业实现了蓬勃发展。得益于此&#xff0c;电商行业也跑出了许多知名电商品牌&#xff0c;其中既有淘宝、京东、拼多多等综合型电…

SSRF漏洞原理、危害以及防御与修复

一、SSRF漏洞原理漏洞概述SSRF&#xff08;Server-side Request Forge&#xff0c;服务端请求伪造&#xff09;是一种由攻击者构造形成由服务端发起请求的安全漏洞。一般情况下&#xff0c;SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的&#xff0c;所…

Java开发 - Elasticsearch初体验

目录 前言 什么是es&#xff1f; 为什么要使用es&#xff1f; es查询的原理&#xff1f; es需要准备什么&#xff1f; es基本用法 创建工程 添加依赖 创建操作es的文件 使用ik分词插件 Spring Data 项目中引入Spring Data 添加依赖 添加配置 创建操作es的业务逻…

深度学习常用的激活函数总结

各种激活函数总结 目录一、sigmoid二、tanh![在这里插入图片描述](https://img-blog.csdnimg.cn/a0d92552edf8464db793fdd2f2b75cb5.png)三、ReLU系列1.原始ReLU2.ReLU改进&#xff1a;Leaky ReLU四、swish五、GeLU一、sigmoid 优点&#xff1a; 1.可以将任意范围的输出映射到 …

高通平台开发系列讲解(Sensor篇)AlsPs的工作原理及介绍

文章目录 一、什么是ALS?二、什么是距感(PS)?三、AlsPs的工作原理四、AlsPs的特性五、距感的校准参数说明六、光感的校准参数说明沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇文章将介绍 AlsPs 的工作原理及介绍。 一、什么是ALS? 光感的英文叫做Ambient Li…

算法小抄2-刷题中Python的常用语法

标准数据类型 不可变数据类型: Number String Tuple 可变数据类型:List Dictionary Set 关于为什么会分成可变和不可变最后会讲到哦 Number Number支持int,float,bool,complex四种,其中int范围小且必须为整数,float范围较大,可以是是小数,bool值表示是否,complex为复数,赋值…

20- widedeep及函数式构建模型 (TensorFlow系列) (深度学习)

知识要点 wide&deep: 模型构建中, 卷积后数据和原始数据结合进行输出.fetch_california_housing&#xff1a;加利福尼亚的房价数据&#xff0c;总计20640个样本&#xff0c;每个样本8个属性表示&#xff0c;以及房价作为target&#xff0c;所有属性值均为number&#xff0…

网上医疗预约挂号系统

技术&#xff1a;Java、JSP等摘要&#xff1a;网上医疗预约挂号系统是主要是对居民的保健、护理、疾病预防等健康信息实行有效的预约挂号管理。医疗机构为居民建立完整的健康档案&#xff0c;安排体检以及实施免疫等预防措施。而基于Web的远程保健平台以网上医疗预约挂号系统为…

基于OMAPL138+FPGA核心板多核软件开发组件MCSDK开发入门(上)

本文测试板卡为创龙科技 SOM-TL138F 是一款基于 TI OMAP-L138(定点/浮点 DSP C674x + ARM9)+ 紫光同创 Logos/Xilinx Spartan-6 低功耗 FPGA 处理器设计的工业级核心板。核心板内部OMAP-L138 与 Logos/Spartan-6 通过 uPP、EMIFA、I2C 通信总线连接,并通过工业级 B2B连接器引…

分布式任务处理

分布式任务处理 1. 什么是分布式任务调度 视频上传成功需要对视频的格式进行处理&#xff0c;如何用Java程序对视频进行处理呢&#xff1f;这里有一个关键的需求就是当视频比较多的时候我们如何可以高效处理。 如何去高效处理一批任务呢&#xff1f; 1、多线程 多线程是充…

IDEA社区版环境配置和插件安装

一、Java环境安装 1.1 下载openjdk环境安装包 可以进华为镜像站进行下载。参考链接&#xff1a; Index of openjdk-local https://repo.huaweicloud.com/openjdk/ 1.2 配置Java环境 解压缩openjdk到任意路径&#xff0c;建议路径不要有中文。然后把路径的bin文件&#xff0…

新手小白亚马逊注册最全教程在此

自从龙哥出了Walmart注册教程后&#xff0c;立刻看到私信有兄弟问这个亚马逊的注册。亚马逊是跨境电商的鼻祖&#xff0c;资源和流量是无容置疑的。作为一个重产品&#xff0c;轻店铺的平台&#xff0c;是比较看中客户体验的&#xff0c;要求卖家要有好的资源。而且亚马逊有强大…

02-MyBatis查询-

文章目录Mybatis CRUD练习1&#xff0c;配置文件实现CRUD1.1 环境准备Debug01: 别名mybatisx报错1.2 查询所有数据1.2.1 编写接口方法1.2.2 编写SQL语句1.2.3 编写测试方法1.2.4 起别名解决上述问题1.2.5 使用resultMap解决上述问题1.2.6 小结1.3 查询详情1.3.1 编写接口方法1.…

改进YOLOv7-Tiny系列:首发改进结合BiFPN结构的特征融合网络,网络融合更多有效特征,高效涨点

💡该教程为改进进阶指南,属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 内容出品:CSDN博客独家更新 @CSDN芒果汁没有芒果 💡本篇文章 基于 YOLOv5、YOLOv7芒果改进YOLO系列:芒果改进YOLOv7-Tiny系列:首发改进结合BiFPN结…

深度学习笔记:不同的反向传播迭代方法

1 随机梯度下降法SGD 随机梯度下降法每次迭代取梯度下降最大的方向更新。这一方法实现简单&#xff0c;但是在很多函数中&#xff0c;梯度下降的方向不一定指向函数最低点&#xff0c;这使得梯度下降呈现“之”字形&#xff0c;其效率较低 class SGD:"""随机…

springsecurity开启方法级的授权源码分析

1、话不多说&#xff0c;先说使用步骤然后分析源码&#xff1a;首先使用 EnableMethodSecurity 注解开启方法级别的权限认证### 使用该注解开启方法级权限鉴定 EnableMethodSecurity使用了方法权限注解开启了方法级的权限鉴定之后&#xff0c;就可以使用如下注解直接在控制器上…

【微信小程序】-- WXSS 模板样式- rpx import (十三)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

OpenCV入门(一)Python环境的搭建

OpenCV入门&#xff08;一&#xff09;Python环境的搭建 因为有点Python基础&#xff0c;并且Python是比较好入门的编程语言&#xff0c;所以&#xff0c;机器视觉后面打算在Python这个平台下进行。 Windows平台OpenCV的Python开发环境搭建 1、Python 的下载与安装 Python是…

Unity UGUI 拖拽组件

效果展示 使用方式 拖到图片上即可用 父节点会约束它的活动范围哦~ 父节点会约束它的活动范围哦~ 父节点会约束它的活动范围哦~ 源码 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems;/// <summary> /…

2023年蜂巢科技最新面试题

2023年蜂巢科技最新面试题 bio与nio的区别 bio同步阻塞io&#xff1a;在此种⽅式下&#xff0c;⽤户进程在发起⼀个IO操作以后&#xff0c;必须等待IO操作的完成&#xff0c;只有当真正完成了IO操作以后&#xff0c;⽤户进程才能运⾏。JAVA传统的IO模型属于此种⽅式&#xff0…