将TextBox的文本绑定到列表<t>值</t>的总和

时间:2014-01-14 16:56:36

标签: c# wpf binding observablecollection inotifypropertychanged

我有一个问题。我有一节课:

public class ParagonClass : INotifyPropertyChanged
{
    //some variables
    private decimal _totalValue;

    public static ObservableCollection<ParagonClass> paragonLista { get; set; }

    public decimal TotalValue
    {
        get
        {
            if (ProductID > 0)
                _totalValue = Math.Round(ProductCount * PriceBrutto, 2, MidpointRounding.AwayFromZero);
            return _totalValue;
        }
        set
        {
            _totalValue = value;
            NotifyPropertyChanged("TotalValue");
        }
    }

    ...
}

在我的窗口中,我想将TotalValue(所有paragonLista元素)的总和绑定到TextBox的Text。我尝试了几个选项,但没有效果。我得到的最好的是计算我想要的东西,但只有当我打开旧版时,才将其命名为文档。当我向此文档添加新位置时,TextBox中的值不会更改。我通过以下方式实现了这一目标:

 private decimal _Sum;
 public decimal Sum
 {
     get
     {
         _Sum = ParagonClass.paragonLista.Sum(x => x.TotalValue);
         return _Sum;
     }
 }

和.xaml:

<TextBox Name="priceTextBox" FontSize="28" Margin="0,0,5,0" HorizontalAlignment="Right" Text="{Binding Sum, UpdateSourceTrigger=PropertyChanged}" />

3 个答案:

答案 0 :(得分:3)

在WPF中的普通属性setter中,您可以调用NotifyPropertyChanged("PropertyName")来警告INotifyPropertyChanged界面PropertyName属性已更改且您想要的事实查看用户界面中的更改。

在像您这样的情况下,如果您没有财产setter需要致电NotifyPropertyChanged("PropertyName")以查看用户界面中的更改。现在显然,你不能从setter中调用它,因为它没有。{/ p>

通常从另一个属性setter调用它,该属性在没有setter的情况下在属性的输出值中起作用。例如,FirstName属性可能在没有Initials的{​​{1}}属性中使用:

setter

现在此属性只会在public string Initial { get { return FirstName[0].ToString(); } } 属性更改时更改,因此调用FirstName的合理位置将位于 属性中:

NotifyPropertyChanged("Initial")

您不必在任何属性中调用它...您也可以在更改关联值的任何地方调用它:

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName= value;
        NotifyPropertyChanged("FirstName");
        NotifyPropertyChanged("Initial");

    }
}

因此,无论您何时调用它,您仍需要调用FirstName = SomeObject.GetFirstName(someIdNumber); NotifyPropertyChanged("Initial"); 方法来更新UI。

答案 1 :(得分:3)

不是将所有东西混合在一起,而是需要两个类。

public class ParagonClass : INotifyPropertyChanged
{
  //some variables
  private decimal _totalValue;

  public decimal TotalValue
  {
    get
    {
        if (ProductID > 0)
            _totalValue = Math.Round(ProductCount * PriceBrutto, 2, MidpointRounding.AwayFromZero);
        return _totalValue;
    }
  // No need for a setter if its calculated
  // See Sheridan's answer for how to do this
  //       set
  //       {
  //           _totalValue = value;
  //           NotifyPropertyChanged("TotalValue");
  //       }
  }

  ...
}

和一个集合

public class ParagonCollection : ObservableCollection<ParagonClass>, INotifyPropertyChanged
{
  private int sum;
  public int Sum
  { 
    get{ return sum;} 
    set
    {
      sum = value;
      NotifyPropertyChanged("Sum");
    }
 }
  // You'll need as implantation of INotifyPropertyChanged here
  // and some extra stuff to come
  ...
}

现在我们只需要在它改变时计算总和。有几次这种情况发生

  1. 将新Paragon添加到集合中
  2. 当Paragon改变时
  3. 让我们一次一个,我们可以通过监听构造函数中的集合更改来连接通过集合添加的Paragon项目

    public ParagonCollection()
    {
       // When the collection changes set the Sum to the new Sum of TotalValues
       this.CollectionChanged += OnCollectionChanged;
    }
    
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
    {
      Recalculate();
    }
    
    private void Recalculate()
    {
      Sum = this.Sum(x=>x.TotalValue);
    }
    

    现在,如果您设计ParagonClass以使项目不可变(即它们在创建后不会更改),那么您应该完成所有操作。但是,如果您需要更改Paragons,我们需要重写添加或删除项目时发生的事情

    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
    {
      foreach(ParagonClass item in args.OldItems)
      {
        // Unsubscribe to changes in each item
        item.PropertyChanged -= OnItemChanged;
      }
      foreach(ParagonClass item in args.NewItems)
      {
        // Subscribe to future changes for each item
        item.PropertyChanged += OnItemChanged;
      }
    
      Recalculate();
    }
    
    private void OnItemChanged(object sender, PropertyChangedEventArgs args)
    {
      Recalulate();
    
      // You might decide that you only want to recalculate for some property 
      // changes, and do something like the following instead
      // if (args.PropertyName=="TotalValue")
      //   Recalulate();
    }
    

答案 2 :(得分:1)

如果您在“ProductCount”或“PriceBertto”更改时尝试更新TotalValue,则需要通知WPF该更改。你可以尝试这样的事情:

...
public double TotalValue
{
    get
    {
         return Math.Round (ProductCount * PriceBrutto, 2, MidpointRounding.AwayFromZero );
    }
}

private int productCount = 0;
public int ProductCount
{
    get
    {
        return productCount;
    }
    set
    {
        if( Equals( productCount, value) ) return;
        productCount = value;

        NotifyPropertyChange( "ProductCount" );
        NotifyPropertyChange( "TotalValue" );
    }
 }

...

请注意,从TotalCount的setter调用NotifyPropertyChange for“TotalValue”。

我没有为你做这一切,但你也可以为你的其他财产做类似的事情。可以为影响TotalValue的其他属性执行类似的操作。