开发者

Bind to Count of items in the DataContext

开发者 https://www.devze.com 2022-12-31 23:23 出处:网络
I want to bind to the Count/amount of items within my DataContext. I have an object, let\'s say person which has a List<address> as a property. I would like to display the amount of addresses fo

I want to bind to the Count/amount of items within my DataContext.

I have an object, let's say person which has a List<address> as a property. I would like to display the amount of addresses for that person, i.e.: 5 or 6 or whate开发者_StackOverflow社区ver the case may be.

I've tried {Binding Path=address#.Count} and a few others but that doesn't seem to work.


You need to bind the name of the property, not its type.

C#:

public class Person
{
    ...
    public List<address> Addresses { get; set; }
    ...
}

XAML:

{Binding Addresses.Count}

Assuming your DataContext is an object of type Person.


As tehMick says, you can bind using the path Addresses.Count.

Note, however, that unless Addresses is an ObservableCollection<address>, or some other type that implements INotifyCollectionChanged, adding and removing addresses won't affect the number that appears in the UI after its initial display. If you need that, you will either need to change the type of the collection in your view model (that's easiest), or implement a property in your view model that exposes the count, and raise the PropertyChanged event every time you add or remove an address.

Edit

I love reading an answer, thinking, "hey, that's not right," and then realizing I wrote it.

If you bind to an object that just implements INotifyCollectionChanged, the count in the UI won't change if items are added or removed ot the collection. The object also has to implement INotifyPropertyChanged and raise PropertyChanged when the Count property changes.

Which, fortunately, ObservableCollection<T> does. So my answer's not that wrong.


XAML:

<Window x:Class="CountDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="CountDemo" Height="300" Width="300">
    <StackPanel>
        <TextBlock Text="{Binding Path=Addresses.Count}" />
    </StackPanel>
</Window>

Code behind:

using System.Collections.Generic;
using System.Windows;

namespace CountDemo
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            DataContext = new Person();
        }
    }

    public class Person
    {
        public List<Address> Addresses
        {
            get { return new List<Address>() {new Address(), new Address(), new Address()}; }
        }
    }

    public class Address
    {
    }
}


To expand on tehMick's answer with functional sample code:

XAML:

<Window x:Class="Sandbox.Wpf.PropertyCount.PropertyCount"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Property Count" Height="300" Width="300">
    <StackPanel>
        <ListView ItemsSource="{Binding Path=People}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="4">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Path=Name}" Margin="3" />
                        <TextBlock Grid.Column="1" Margin="3">
                            <TextBlock Text="{Binding Path=Addresses.Count}" /> <Run>addresses</Run>
                        </TextBlock>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackPanel>
</Window>

Code Behind:

namespace Sandbox.Wpf.PropertyCount
{
    /// <summary>
    /// Interaction logic for PropertyCount.xaml
    /// </summary>
    public partial class PropertyCount : Window
    {

        public PropertyCount()
        {
            InitializeComponent();
            this.DataContext = new Model();
        }
    }

    public class Model
    {
        public List<Person> People { get; private set; }

        public Model()
        {

            People = new List<Person>{
                new Person ("joe", new List<object> { 1, 2, 3 }),
                new Person ("bob", new List<object> { 1, 2 }),
                new Person ("kay", new List<object> { 1, 2, 3, 4, 5 }),
                new Person ("jill", new List<object> { 1, 2, 3, 4 }),
            };
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public List<object> Addresses { get; set; }

        public Person(string name, List<object> addresses)
        {
            Name = name;
            Addresses = addresses;
        }
    }

}


In my case, Robert's answer got me really close to what I was after. However, I'm adding many items to the list from a service call, and didn't want the event firing for each item. To this end, I took advantage of functionality already built into BindingList:

public class BindingListNotifyCount<T> : BindingList<T>, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected override void OnListChanged(ListChangedEventArgs e)
    {
        base.OnListChanged(e);
        RaisePropertyChanged("Count");
    }

    protected void RaisePropertyChanged([CallerMemberName]string propertyName = "") =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Then I simply use it as:

displayItems.RaiseListChangedEvents = false;
serviceItems.ForEach(item => displayItems.Add(item));
displayItems.RaiseListChangedEvents = true;
displayItems.ResetBindings();
0

精彩评论

暂无评论...
验证码 换一张
取 消