【问题标题】:How can I dynamically display the count of items in a ListBox each time it changes?如何在每次更改时动态显示 ListBox 中的项目数?
【发布时间】:2014-07-25 18:58:30
【问题描述】:

我有一个 C# 项目,其中有一个 ListBox 作为其用户界面的一部分。此 ListBox 用于显示多个项目名称。我还有一些选项可以根据对数据库的查询(所有项目、不完整、完整等)更改此 ListBox 的大小。

我还有一个标签,用于显示 ListBox 内的结果数量。我希望找到一种方法在每次列表更改时自动执行此操作,而不是在我更改列表的每一行代码中。

我尝试过使用 DataSourceChanged 事件,但这带来了一个非常有趣的问题。在 ListBox 实际填充新值之前触发该事件。例如,在程序开始时,我将 ListBox 的数据源设置为一组 100 个项目。然后,触发 DataSourceChanged 事件,我调用 listBox1.Items.Count.ToString() 来获取值,它返回 0。同样,因为列表框尚未填充。所以我会有一个显示 0 的标签和一个包含 100 个项目的列表框。

现在,如果我将其缩小到不完整的项目(例如,计数为 50),当事件被触发时,它将返回值 100。这是因为不完整的项目没有t 自数据源更改以来尚未填充。所以,我将有一个标签,上面写着 100,但列表框只有 50 个项目。

还有其他我可以使用的事件吗? DataSourceChanged 事件是否有任何参数可以让我查看待处理的数据源以获取计数?或者我真的应该在我的代码中找到每个更改列表框并在那里更新标签的实例。

【问题讨论】:

  • 使用ObservableCollection<T>绑定ItemsSource,它会自动向UI提供更新通知。
  • WPF 与事件无关。您使用的是完全错误的方法。 WPF 是关于 XAML 和 DataBinding,而不是过程代码。只需执行<TextBox Text="{Binding Items.Count, ElementName=YourListBox}"/> 即可。不需要可怕的类似 winforms 的黑客攻击。
  • 感谢你们的好主意。不幸的是(好吧,对我来说很幸运)这周我不在办公室度假,这是一个工作项目,源代码仍在我的桌面上。如果有人有兴趣回来查看,将在一周内返回结果。

标签: c# events listbox


【解决方案1】:

您可以使用接口 ICollectionView 来执行此类任务,这甚至可以使您的 itemssource 保持完整(为您的数据库节省一些工作量,并避免很多混乱)。 您还需要将 ObservableCollection 用于您的 itemssource,如此处其他 cmets 中所述。与其关注 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));
    }
}

希望对你有帮助!

干杯, 斯蒂安

【讨论】:

  • 感谢您的想法。由于假期,我将离开这个项目一个星期,但我肯定会在八月带着我的结果回来。我只是不想让它看起来好像被忽略了。
  • 你有你需要的一切,度过一个愉快的假期!它并没有那么复杂,但如上所述,您需要包含 INot。在你所有的嵌套类中,你已经启动并运行了。如果您自己测试,上面的代码就会运行。我刚刚通过 rdp 做了一个真正的快速应用程序,因为我自己去拜访我的亲戚。 ;)
  • 原谅我的无知,但这是我第一次使用 xaml 文件,我似乎找不到它。这是一个应该已经存在于 Visual Studio 中某处的文件,还是我必须创建的文件?
  • @McAdam331 这完全取决于您用于创建 wpf 项目的模板。我建议下载 galasoft mvvm light,并使用他们的模板。否则,您只需创建一个新的 WPF 项目。如果您打算创建一个新的 WPF 窗口/用户控件,只需右键单击您的项目,选择添加新项目并浏览到您的 wpf 窗口/usercoontrol/cust.ctl/page,或者直接从菜单新建菜单中选择它们。如果要创建库,还要注意属性文件夹中的 assemblyinfo.cs。一些行被注释掉了,这是 WPF 需要的。
  • 我知道我做了什么。一个长期复杂的错误,但我现在回到了正确的轨道上。再次感谢您的所有帮助,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-24
  • 1970-01-01
  • 2019-11-10
  • 2011-03-24
相关资源
最近更新 更多