根据TextBoxes到DataGrid(ItemCollectionViewSource)中的几个值应用筛选器



我为数据库制作了一个工具,用于显示具有特定筛选选项的项目。然而,在阅读了更多关于WPF和C#的内容之后。我用过这个https://www.codeproject.com/Articles/683429/Guide-to-WPF-DataGrid-formatting-using-bindings修改我的应用程序以处理ItemCollectionViewSource的教程

我以前用过这个过滤:

public void FilterSetup()
{
try
{
string qry = null;
_conditions["name"] = null;
if (!string.IsNullOrEmpty(BusinessIDSearch.Text))
{
qry = string.Format("LY Like '{0}%'", BusinessIDSearch.Text);
}
if (!string.IsNullOrEmpty(NameSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("HAKUNIMI Like '%{0}%'", NameSearch.Text);
}
if (!string.IsNullOrEmpty(GroupSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("KONSERNI Like '{0}%'", GroupSearch.Text);
}
if (!string.IsNullOrEmpty(LiinosIDSearch.Text))
{
if (!string.IsNullOrEmpty(qry))
qry += " AND ";
qry += string.Format("YRNRO Like '{0}%'", LiinosIDSearch.Text);
}
_conditions["name"] = qry;
UpdateFilter();
//LiinosFICount.Content = DataGrid1.Items.Count;
}
catch (Exception)
{
throw;
}
}

然后这个:

private void UpdateFilter()
{
try
{
var activeConditions = _conditions.Where(c => c.Value != null).Select(c => "(" + c.Value + ")");
DataView dv = DataGrid1.ItemsSource as DataView;
dv.RowFilter = string.Join(" AND ", activeConditions);
}
catch (Exception)
{
//MessageBox.Show(ex.Message);
}
}

然而,我现在似乎需要使用ItemCollectionViewSource的另一种方法。

以下是文本框的XAML部分:

<TextBox Style="{StaticResource TextBox_Style}" x:Name="GroupSearch" HorizontalAlignment="Left" Margin="414,121,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="90" Height="20" TextChanged="GroupSearch_TextChanged"/>
<TextBox Style="{StaticResource TextBox_Style}" x:Name="NameSearch" HorizontalAlignment="Left" Margin="130,121,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="279" Height="20" TextChanged="NameSearch_TextChanged"/>
<TextBox Style="{StaticResource TextBox_Style}" Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}" x:Name="LiinosIDSearch" HorizontalAlignment="Left" Margin="20,121,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="105" Height="20"/>
<TextBox Style="{StaticResource TextBox_Style}" x:Name="BusinessIDSearch" HorizontalAlignment="Left" Margin="509,121,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="192" Height="20" TextChanged="BusinessIDSearch_TextChanged"/>

以下是DataGrid:的XAML

<DataGrid Margin="0,146,0,0" Background="{x:Null}" BorderBrush="{x:Null}"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" IsReadOnly="True" 
HorizontalGridLinesBrush="#FF377A6C" VerticalGridLinesBrush="#FF377A6C" 
DataContext="{StaticResource ItemCollectionViewSource}"
ItemsSource="{Binding}"
AutoGenerateColumns="False" FontFamily="Arial Nova" Foreground="White" >
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" >
<Setter Property="Background" Value="{Binding YRNRO, Converter={StaticResource LiinosIDToBackgroundConverter}}" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Resources>
<Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#377A6C" />
<Setter Property="Foreground" Value="White" />
<Setter Property="MinHeight" Value="20" />
</Style>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" 
Color="#5AC37E"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding YRNRO}">
<DataGridTextColumn.Header>
<TextBlock Text="LIINOS ID" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding HAKUNIMI}">
<DataGridTextColumn.Header>
<TextBlock Text="SEARCH NAME" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding KONSERNI}">
<DataGridTextColumn.Header>
<TextBlock Text="GROUP" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding LY}">
<DataGridTextColumn.Header>
<TextBlock Text="BUSINESS ID" FontWeight="Bold" TextAlignment="Left"/>
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>

我尝试了好几个教程,但都没有成功。有人有任何类型的教程可以建议,或者可能提供一个我也可以实现到其他TextBox的解决方案的答案吗?棘手的部分是,我有几个TextBoxes,我需要根据TextBoxes中的值组合过滤查询。

正如你所看到的,我已经尝试在这里应用绑定:

<TextBox Style="{StaticResource TextBox_Style}" Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}" x:Name="LiinosIDSearch" HorizontalAlignment="Left" Margin="20,121,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="105" Height="20"/>

我从一些教程中得到了这个,并试图根据我的需求进行修改,但没有成功:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Data;
namespace Liinos_inspector_FilterTest
{
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _filter1 = "";
private string _filter2 = "";
private string _filter3 = "";
public ViewModel()
{
var List = MainProcess.CustomersInLiinos.AsEnumerable()
.GroupBy(x => x.Field<string>("HAKUNIMI"))
.Where(x => x.Count() > 1)
.SelectMany(x => x)
.ToList();
//ItemList = new ObservableCollection<Items>(List);
ItemView = (CollectionView)CollectionViewSource.GetDefaultView(List);
ItemView.Filter = TextFilter;
}
private bool TextFilter(object obj)
{
var data = obj as Items;
if (data != null)
{
return data.Text1.StartsWith(_filter1) && data.Text2.StartsWith(_filter2) && data.Text3.StartsWith(_filter3);
}
return false;
}
private void NotifyPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public ObservableCollection<Items> ItemList { get; set; }
public CollectionView ItemView { get; set; }
public string Filter1
{
get { return _filter1; }
set
{
_filter1 = value;
NotifyPropertyChanged("Filter1");
ItemView.Refresh();
}
}
public string Filter2
{
get { return _filter2; }
set
{
_filter2 = value;
NotifyPropertyChanged("Filter2");
ItemView.Refresh();
}
}
public string Filter3
{
get { return _filter3; }
set
{
_filter3 = value;
NotifyPropertyChanged("Filter3");
ItemView.Refresh();
}
}
}
public class Items
{
public string Text1 { get; set; }
public string Text2 { get; set; }
public string Text3 { get; set; }
}
}

编辑:

我正在点击DataGrid:按钮加载数据

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
if (MainProcess.CheckForVPNInterface() == true)
{
if (MainProcess.Customers != null)
{
ProgressBar.IsIndeterminate = true;
CollectionViewSource itemCollectionViewSource;
itemCollectionViewSource = (CollectionViewSource)(FindResource("ItemCollectionViewSource"));
itemCollectionViewSource.Source = await LoadMainTableDataAsync();
ProgressBar.IsIndeterminate = false;
}
}
else
{
string caption = "VPN connection missing";
MessageBox.Show("Please, check your VPN connection!", caption,
MessageBoxButton.OK,
MessageBoxImage.Exclamation);
}
}

编辑2:

这是我一直在使用的LoadMainTableDataAsync方法:

public Task<DataView> LoadMainTableDataAsync()
{
return Task.Run(() =>
{
MainProcess.MergedTable();
return MainProcess.Customers.DefaultView;
});
}

以下是数据表的合并:

public static DataTable Customers = new DataTable();
public static void MergedTable()
{
var t1 = ConnectAndRetriveDatatatableS(); // t1
var t2 = ConnectAndRetriveDatatatableF(); // t2
Customers = t1.Copy();
Customers.Merge(t2);
}

您不需要CollectionViewSource来过滤集合。只需绑定到视图模型的集合即可。在WPF中,集合通过罩子下的ICollectionsView消耗。每个集合都返回一个默认视图。控件在此视图上自动运行。若要更改顺序、分组或筛选,请修改集合的当前视图,而不是实际的集合实例。也不要将DataContext明确设置为CollectionViewSource。直接绑定到它。

附带说明一下,由于您绑定到模型项,Items应该实现INotifyPropertyChanged,否则会引发内存泄漏。

不要在视图模型中处理ProgressBar。设置一个bool属性并将其绑定到ProgressBar.Visibility

不要为了处理异常而在视图模型中显示MessageBox或任何用户对话框。相反,抛出一个有意义的完全自定义异常或包装器异常(将原始异常作为内部异常(,并在视图中处理它,例如通过显示交互对话框。

不要处理视图中的数据库或任何其他数据(模型(访问。相反,实现ICommand并将其分配给按钮以替换事件处理程序,并在视图模型中执行操作。有关RelayCommand的简单实现,请参阅Microsoft文档:中继命令逻辑。

这是一个如何使用集合的默认ICollectionView过滤集合的基本示例,其中包含了建议的改进。您需要根据自己的需求调整实际的过滤逻辑:

VpnInterfaceException.cs

class VpnInterfaceException : Exception
{
public VpnInterfaceException(string message) : base(message)
{
}
public VpnInterfaceException(string message, Exception innerException) : base(message, innerException)
{
}
}

项目.cs

class Item : INotifyPropertyChanged
{
private string text;   
public string Text 
{
get => this.text;
set 
{ 
this.text = value; 
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<Item> Items { get; set; }
public ICommand LoadMainTableDataCommand => new RelayCommand(ExecuteLoadMainTableDataAsync);
// Binding source for the TextBox
private string searchKey;   
public string SearchKey
{
get => this.searchKey;
set 
{ 
this.searchKey = value; 
OnPropertyChanged();  

// Refresh the ICollectionView to update the filter expression
CollectionViewSource.GetDefaultView(this.Items).Refresh();
}
}
private bool hasProgress;   
public bool HasProgress
{
get => this.hasProgress;
set 
{ 
this.hasProgress = value; 
OnPropertyChanged();
}
}
public ViewModel()
{
this.Items = new ObservableCollection<Item>();
EnableItemsFiltering();
}
public void EnableItemsFiltering()
{
// Assign the filter expression which is executed when items are added 
// or the 'ICollectionView.Refresh()'  was called
CollectionViewSource.GetDefaultView(this.Items).Filter = FilterPredicate;
}
// The filter expression.
// Returns 'true' to include the current item.
private bool FilterPredicate(object item) 
=> string.IsNullOrWhiteSpace(this.SearchKey) 
|| ((item as Item)?.Text.StartsWith(this.SearchKey, StringComparison.OrdinalIgnoreCase) ?? false);
private async Task ExecuteLoadMainTableDataAsync(object commandParameter)
{
if (MainProcess.CheckForVPNInterface())
{
if (MainProcess.Customers != null)
{
this.HasProgress = true;
IEnumerable<Item> resultItems = await LoadMainTableDataAsync();
this.Items = new ObservableCollection<Item>(resultItems);
EnableItemsFiltering();
this.HasProgress = false;
}
}
else
{
// Throw an exception since the operation cannot be completed unexpectedly. 
// The view can catch this exception to execute the error handling.
throw new VpnInterfaceException("Please, check your VPN connection!");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

主窗口.xaml.cs

partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

// Handle specific view model exceptions for user interaction
this.Dispatcher.UnhandledException += (sender, args) =>
{
// Only handle selected exceptions, that can be handled through user interaction
if (args.Exception is VpnInterfaceException exception)
{
args.Handled = true;
string caption = "VPN connection missing";

// Convert exception message to user friendly message
MessageBox.Show(exception.Message, 
caption,
MessageBoxButton.OK, 
MessageBoxImage.Exclamation);
}
};
}
}

主窗口.xaml

<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>

<StackPanel>
<ProgressBar IsIndeterminate="True"
Visibility="{Binding HasProgress, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Command="{Binding LoadMainTableDataCommand}" 
Content="Load Data" />
<TextBox Text="{Binding SearchKey}" />
<DataGrid ItemsSource="{Binding Items}" />
<StackPanel>
</Window>

最新更新