簡體   English   中英

更改列表中基礎項目上的屬性時更新計算的總數-WPF

[英]Updating calculated total when a property on the underlying item in a list is changed - wpf

我有一個ViewModel(VM只是簡化示例的背后代碼),其中包含(除其他事項外)一個Pallet類。 托盤上有很多箱子。 每個盒子里都有幾塊。

我有一個Wpf表單,列出了托盤上的每個盒子以及一個顯示盒子中有多少物品的文本框。 此標簽下面是標簽,顯示托盤上所有物品的總數。

我的問題是,當其中一個文本框發生更改時,如何使標簽更新。 我認為這與屬性更改和集合更改事件有關,但是我似乎無法使其正常工作。

我遇到了似乎可以在集合中添加或刪除項目的答案。 問題是我沒有添加或刪除任何物品。 我只更改集合中某個項目的值。 我知道關於此問題有很多問題,但我一直找不到適合我的問題。

這是一個示例程序:

MainWindow.xaml

<Window>
    <StackPanel>
        <ItemsControl ItemsSource="{Binding Pallet.BoxesOnPallet}" AlternationCount="100" Tag="{Binding .}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <!-- Cast 1 -->
                        <TextBox Text="{Binding NumberOfPiecesinBox}" Margin="10" Padding="3"></TextBox>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <TextBlock Text="{Binding Total}" Padding="3"></TextBlock>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.ComponentModel;

namespace Keops.Mes.Casthouse.Entities.BO
{
    public class Box : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public Box(int num)
        {
            NumberOfPiecesinBox = num;
        }

        public int NumberOfPiecesinBox
        {
            get { return _numberOfPiecesinBox; }
            set
            {
                _numberOfPiecesinBox = value;
                OnPropertyChanged("NumberOfPiecesinBox"); 
            } 
        }
        public int _numberOfPiecesinBox;

        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Pallet.cs

using System.Collections.ObjectModel;
using System.Linq;
using Keops.Mes.Casthouse.Entities.BO;

namespace WpfApplication2
{
    public class Pallet
    {
        public Pallet()
        {
            BoxesOnPallet = new ObservableCollection<Box>
            {
                new Box(3),
                new Box(8),
                new Box(5),
                new Box(1),
                new Box(0)
            };
        }
        public ObservableCollection<Box> BoxesOnPallet { get; set; }

        public int ItemTotal
        {
            get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
            set { }
        }
    }
}

Box.cs

using System.ComponentModel;

namespace Keops.Mes.Casthouse.Entities.BO
{
    public class Box : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public Box(int num)
        {
            NumberOfPiecesinBox = num;
        }

        public int NumberOfPiecesinBox
        {
            get { return _numberOfPiecesinBox; }
            set
            {
                _numberOfPiecesinBox = value;
                OnPropertyChanged("NumberOfPiecesinBox"); 
            } 
        }
        public int _numberOfPiecesinBox;

        private void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

在此示例中,要更新總數,您的Pallet類將需要通過處理BoxesOnPalletCollectionChanged來“監視”正在添加和從BoxesOnPallet刪除的項目。 然后,該處理程序應掛鈎/取消掛鈎已添加/已刪除項目的PropertyChanged事件。 事件的處理程序可以更新Total財產Pallet 一切都一起工作有點復雜。

public class Pallet : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Pallet()
    {
        BoxesOnPallet = new ObservableCollection<Box>();
        BoxesOnPallet.CollectionChanged += BoxesOnPallet_CollectionChanged;

        BoxesOnPallet.Add(new Box(3));
        BoxesOnPallet.Add(new Box(8));
        BoxesOnPallet.Add(new Box(5));
        BoxesOnPallet.Add(new Box(1));
        BoxesOnPallet.Add(new Box(0));
    }

    private void BoxesOnPallet_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {    
        if (e.Action == NotifyCollectionChangedAction.Add)
       {
            foreach (var item in e.NewItems)
            {
                ((Box)item).PropertyChanged += Box_Changed;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (var item in e.OldItems)
            {
                ((Box)item).PropertyChanged -= Box_Changed;
            }
        }
    }

    void Box_Changed(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Box.NumberOfPiecesinBox))
        {
            OnPropertyChanged(nameof(BoxesOnPallet));
        }
    }

    public ObservableCollection<Box> BoxesOnPallet { get; set; }

    public int ItemTotal
    {
        get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
        set { }
    }

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Box : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Box(int num)
    {
        NumberOfPiecesinBox = num;
    }

    public int NumberOfPiecesinBox
    {
        get { return _numberOfPiecesinBox; }
        set
        {
            _numberOfPiecesinBox = value;
            OnPropertyChanged(nameof(NumberOfPiecesinBox));
        }
    }
    public int _numberOfPiecesinBox;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

首先,您需要在Pallet類中實現INotifyPropertyChanged ,以便創建一種告訴視圖重新讀取正確值的方法。 然后,您需要監視集合中每個項目的PropertyChanged事件,以便可以在保持受監視項目列表與集合中項目同步的同時,判斷屬性是否已更改。

Pallet.cs

public class Pallet : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Pallet()
    {
        BoxesOnPallet = new ObservableCollection<Box>
        {
            new Box(3),
            new Box(8),
            new Box(5),
            new Box(1),
            new Box(0)
        };
    }

    private ObservableCollection<Box> _boxesOnPallet;
    public ObservableCollection<Box> BoxesOnPallet
    {
        get { return _boxesOnPallet; }
        set
        {
            if (_boxesOnPallet != null)
            {
                foreach (Box box in _boxesOnPallet)
                {
                    if (box != null)
                        box.PropertyChanged -= Box_PropertyChanged;
                }
                _boxesOnPallet.CollectionChanged -= BoxesOnPallet_CollectionChanged;
            }
            _boxesOnPallet = value;
            if (value != null)
            {
                foreach (Box box in value)
                {
                    if (box != null)
                        box.PropertyChanged += Box_PropertyChanged;
                }
                value.CollectionChanged += BoxesOnPallet_CollectionChanged;
            }
            OnPropertyChanged(nameof(BoxesOnPallet));
        }
    }

    private void BoxesOnPallet_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e?.OldItems != null)
        {
            foreach (Box box in e.OldItems)
            {
                if (box != null)
                    box.PropertyChanged -= Box_PropertyChanged;
            }
        }
        if(e?.NewItems != null)
        {
            foreach (Box box in e.NewItems)
            {
                if (box != null)
                    box.PropertyChanged += Box_PropertyChanged;
            }
        }
    }

    private void Box_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName.Equals(nameof(Box.NumberOfPiecesinBox)))
            OnPropertyChanged(nameof(ItemTotal));
    }

    public int ItemTotal
    {
        get { return BoxesOnPallet.Sum(x => x.NumberOfPiecesinBox); }
    }

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

同樣,XAML文件中提到的綁定似乎是OneWay ,這意味着將從源到視圖中獲取值,反之亦然; 相反,這應該是TwoWay綁定。 MainWindow.xaml

...
<TextBox Text="{Binding NumberOfPiecesinBox, Mode=TwoWay}" Margin="10" Padding="3"/>
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM