I've a question. I have a class:
我一个问题。我有一个类:
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");
}
}
...
}
In my window I'd like to bind sum of TotalValue (of all paragonLista elements) to Text of TextBox. I tried few options but with no effect. Best what I get was calculate what I want but only when I opening old, name it document. When I add new position to this document, the value in TextBox doesn't change. I achieved that with:
在我的窗口中,我想将TotalValue(所有共生元素的总和)绑定到文本框的文本。我尝试了一些选择,但没有效果。我得到的最好的结果是计算出我想要的东西,但只有当我打开旧的,命名为文档。当我向这个文档添加新位置时,文本框中的值不会改变。我实现了:
private decimal _Sum;
public decimal Sum
{
get
{
_Sum = ParagonClass.paragonLista.Sum(x => x.TotalValue);
return _Sum;
}
}
and in .xaml:
而在.xaml:
<TextBox Name="priceTextBox" FontSize="28" Margin="0,0,5,0" HorizontalAlignment="Right" Text="{Binding Sum, UpdateSourceTrigger=PropertyChanged}" />
3 个解决方案
#1
3
Instead of mixing everything together you need two classes.
不要把所有东西混合在一起,你需要两个类。
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");
// }
}
...
}
And a collection
和一个集合
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
...
}
Now we just need to calculate the sum whenever the it changes. There are several times this occurs
现在我们只需要计算它变化时的和。这种情况发生了好几次
- When a new Paragon is added to the collection
- 当一个新的典范被添加到集合中
- When a Paragon changes
- 当一个典范的变化
Lets take them one at a time, and we can hook up the Paragon items being added via the collection by listening for collection changes in the constructor
让我们一次一个地使用它们,我们可以通过在构造函数中侦听集合更改来连接通过集合添加的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);
}
Now if you design your ParagonClass
so that the items are immutable (i.e they don't change after they have been created), then you should be all done. However if you need your Paragons to change we need to rewrite what happens when we add or remove an item
现在,如果你设计你的滑翔伞类,使项目是不可变的(i)。当它们被创造出来后,它们不会改变),那么你应该完成所有的事情。然而,如果你需要你的“副”来改变,我们需要重写当我们添加或删除一个项目时发生的事情。
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
3
In a normal property setter
in WPF, you would call NotifyPropertyChanged("PropertyName")
to alert the INotifyPropertyChanged
interface to the fact that the PropertyName
property has been changed and that you want to see the changes in the UI.
在WPF中的一个普通属性设置程序中,您将调用NotifyPropertyChanged(“PropertyName”)来通知INotifyPropertyChanged接口,告知这个事实,即PropertyName属性已经更改,您希望看到UI中的更改。
In cases like yours, where you have no property setter
, you still need to call NotifyPropertyChanged("PropertyName")
to see the changes in the UI. Now clearly, you can't call it from the setter
as it doesn't have one.
在类似您的情况下,如果没有属性设置器,您仍然需要调用NotifyPropertyChanged(“PropertyName”)来查看UI中的更改。显然,你不能从setter调用它,因为它没有一个。
It is most usual to call it from another property setter
that plays a part in the output value of the property without the setter
. For example, a FirstName
property might be used in an Initials
property without a setter
:
最常见的方法是从另一个属性setter调用它,该属性在没有设置setter的属性的输出值中扮演一个角色。例如,可以在没有setter的首字母属性中使用FirstName属性:
public string Initial
{
get { return FirstName[0].ToString(); }
}
Now this property will only change when the FirstName
property changes, so the sensible place to call NotifyPropertyChanged("Initial")
would be in that property:
这个属性只会在FirstName属性发生变化时发生变化,因此调用NotifyPropertyChanged("Initial")的合适位置应该在这个属性中:
public string FirstName
{
get { return _firstName; }
set
{
_firstName= value;
NotifyPropertyChanged("FirstName");
NotifyPropertyChanged("Initial");
}
}
You don't have to call it in any property though... you could also call it wherever you change the associated values:
你不需要在任何属性中调用它…您还可以在更改相关值的任何地方调用它:
FirstName = SomeObject.GetFirstName(someIdNumber);
NotifyPropertyChanged("Initial");
So, wherever you call it from, you still need to call the NotifyPropertyChanged
method to update the UI.
因此,无论您从哪里调用它,您仍然需要调用NotifyPropertyChanged方法来更新UI。
#3
1
If you are trying to update TotalValue when the "ProductCount" or "PriceBertto" change, you will need to notify WPF of that change. You could try something like this:
如果您试图在“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" );
}
}
...
Notice that NotifyPropertyChange for "TotalValue" is invoked from the setter of ProductCount.
注意,“TotalValue”的NotifyPropertyChange是从ProductCount的setter调用的。
I didn't do it all for you, but you can do similar things for your other properties as well. can do the similar things for your other properties that affect TotalValue.
我不是为你们做的,但是你们也可以为你们的其他属性做类似的事情。可以对影响TotalValue的其他属性执行类似的操作。
#1
3
Instead of mixing everything together you need two classes.
不要把所有东西混合在一起,你需要两个类。
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");
// }
}
...
}
And a collection
和一个集合
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
...
}
Now we just need to calculate the sum whenever the it changes. There are several times this occurs
现在我们只需要计算它变化时的和。这种情况发生了好几次
- When a new Paragon is added to the collection
- 当一个新的典范被添加到集合中
- When a Paragon changes
- 当一个典范的变化
Lets take them one at a time, and we can hook up the Paragon items being added via the collection by listening for collection changes in the constructor
让我们一次一个地使用它们,我们可以通过在构造函数中侦听集合更改来连接通过集合添加的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);
}
Now if you design your ParagonClass
so that the items are immutable (i.e they don't change after they have been created), then you should be all done. However if you need your Paragons to change we need to rewrite what happens when we add or remove an item
现在,如果你设计你的滑翔伞类,使项目是不可变的(i)。当它们被创造出来后,它们不会改变),那么你应该完成所有的事情。然而,如果你需要你的“副”来改变,我们需要重写当我们添加或删除一个项目时发生的事情。
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
3
In a normal property setter
in WPF, you would call NotifyPropertyChanged("PropertyName")
to alert the INotifyPropertyChanged
interface to the fact that the PropertyName
property has been changed and that you want to see the changes in the UI.
在WPF中的一个普通属性设置程序中,您将调用NotifyPropertyChanged(“PropertyName”)来通知INotifyPropertyChanged接口,告知这个事实,即PropertyName属性已经更改,您希望看到UI中的更改。
In cases like yours, where you have no property setter
, you still need to call NotifyPropertyChanged("PropertyName")
to see the changes in the UI. Now clearly, you can't call it from the setter
as it doesn't have one.
在类似您的情况下,如果没有属性设置器,您仍然需要调用NotifyPropertyChanged(“PropertyName”)来查看UI中的更改。显然,你不能从setter调用它,因为它没有一个。
It is most usual to call it from another property setter
that plays a part in the output value of the property without the setter
. For example, a FirstName
property might be used in an Initials
property without a setter
:
最常见的方法是从另一个属性setter调用它,该属性在没有设置setter的属性的输出值中扮演一个角色。例如,可以在没有setter的首字母属性中使用FirstName属性:
public string Initial
{
get { return FirstName[0].ToString(); }
}
Now this property will only change when the FirstName
property changes, so the sensible place to call NotifyPropertyChanged("Initial")
would be in that property:
这个属性只会在FirstName属性发生变化时发生变化,因此调用NotifyPropertyChanged("Initial")的合适位置应该在这个属性中:
public string FirstName
{
get { return _firstName; }
set
{
_firstName= value;
NotifyPropertyChanged("FirstName");
NotifyPropertyChanged("Initial");
}
}
You don't have to call it in any property though... you could also call it wherever you change the associated values:
你不需要在任何属性中调用它…您还可以在更改相关值的任何地方调用它:
FirstName = SomeObject.GetFirstName(someIdNumber);
NotifyPropertyChanged("Initial");
So, wherever you call it from, you still need to call the NotifyPropertyChanged
method to update the UI.
因此,无论您从哪里调用它,您仍然需要调用NotifyPropertyChanged方法来更新UI。
#3
1
If you are trying to update TotalValue when the "ProductCount" or "PriceBertto" change, you will need to notify WPF of that change. You could try something like this:
如果您试图在“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" );
}
}
...
Notice that NotifyPropertyChange for "TotalValue" is invoked from the setter of ProductCount.
注意,“TotalValue”的NotifyPropertyChange是从ProductCount的setter调用的。
I didn't do it all for you, but you can do similar things for your other properties as well. can do the similar things for your other properties that affect TotalValue.
我不是为你们做的,但是你们也可以为你们的其他属性做类似的事情。可以对影响TotalValue的其他属性执行类似的操作。