我有一个C#项目,它有一个ListBox作为其用户界面的一部分。此ListBox用于显示许多项目名称。我还有一些选项可以根据对数据库的查询(所有项目,不完整,完整等)更改此ListBox的大小。
我还有一个标签,显示ListBox内的结果数量。我希望每次列表更改时都能找到一种自动执行此操作的方法,而不是在我更改列表的每行代码中。
我尝试过使用DataSourceChanged事件,但这会带来一个非常有趣的问题。在实际使用新值填充ListBox之前触发事件。例如,在程序开始时,我将ListBox的数据源设置为一组100个项目。然后,触发DataSourceChanged事件,我调用listBox1.Items.Count.ToString()
来获取值,然后返回0.再次,因为列表框尚未填充。所以我将有一个显示0的标签和一个包含100个项目的列表框。
现在,如果我将其缩小到不完整的项目(例如,计数为50),当事件被触发时,它将返回值100.这是因为不完整的项目没有'自数据源发生变化以来,人口已经填充。所以,我会有一个标签,上面写着100,但只有50个项目的列表框。
我还可以使用其他活动吗? DataSourceChanged事件是否具有可以查看待处理数据源以获取计数的任何参数?或者我应该在代码中找到更改列表框并更新标签的每个实例。
答案 0 :(得分:1)
您可以使用接口ICollectionView执行此类任务,这甚至可以使您的项目源保持不变(保存您的数据库一些工作量,以及很多混乱)。 您还需要在此处的其他注释中使用您的itemssource的ObservableCollection。您应该使用绑定,命令和工作,而不是关注WPF中的事件。令人讨厌的代码隐藏给老MVVM老将眼睛疼痛并让小猫咪哭泣;)
尽可能使用过滤器,完全更改"数据源"你只需更改Stuffs集合。请原谅我的命名,我试图让你的例子尽可能简单。
的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>
视图模型:
以下代码非常简单,你永远不应该在ctor中做我做的事情!这只是为了简单起见。
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