WPF绑定where子句可能吗?

时间:2013-02-02 23:26:07

标签: c# wpf linq xaml data-binding

如果我有Observable这样的集合:

public ObservableCollection<SpecialPriceRow> SpecialPriceRows = new ObservableCollection<SpecialPriceRow>();

SpecialPriceRow上课:

public class SpecialPriceRow : INotifyPropertyChanged
{
    public enum ChangeStatus
    {
        Original,
        Added,
        ToDelete,
        Edited
    }

    public ChangeStatus Status { get; set; }
    public string PartNo { get; set; }

    private decimal _price;
    public decimal Price
    {
        get
        {
            return _price;
        }
        set
        {
            if (value != _price)
            {
                _price = value;
                Status = ChangeStatus.Edited;
                OnPropertyChanged("Status");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

我可以将XAML中的Label绑定到对象的计数吗?添加?所以我可以得到这样的东西:

enter image description here

其中green是集合中“已添加”对象的计数。我该如何做这样的事情?

2 个答案:

答案 0 :(得分:0)

我不知道有任何内置功能来执行此操作。我会在你的数据上下文类中创建一个自定义属性来进行计数并绑定到它。

这样的事情:

public int AddedCount
{
    get
    {
        return SpecialPriceRows.Where(r => r.Status == ChangeStatus.Added).Count();
    }
}

然后,无论何时更改或添加项目,您都需要显式提升为此更改的属性:

public void AddItem()
{
    ...
    OnPropertyChanged("AddedCount");
}

然后你只需要绑定你的XAML代码,如:

<TextBlock Text="{Binding AddedCount}" />

您可能需要订阅集合中的更改事件,以了解项目何时更改。

<强>替代:

您还可以使用特定过滤器创建ListCollectionView并绑定到其Count属性:

    AddedItems = new ListCollectionView(TestItems);
    AddedItems.Filter = r => ((SpecialPriceRow)r).Status == ChangeStatus.Added;

然后,在您的XAML中,您将绑定到此Count属性:

<TextBlock Text="{Binding AddedItems.Count}" />

这样做的好处是它会自动跟踪集合中添加和删除的项目并自行更新。您必须手动刷新它,但项目的属性更改会影响过滤器。

答案 1 :(得分:0)

我已经编写了一个ViewModel,它将执行您正在寻找的所需功能。

    class VM : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ObservableCollection<SpecialPriceRow> _SpecialPriceRows = new ObservableCollection<SpecialPriceRow>();
        private int _Original = 0;
        private int _Added = 0;
        private int _ToDelete = 0;
        private int _Edited = 0;

        public VM()
        {
            PropertyChanged = new PropertyChangedEventHandler(VM_PropertyChanged);

            //The following lines in the constructor just initialize the SpecialPriceRows.
            //The important thing to take away from this is setting the PropertyChangedEventHandler to point to the UpdateStatuses() function.
            for (int i = 0; i < 12; i++)
            {
                SpecialPriceRow s = new SpecialPriceRow();
                s.PropertyChanged += new PropertyChangedEventHandler(SpecialPriceRow_PropertyChanged);
                SpecialPriceRows.Add(s);
            }
            for (int j = 0; j < 12; j+=2)
                SpecialPriceRows[j].Price = 20;
        }

        private void VM_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
        }

        private void SpecialPriceRow_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Status")
                UpdateStatuses();
        }

        public ObservableCollection<SpecialPriceRow> SpecialPriceRows
        {
            get
            {
                return _SpecialPriceRows;
            }
        }

        private void UpdateStatuses()
        {
            int original = 0, added = 0, todelete = 0, edited = 0;
            foreach (SpecialPriceRow SPR in SpecialPriceRows)
            {
                switch (SPR.Status)
                {
                    case SpecialPriceRow.ChangeStatus.Original:
                        original++;
                        break;
                    case SpecialPriceRow.ChangeStatus.Added:
                        added++;
                        break;
                    case SpecialPriceRow.ChangeStatus.ToDelete:
                        todelete++;
                        break;
                    case SpecialPriceRow.ChangeStatus.Edited:
                        edited++;
                        break;
                    default:
                        break;
                }
            }
            Original = original;
            Added = added;
            ToDelete = todelete;
            Edited = edited;
        }

        public int Original
        {
            get
            {
                return _Original;
            }
            set
            {
                _Original = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Original"));
            }
        }

        public int Added
        {
            get
            {
                return _Added;
            }
            set
            {
                _Added = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Added"));
            }
        }

        public int ToDelete
        {
            get
            {
                return _ToDelete;
            }
            set
            {
                _ToDelete = value;
                PropertyChanged(this, new PropertyChangedEventArgs("ToDelete"));
            }
        }

        public int Edited
        {
            get
            {
                return _Edited;
            }
            set
            {
                _Edited = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Edited"));
            }
        }
    }

记下构造函数中的注释。您需要将每个SpecialPriceRow的PropertyChanged事件指向UpdateStatuses函数,以使其正常工作。 现在,您只需将标签绑定到ViewModel中的相应属性即可。 如果您的SpecialPriceRows列表变得非常大,您可能需要考虑计算状态计数有点不同。目前,每次更新一个实例时,它都会遍历整个列表。为了更好地执行此操作,您可能希望在SpecialPriceRow类中保留状态的旧值,并且每次更新发生时,递增新状态计数并递减旧状态。