PropertyChanged 影响多个属性
我遇到的情况是,我有几个变量,它们的值相互依赖,如下所示:
A 是 B 和 C 的函数 B 是 A 和 C 的函数 C 是 A 和 B 的函数
任一值都可以在 UI 上更改。我正在执行这样的计算和更改通知:
private string _valA;
private string _valB;
private string _valC;
public string ValA
{
get { return _valA; }
set
{
if (_valA != value)
{
_valA = value;
RecalculateValues("ValA"); //Here ValB and ValC are calculated
OnPropertyChanged("ValA");
}
}
}
public string ValB
{
get { return _valB; }
set
{
if (_valB != value)
{
_valB = value;
RecalculateValues("ValB"); //Here ValA and ValC are calculated
OnPropertyChanged("ValB");
}
}
}
(...)
private void RecalculateValues(string PropName)
{
if (PropName == "ValA")
{
_valB = TotalValue * _valA;
OnPropertyChanged("ValB");
_valC = something * _valA
OnPropertyChanged("ValC");
}
else
(...)
}
我在已更改变量的设置器上调用计算方法,计算 _valB、_valC 的值(例如),然后为这些值调用 PropertyChanged。 我这样做是因为变量之间的依赖关系,这样我可以控制使用正确的值计算哪个变量。我还考虑过触发其他变量的 PropertyChanged 并对变量的 getter 执行计算,但我必须知道之前更改了哪个属性并使用该值...不确定这是否是最好/最简单的解决方案。
这是一个好方法吗?我不喜欢在 setter 块上执行此操作的想法,但当时我看不到任何更好的方法来执行此操作。您是否看到任何其他(更好或更干净的解决方案)?
我遇到的另一个问题是使用 IdataErrorInfo 进行验证/向 UI 呈现错误信息。问题是 this[columnName] 索引器在 setter 末尾被调用,我需要在计算之前验证值,这样如果值输入无效,计算不会发生。我正在认真考虑放弃 IDataErrorInfo 并在计算发生之前简单地调用我的验证方法。有什么方法可以显式调用它或在值归属之后立即调用它吗?
注意:ValidationRules 不是一个选项,因为我需要从 ViewModel 调用另一个对象的验证逻辑。
I have a situation where I have a couple of variables who's values depend on each other like this:
A is a function of B and C
B is a function of A and C
C is a function of A and B
Either value can change on the UI. I'm doing the calculation and change notification like this:
private string _valA;
private string _valB;
private string _valC;
public string ValA
{
get { return _valA; }
set
{
if (_valA != value)
{
_valA = value;
RecalculateValues("ValA"); //Here ValB and ValC are calculated
OnPropertyChanged("ValA");
}
}
}
public string ValB
{
get { return _valB; }
set
{
if (_valB != value)
{
_valB = value;
RecalculateValues("ValB"); //Here ValA and ValC are calculated
OnPropertyChanged("ValB");
}
}
}
(...)
private void RecalculateValues(string PropName)
{
if (PropName == "ValA")
{
_valB = TotalValue * _valA;
OnPropertyChanged("ValB");
_valC = something * _valA
OnPropertyChanged("ValC");
}
else
(...)
}
I'm calling the calculation method on the setter of the changed variable, calculating the values for _valB, _valC (for example) and then calling PropertyChanged for these ones.
I do it like this because of the dependencies between the variables, like this i can control which variable gets calculated with the correct values. I also thought about triggering the PropertyChanged for the other variables and perform the calculation on the getter of the variables but i would have to know which property changed before and use that value...not sure if it's the best/simplest solution.
Is this a good way to do this? I don't like the idea of performing this on the setter block, but at the time I can't see any better way to do it.do you see any other (better or cleaner solution)?
Another issue I have is using IdataErrorInfo for validation/presenting error info to the UI.The thing is the this[columnName] indexer gets called at the end of the setter and I needed to validate the values before the calculation, so that if the value inputted is not valid the calculation would not happen.I'm seriously considering abandoning IDataErrorInfo and simply calling my validation method before the calculation(s) occurs. Is there any way to explicitly calling it or right after the value attribution?
NOTE: ValidationRules are not an option because I need to call validation logic on another object from my ViewModel.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
可以在 Setter 中调用您的验证和计算,只要它不阻塞线程并进行大量 CPU 密集型计算即可。如果您有简单的 5 到 10 个基于数学的语句而不涉及复杂的循环,那就没问题。
对于数据绑定和WPF,这是唯一的方法,但是还有一种名为IEditableObject的实现,它具有BeginEdit、CancelEdit和EndEdit,您可以在其中对“EndEdit”函数进行计算和验证。
在 BeginEdit 中,您可以将所有值保存在临时存储中,在 CancelEdit 中,您可以从临时存储中带回所有值,并为所有已修改的值触发 PropertyChanged 事件,在 EndEdit 中,您最终可以更新所有变量并为所有这些值触发 PropertyChanged 。已更新。
IEditableObject 对于性能而言是最好的,但在取消或结束之前它可能不会显示新值,但是要立即显示,唯一的方法就是您正在执行的方式。
如果 CPU 使用率很高,您可以调用另一个线程来进行计算并设置变量,最后您可以触发 PropertyChanged,但是从技术上讲,您只是在异步地在 setter 中设置值时做同样的事情。
Its alright to call your Validation and Calculation in Setter, as long as it does not block the thread and goes into heavy cpu intensive calculations. If you have simple 5 to 10 math based statements without involving complex loops, its alright.
For databinding and WPF, this is the only way, However there is one more implementation called IEditableObject which has BeginEdit, CancelEdit and EndEdit, where you can do your calculation and validation on "EndEdit" function.
In BeginEdit, you can save your all values in temp storage, in CancelEdit you can bring back all values from temp and fire PropertyChaged event for all values those were modified and in EndEdit, you can finally update all variables and fire PropertyChanged for all those are updated.
IEditableObject will be best for performance wise, but it may not display new values until it was cancelled or ended, however to display instantly the only way to do is the way you are doing it.
In case of heavy cpu usage, you can invoke another thread to do calculation and set variables and at the end you can fire PropertyChanged, but yes technicaly you are just doing same thing while setting value in setter but asynchronously.
由于您可以从类中的任何位置调用 NotifyPropertyChanged,因此简化此操作的一种方法是让您的Calculate 方法为所有三个变量触发 NotifyPropertyChanged。当我进行具有多重依赖性的复杂计算时,我会使用这个技巧。有时您仍然想在 Setter 中触发事件:在这种情况下,当我从计算中更新属性时,我会使用标志字段来禁用该事件,以便该事件不会触发两次。
Since you can evoke NotifyPropertyChanged from anywhere in the class, one way to simplify this is to have your Calculate method fire the NotifyPropertyChanged for all three variables. I use this trick when I have complex calculations with multi-dependencies. Sometimes you'll still want to fire the event in the Setter: in that case I use a flag field to disable the event when I am updating the property from within the Calculations so that the event is not fired twice.