#wpf #binding #inotifypropertychanged
#wpf #привязка #inotifypropertychanged
Вопрос:
У меня есть набор элементов управления, для которых определенное значение всегда допустимо, но другие допустимы или недопустимы в зависимости от некоторой логики. Эта логика спроектирована таким образом, что она никогда не сможет сама себя аннулировать: при вызове logic.setState( … ) с недопустимым параметром она вернет false и сгенерирует сообщение об ошибке, но на ее внутренние компоненты это не повлияет. Другими словами, его состояние не меняется. И я хочу, чтобы это отражалось на экране, но не могу понять, что не так с кодом.
Вот пример того, чего я хотел бы достичь с помощью ComboBox, но то же самое относится к набору флажков или даже текстовых полей, то есть к любым элементам управления, принимающим пользовательский ввод. xaml:
<ComboBox ItemsSource="{Binding Path=States}"
SelectedItem="{Binding Path=State}"/>
код:
public string State
{
get { return state; }
set
{
if( value != "invalid" )
state = value;
else
ShowError(); //tell user this selection was not ok
RaisePropertyChanged( "State" ); //the usual INotifyPropertyChanged method
}
}
public string[] States
{
get { return new string[] { "none", "valid", "invalid" }; }
}
private string state;
Начальное значение для состояния установлено в «none». Когда пользователь выбирает «допустимый», члену состояния присваивается новое значение и публикуется изменение свойства.
Однако, когда пользователь выбирает «недопустимый», состояние элемента не изменяется, однако в выпадающем списке отображается «недопустимый». Следовательно, существует несоответствие между тем, что отображается на экране («недопустимо»), и эффективным значением, используемым в приложении («допустимо»), и я бы предпочел избежать этого.
-
Я не понимаю, почему в выпадающем списке по-прежнему отображается «недопустимый»: у меня создалось впечатление, что при вызове RaisePropertyChanged («Состояние» ) выпадающий список будет запущен, чтобы получить значение State и отобразить его, тем самым снова установив для выпадающего списка значение «действительный»?
-
Есть ли способ сделать это? Обратите внимание, что код находится в классе в стиле ViewModel, который не знает о ComboBox.
-
Не лучше ли не делать этого таким образом, а вместо этого полагаться на «обычные» методы проверки? Например, я мог бы реализовать IDataErrorInfo и показать сообщение, сообщающее пользователю, что отображаемое в данный момент значение недействительно, с красной рамкой вокруг него и т.д. В то же время мне также пришлось бы отключить практически все другие элементы управления, пока этот элемент управления снова не станет действительным (поскольку другие части приложения будут использовать другое значение, которое затем будет отображаться на экране, результаты могут быть довольно неожиданными).
Ответ №1:
Вызов события PropertyChanged игнорируется, когда пользовательский интерфейс вызывает установщик. Существует известный способ обойти это, когда, если у вас есть конвертер в вашей привязке, он правильно обрабатывает PropertyChange. Решение заключается в создании фиктивного конвертера, который просто возвращает переданное значение. Смотрите эту статью о том, как вы можете это сделать:
http://www.lhotka.net/weblog/DataBindingIssueInWPFWithSolution.aspx
Чтобы ответить на вопрос 3 в вашем списке, да, я обычно использую именно такой подход. Никогда не меняйте значение пользователя обратно на что-то для них, а вместо этого показывайте ошибку и позволяйте им изменять ее обратно.
Комментарии:
1. 1 за ссылку и ваш комментарий к q3. Для пользователя действительно может быть удивительно увидеть, что его значение было возвращено.