UWP AdvancedCollectionView 过滤器不适用于字符串
UWP AdvancedCollectionView filter not working with strings
我有一个 AdvancedCollectionView 来自 Windows Community Toolkit 版本 6.1.1 并尝试使用它来过滤掉 2 个字符串属性。
我创建了一个简单的应用程序来重现该问题:https://github.com/touseefbsb/UWP-Filter-List
它有一个文本框,用于在项目的 StartNumber 和 EndNumber 属性之间进行过滤。
但是当我在其中输入文本“123”时,它在 ListView 中没有显示任何项目,而根据测试逻辑,它实际上应该只显示第一个项目。
代码
MainPage.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox
x:Name="SearchTicketBooksBox"
Width="300"
Header="Search"
TextChanged="SearchTicketBooks_TextChanged" />
<ListView
x:Name="TicketBooksListView"
Grid.Row="1"
Margin="4,0,0,0"
ItemsSource="{x:Bind ViewModel.TicketBooks}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="app1:TicketBookDto">
<StackPanel Margin="20">
<TextBlock Text="{x:Bind StartNumber}" />
<TextBlock Text="{x:Bind EndNumber}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel { get; }
public MainPage() { InitializeComponent(); ViewModel = new MainViewModel(); }
private void SearchTicketBooks_TextChanged(object sender, TextChangedEventArgs e)
{
if (ViewModel != null)
{
if (string.IsNullOrWhiteSpace(SearchTicketBooksBox.Text))
{
ViewModel.TicketBooks.Filter = _ => true;
}
else
{
ViewModel.TicketBooks.Filter = x => ((TicketBookDto)x).StartNumber == SearchTicketBooksBox.Text;
//{
// var startNumber = Convert.ToInt32(((TicketBookDto)x).StartNumber);
// var endNumber = Convert.ToInt32(((TicketBookDto)x).EndNumber);
// var searchText = Convert.ToInt32(SearchTicketBooksBox.Text);
// return searchText >= startNumber && searchText <= endNumber;
//};
}
}
}
private void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
ViewModel.TicketBooks.Add(new TicketBookDto { StartNumber = "123", EndNumber = "456" });
ViewModel.TicketBooks.Add(new TicketBookDto { StartNumber = "789", EndNumber = "987" });
}
}
MainViewModel
public class MainViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<TicketBookDto> _ticketBooksPrivate = new ObservableCollection<TicketBookDto>();
private AdvancedCollectionView ticketBooks;
public AdvancedCollectionView TicketBooks
{
get
{
if (ticketBooks is null)
{
ticketBooks = new AdvancedCollectionView(_ticketBooksPrivate, true);
ticketBooks.ObserveFilterProperty(nameof(TicketBookDto.StartNumber));
ticketBooks.ObserveFilterProperty(nameof(TicketBookDto.EndNumber));
}
return ticketBooks;
}
set => Set(ref ticketBooks, value);
}
#region INotifyStuff
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#endregion
}
TicketBookDto
public partial class TicketBookDto
{
public string StartNumber { get; set; }
public string EndNumber { get; set; }
}
I have commented out code of the actual logic I need in the filter, which is to show the list items only those who have the search number between their "StartNumber" and "EndNumber" properties. But for simplicity I am using a simple match to StartNumber logic to find out why it aint working. Also when I add a boolean property and simply filter using that property then it works fine, its just not working with these string properties.
恐怕你不能在TextChanged
事件中使用Filter
,请参考源代码here。
if (_filter != null)
{
for (var index = 0; index < _view.Count; index++)
{
var item = _view.ElementAt(index);
if (_filter(item))
{
continue;
}
RemoveFromView(index, item);
index--;
}
}
当您在 SerchBox 中输入文本时,如果文本不等于过滤器 属性,则该项目将为 RemoveFromView
。所以它会让下一个输入不生效。对于这种设计,我们建议您在输入完成后制作提交按钮来过滤数据。
并且如果您确实想在 TextChanged
中过滤 ,您可以在设置 Filter
委托之前调用 ViewModel.TicketBooks.Filter = _ => true;
重置视图方法如下。
private void SearchTicketBooks_TextChanged(object sender, TextChangedEventArgs e)
{
if (ViewModel != null)
{
if (string.IsNullOrWhiteSpace(SearchTicketBooksBox.Text))
{
ViewModel.TicketBooks.Filter = _ => true;
}
else
{ // reset the filter
ViewModel.TicketBooks.Filter = _ => true;
ViewModel.TicketBooks.Filter = x => ((TicketBookDto)x).EndNumber == SearchTicketBooksBox.Text;
}
}
}
我有一个 AdvancedCollectionView 来自 Windows Community Toolkit 版本 6.1.1 并尝试使用它来过滤掉 2 个字符串属性。
我创建了一个简单的应用程序来重现该问题:https://github.com/touseefbsb/UWP-Filter-List
它有一个文本框,用于在项目的 StartNumber 和 EndNumber 属性之间进行过滤。
但是当我在其中输入文本“123”时,它在 ListView 中没有显示任何项目,而根据测试逻辑,它实际上应该只显示第一个项目。
代码
MainPage.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBox
x:Name="SearchTicketBooksBox"
Width="300"
Header="Search"
TextChanged="SearchTicketBooks_TextChanged" />
<ListView
x:Name="TicketBooksListView"
Grid.Row="1"
Margin="4,0,0,0"
ItemsSource="{x:Bind ViewModel.TicketBooks}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="app1:TicketBookDto">
<StackPanel Margin="20">
<TextBlock Text="{x:Bind StartNumber}" />
<TextBlock Text="{x:Bind EndNumber}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel { get; }
public MainPage() { InitializeComponent(); ViewModel = new MainViewModel(); }
private void SearchTicketBooks_TextChanged(object sender, TextChangedEventArgs e)
{
if (ViewModel != null)
{
if (string.IsNullOrWhiteSpace(SearchTicketBooksBox.Text))
{
ViewModel.TicketBooks.Filter = _ => true;
}
else
{
ViewModel.TicketBooks.Filter = x => ((TicketBookDto)x).StartNumber == SearchTicketBooksBox.Text;
//{
// var startNumber = Convert.ToInt32(((TicketBookDto)x).StartNumber);
// var endNumber = Convert.ToInt32(((TicketBookDto)x).EndNumber);
// var searchText = Convert.ToInt32(SearchTicketBooksBox.Text);
// return searchText >= startNumber && searchText <= endNumber;
//};
}
}
}
private void Page_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
ViewModel.TicketBooks.Add(new TicketBookDto { StartNumber = "123", EndNumber = "456" });
ViewModel.TicketBooks.Add(new TicketBookDto { StartNumber = "789", EndNumber = "987" });
}
}
MainViewModel
public class MainViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<TicketBookDto> _ticketBooksPrivate = new ObservableCollection<TicketBookDto>();
private AdvancedCollectionView ticketBooks;
public AdvancedCollectionView TicketBooks
{
get
{
if (ticketBooks is null)
{
ticketBooks = new AdvancedCollectionView(_ticketBooksPrivate, true);
ticketBooks.ObserveFilterProperty(nameof(TicketBookDto.StartNumber));
ticketBooks.ObserveFilterProperty(nameof(TicketBookDto.EndNumber));
}
return ticketBooks;
}
set => Set(ref ticketBooks, value);
}
#region INotifyStuff
public event PropertyChangedEventHandler PropertyChanged;
protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#endregion
}
TicketBookDto
public partial class TicketBookDto
{
public string StartNumber { get; set; }
public string EndNumber { get; set; }
}
I have commented out code of the actual logic I need in the filter, which is to show the list items only those who have the search number between their "StartNumber" and "EndNumber" properties. But for simplicity I am using a simple match to StartNumber logic to find out why it aint working. Also when I add a boolean property and simply filter using that property then it works fine, its just not working with these string properties.
恐怕你不能在TextChanged
事件中使用Filter
,请参考源代码here。
if (_filter != null)
{
for (var index = 0; index < _view.Count; index++)
{
var item = _view.ElementAt(index);
if (_filter(item))
{
continue;
}
RemoveFromView(index, item);
index--;
}
}
当您在 SerchBox 中输入文本时,如果文本不等于过滤器 属性,则该项目将为 RemoveFromView
。所以它会让下一个输入不生效。对于这种设计,我们建议您在输入完成后制作提交按钮来过滤数据。
并且如果您确实想在 TextChanged
中过滤 ,您可以在设置 Filter
委托之前调用 ViewModel.TicketBooks.Filter = _ => true;
重置视图方法如下。
private void SearchTicketBooks_TextChanged(object sender, TextChangedEventArgs e)
{
if (ViewModel != null)
{
if (string.IsNullOrWhiteSpace(SearchTicketBooksBox.Text))
{
ViewModel.TicketBooks.Filter = _ => true;
}
else
{ // reset the filter
ViewModel.TicketBooks.Filter = _ => true;
ViewModel.TicketBooks.Filter = x => ((TicketBookDto)x).EndNumber == SearchTicketBooksBox.Text;
}
}
}