У меня есть TextBox, Значение которого связывается со свойством ViewModel:
<TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding Mode=TwoWay, Path=RunAfter}" Style="{StaticResource TestStepTextBox}"/>
Набор и добирается, хорошо работали, пока я не пытался добавить некоторую проверку, когда Значение установлено:
private int _runAfter = 0;
public string RunAfter
{
get
{
return _runAfter.ToString();
}
set
{
int val = int.Parse(value);
if (_runAfter != val)
{
if (val < _order)
_runAfter = val;
else
{
_runAfter = 0;
OnPropertyChanged("RunAfter");
}
}
}
}
Хотя OnPropertyChanged достигнут (у меня есть dubugged, что), Представление не изменяется. Как я могу сделать эту работу?
Спасибо, José Tavares
Проблема в том, что вы обновляете источник для Binding
, в то время как Binding
обновляет ваше свойство. WPF фактически не проверяет значение вашего свойства, когда поднимает событие PropertyChanged
в ответ на обновление Binding
. Вы можете решить эту проблему, используя Диспетчер
для задержки распространения события в этой ветке:
set
{
int val = int.Parse(value);
if (_runAfter != val)
{
if (val < _order)
{
_runAfter = val;
OnPropertyChanged("RunAfter");
}
else
{
_runAfter = 0;
Dispatcher.CurrentDispatcher.BeginInvoke(
new Action<String>(OnPropertyChanged),
DispatcherPriority.DataBind, "RunAfter");
}
}
}
Update:
Другая вещь, которую я заметил, это то, что Binding
на вашем TextBox
использует стандартный UpdateSourceTrigger
, который происходит, когда TextBox
теряет фокус. В этом режиме вы не увидите, как текст изменится на 0, пока TextBox
не потеряет фокус. Если вы измените его на PropertyChanged
, вы увидите, что это произойдет немедленно. В противном случае, ваше свойство не будет установлено, пока ваш TextBox
не потеряет фокус:
<TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding RunAfter, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TestStepTextBox}"/>
Несколько вещей, которые я заметил здесь.
Если у вас нет веских причин для предоставления свойства RunAfter в виде строки, нет причин, по которым оно не может быть int. Это сэкономит вам приведения в сеттере (а также скрывающегося возможного исключение InvalidCastException, если пользователь введет в поле что-то не целое число).
Во-вторых, вызов OnPropertyChanged() должен происходить вне внутренней инструкции if, как по следующему:
if(_runAfter != val)
{
if(val < _order)
_runAfter = val;
else
_runAfter = 0;
OnPropertyChanged("RunAfter");
}
Поскольку _runAfter local обновляется в обоих путях условного условия, OnPropertyChanged() должен вызываться независимо от принятой ветви. Я надеюсь, что это поможет вам указать правильное направление!