我如何动态地显示每次发生变化时ListBox中的项目计数?
本文关键字:ListBox 变化 项目 何动态 动态 显示 | 更新日期: 2023-09-27 18:14:58
我有一个c#项目,它有一个ListBox作为它的用户界面的一部分。此列表框用于显示多个项目名称。我还可以根据对数据库的查询(所有项目,未完成的,完成的,等等)更改这个ListBox的大小。
我还有一个标签,它将显示ListBox内的结果数量。我希望找到一种方法,在每次列表更改时自动执行此操作,而不是在我更改列表的每一行代码中执行此操作。
我已经尝试使用DataSourceChanged事件,但这提出了一个非常有趣的问题。该事件在ListBox实际用新值填充之前被触发。例如,在程序开始时,我将ListBox的数据源设置为一组100个项目。然后,DataSourceChanged事件被触发,我调用listBox1.Items.Count.ToString()
来获取值,它返回0。同样,因为列表框还没有被填充。因此,我将有一个显示0的标签和一个包含100个项目的列表框。
现在,如果我要将其缩小到未完成的项目(例如,将具有50个计数),当事件被触发时,它将返回值100。这是因为自数据源更改以来尚未填充未完成的项目。因此,我将有一个标签,上面写着100,但列表框中只有50个项目。
还有其他事件可以使用吗?DataSourceChanged事件是否有任何参数,我可以查看挂起的数据源以获得计数?或者我真的应该找到代码中每个改变listbox的实例并更新那里的标签吗
您可以使用接口ICollectionView来完成这样的任务,这甚至可以使您保持itemssource的完整(为您的数据库节省一些工作负载,以及大量的混乱)。你还需要为你的itemssource使用ObservableCollection,就像在这里的其他评论中提到的那样。您应该使用绑定、命令和工作,而不是关注WPF中的事件。讨厌的代码背后让老MVVM老手眼睛酸痛,让小猫咪哭;)
尽可能使用过滤器,在完全更改"数据源"时,只需更改stuff集合。请原谅我在这里的命名,我试图让这个例子对你来说尽可能简单。
Xaml:<Window x:Class="custtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custtest="clr-namespace:custtest"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<custtest:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto" MinWidth="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Stuffs}" Grid.Row="0" Grid.Column="0"></ListBox>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding StuffFilterView.Count}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
<TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding SearchText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ></TextBox>
</Grid>
</Window>
ViewModel:
下面的代码非常简单,你永远不应该做我在actor中做的事情!这只是为了简单。
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> stuffs;
private string searchText;
private ICollectionView stuffFilterView;
public ICollectionView StuffFilterView
{
get { return stuffFilterView; }
set
{
if (Equals(value, stuffFilterView)) return;
stuffFilterView = value;
OnPropertyChanged();
}
}
public ObservableCollection<String> Stuffs
{
get { return stuffs; }
set
{
if (Equals(value, stuffs)) return;
stuffs = value;
OnPropertyChanged();
}
}
public String SearchText
{
get { return searchText; }
set
{
if (value == searchText) return;
searchText = value;
OnPropertyChanged();
OnSearchTextChanged();
}
}
private void OnSearchTextChanged()
{
StuffFilterView.Refresh(); // Refresheses content in your ICollectionView when text changes
}
public MainViewModel()
{
// Bad pie!
Stuffs = new ObservableCollection<string> {"jall", "b", "c", "d", "blabla"};
StuffFilterView = CollectionViewSource.GetDefaultView(Stuffs);
StuffFilterView.Filter = FilterStuff;
}
private bool FilterStuff(object obj)
{
String str = obj.ToString();
if (String.IsNullOrEmpty(SearchText))
return true;
return str.Contains(SearchText);
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] // R# remove if you don't have it
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
希望有帮助!
欢呼,Stian