【问题标题】:WPF DataGrid Column Total MVVM PaternWPF DataGrid 列总 MVVM 模式
【发布时间】:2015-02-23 01:45:51
【问题描述】:

我的DataGrid 中有一个列是价格字段。 在表单底部的TextBlock 中。

TextBlock 中如何根据 Price 列的值显示总值?

XAML 代码:

 <Grid>
    <DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
        <DataGrid.Columns>
            <DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
            <DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, NotifyOnTargetUpdated=True, ValidatesOnDataErrors=True}" Width="*" />
        </DataGrid.Columns>
    </DataGrid>
    <TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>
</Grid>

视图模型:

public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
{
    get { return _SaleryDetailsCollection; }
    set
    {
        SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
        _SaleryDetailsCollection = value;
        NotifyPropertyChanged("SaleryDetailsCollection");
    }
}
public Double SalaryTotal
{
    get { return _SalaryTotal; }
    set
    {
        _SalaryTotal = value;
        NotifyPropertyChanged("SalaryTotal");
    }
}

类 SaleryDetailsMode

  class SaleryDetailsModel:ViewModel
{
    private Double _Amount;
    private String _Type;
    public Double Amount
    {
        get { return _Amount; }
        set
        {
            _Amount = value;
            NotifyPropertyChanged("Amount");
        }
    }
    public String Type { get { return _Type; } set { _Type = value; NotifyPropertyChanged("Type"); } }

}

类视图模型

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

【问题讨论】:

  • 能否请您发布当前的实现?

标签: c# wpf xaml mvvm


【解决方案1】:

在构造函数中添加这段代码

SaleryDetailsCollection = new ObservableCollection<SaleryDetailsModel>();
SaleryDetailsCollection.CollectionChanged += MyItemsSource_CollectionChanged;

在视图模型中

void MyItemsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
            foreach (SaleryDetailsModel item in e.NewItems)
                item.PropertyChanged += MyType_PropertyChanged;

        if (e.OldItems != null)
            foreach (SaleryDetailsModel item in e.OldItems)
                item.PropertyChanged -= MyType_PropertyChanged;
    }

void MyType_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Amount")
            DoWork();
    }

    private void DoWork()
    {
        SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount);
    }

XAML

<Grid>
<DataGrid HorizontalAlignment="Left" ItemsSource="{Binding Path=SaleryDetailsCollection, Mode=TwoWay}" AutoGenerateColumns="False" VerticalAlignment="Top" Width="640" Height="192" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Type" Binding="{Binding Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
        <DataGridTextColumn Header="Amount" Binding="{Binding Price, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Width="*" />
    </DataGrid.Columns>
</DataGrid>
<TextBlock HorizontalAlignment="Left" Margin="415,358,0,0" TextWrapping="Wrap" Text="{Binding SalaryTotal}" VerticalAlignment="Top"/>

【讨论】:

    【解决方案2】:

    必须在字段赋值后进行计算:

    public ObservableCollection<SaleryDetailsModel> SaleryDetailsCollection
    {
        get { return _SaleryDetailsCollection; }
        set
        {
            _SaleryDetailsCollection = value;
            SalaryTotal = SaleryDetailsCollection.Sum(x => x.Amount); // This line must be after the field assignment.
            NotifyPropertyChanged("SaleryDetailsCollection");
        }
    }
    

    【讨论】:

    • 是的,我明白了。我假设模型是“静态的”(在运行时没有改变)。答案将很快更新。
    • 没关系,谢谢您的回复。
    • @SamAlex,您能否也发布SaleryDetailsModel 类的实现?是否实现INotifyPropertyChanged接口?
    • 我发布了 INotifyPropertyChanged 用于 NotifyPropertyChanged()
    • @SamAlex,谢谢!顺便说一句,用户可以在ObservableCollection&lt;SalaryDetailsModel&gt; 中添加/删除项目还是只编辑现有项目?
    【解决方案3】:

    您需要使用一个集合,该集合会在其属性发生更改时收到通知。请参阅链接https://social.msdn.microsoft.com/Forums/silverlight/en-US/12915e07-be95-4fc5-b8f0-b0a49b10bc57/observablecollection-item-changed。它有 NotifyableCollection。我已经将它用于以下代码。

    <Grid>
        <StackPanel>
            <DataGrid x:Name="dgr" HorizontalAlignment="Left" ItemsSource="{Binding Path=Salaries, Mode=TwoWay}"
                      AutoGenerateColumns="True" VerticalAlignment="Top" Width="640" Height="192" >                
            </DataGrid>
            <TextBlock HorizontalAlignment="Left"  TextWrapping="Wrap"  VerticalAlignment="Top" Text="{Binding TotalSalary}">               
            </TextBlock>
        </StackPanel>
    </Grid>
    
     class ViewModel : INotifyPropertyChanged
    {
        private NotifiableCollection<Salary> salaries;        
        double _totalSal;
        public double TotalSalary
        {
            get { return _totalSal = Salaries.Sum(x => x.Amount); }
            set { _totalSal = value; }
        }
    
        public NotifiableCollection<Salary> Salaries
        {
            get { return salaries; }
            set
            {
                salaries = value;
                if (salaries != null)
                {
                    salaries.ItemChanged += salaries_ItemChanged;
                }
    
            }
        }
    
        void salaries_ItemChanged(object sender, NotifyCollectionChangeEventArgs e)
        {
            OnPropertyChanged("TotalSalary");
        }     
    
    
        public ViewModel()
        {
            Salaries = new NotifiableCollection<Salary>();
            for (int i = 0; i < 10; i++)
            {
                Salary s = new Salary() { Type="Type"+i,Amount=new Random().Next(20000,30000)};
    
                Salaries.Add(s);
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    
    }
    
    
    class Salary : INotifyPropertyChanged
    {
        private string type;
    
        public string Type
        {
            get { return type; }
            set { type = value; OnPropertyChanged("Type"); }
        }
        private double amount;
    
        public double Amount
        {
            get { return amount; }
            set { amount = value; OnPropertyChanged("Amount"); }
        }
    
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
    
    public class NotifyCollectionChangeEventArgs : PropertyChangedEventArgs
        {
            public int Index { get; set; }
            public NotifyCollectionChangeEventArgs(int index, string propertyName) : base(propertyName) { Index = index; }
        }
    
    public class NotifiableCollection<T> : ObservableCollection<T> where T : class, INotifyPropertyChanged
    {
        public event EventHandler<NotifyCollectionChangeEventArgs> ItemChanged;
    
        protected override void ClearItems()
        {
            foreach (var item in this.Items)
                item.PropertyChanged -= ItemPropertyChanged;
            base.ClearItems();
        }
    
        protected override void SetItem(int index, T item)
        {
            this.Items[index].PropertyChanged -= ItemPropertyChanged;
            base.SetItem(index, item);
            this.Items[index].PropertyChanged += ItemPropertyChanged;
        }
    
        protected override void RemoveItem(int index)
        {
            this.Items[index].PropertyChanged -= ItemPropertyChanged;
            base.RemoveItem(index);
        }
    
        protected override void InsertItem(int index, T item)
        {
            base.InsertItem(index, item);
            item.PropertyChanged += ItemPropertyChanged;
        }
    
        private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            T changedItem = sender as T;
            OnItemChanged(this.IndexOf(changedItem), e.PropertyName);
        }
    
        private void OnItemChanged(int index, string propertyName)
        {
            if (ItemChanged != null)
                this.ItemChanged(this, new NotifyCollectionChangeEventArgs(index, propertyName));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-12
      • 2016-02-12
      • 2021-03-01
      • 2021-07-17
      相关资源
      最近更新 更多