Обновление свойств и событие пинг-понга
В приложении WPF, которое использует Catel для MVVM Framework, у меня есть 3 различных свойства в модели представления
public double? QtaDiv1 { get; set; }
public double? Exchange{ get; set; }
public double? QtaDiv2 { get; set; }
Я переопределил OnPropertyChanged как
protected async override void OnPropertyChanged(AdvancedPropertyChangedEventArgs e)
{
if (e.PropertyName == "Data")
{
await GetValueDate(e);
}
else if (e.PropertyName == "QtaDiv1" || e.PropertyName == "Exchange")
{
ChangeQtaDiv2(QtaDiv1, Exchange);
}
if (e.PropertyName == "QtaDiv2")
{
ChangeQtaDiv1(QtaDiv2, Exchange);
}
else if (e.PropertyName == "SelectedCross")
{
await GetValueDate(e);
CheckForSplitVisibility();
}
base.OnPropertyChanged(e);
}
И что я делаю, если значения QtaDiv1 и Exchangehave я вычисляю QtaDiv2. В противном случае, если пользователь (и Exchange) изменяет QtaDiv2, я обновляю QtaDiv1.
Это работает нормально, пока я не обновлю QtaDiv2, так как в этот момент я получил PropertyChanged на QtaDiv1, который вызывает обновление QtaDiv2 и так далее...
Как я могу разрушить это заклинание??? Я думал о настройке строкового поля, содержащего изменяющееся значение, но если я сделаю это, мне придется подавить уведомление RaisePropertyChanged (и я должен преобразовать в свойство вспомогательного поля), чтобы я не получал проверку на них
Спасибо
2 ответа
Вам просто нужно добавить простую bool
переменная, чтобы указать, произошло ли изменение изнутри кода или нет:
private bool isInternalChange = false;
Если это внутреннее изменение, то вы можете игнорировать это:
if (!isInternalChange)
{
if (e.PropertyName == "Data")
{
await GetValueDate(e);
}
else if (e.PropertyName == "QtaDiv1" || e.PropertyName == "Exchange")
{
isInternalChange = true;
ChangeQtaDiv2(QtaDiv1, Exchange);
isInternalChange = false;
}
if (e.PropertyName == "QtaDiv2")
{
isInternalChange = true;
ChangeQtaDiv1(QtaDiv2, Exchange);
isInternalChange = false;
}
else if (e.PropertyName == "SelectedCross")
{
await GetValueDate(e);
CheckForSplitVisibility();
}
base.OnPropertyChanged(e);
}
Ответ @Sheridan правильный. Как указывает @Boris B., лучше попробовать это... наконец. Вы можете сделать это так, используя Catel:
if (!_isInternalChange)
{
if (e.HasPropertyChanged(() => Data))
{
await GetValueDate(e);
}
else if (e.HasPropertyChanged(() => QtaDiv1) || e.HasPropertyChanged(() => Exchange))
{
using (StartInternalChange())
{
ChangeQtaDiv2(QtaDiv1, Exchange);
}
}
if (e.HasPropertyChanged(() => QtaDiv2))
{
using (StartInternalChange())
{
ChangeQtaDiv1(QtaDiv2, Exchange);
}
}
else if (e.HasPropertyChanged(() => SelectedCross))
{
await GetValueDate(e);
CheckForSplitVisibility();
}
base.OnPropertyChanged(e);
}
private IDisposable StartInternalChange()
{
return new DisposableToken<MyClass>(this,
x => x._isInternalUpdate = false,
x => x._isInternalUpdate = true);
}