Как реализовать наблюдаемый int в wpf ViewModel?
В моем mvvm ViewModel у меня есть такое поле
public int Delta { get; private set; }
Однако, когда я обновляю его так:
Delta = newValue;
Пользовательский интерфейс не обновляется.
Я думал, что привязка данных сделает это для меня. Например, я могу объявить коллекцию как ObservableCollection
, а затем будет работать привязка данных.
Однако нет ObservableInt
, как сказать View, что его нужно обновить тогда?
Возможно, я должен поднять какое-то событие "изменить свойство уведомления" или что-то еще?
Ответы
Ответ 1
У вас есть два варианта:
- Внедрите
INotifyPropertyChanged
интерфейс в своем классе.
- Наследовать от DependencyObject и реализовать Delta как DependencyProperty.
Самый простой вариант - # 1. Вы можете легко реализовать интерфейс INotifyPropertyChanged в своем классе:
public class YourClass : INotifyPropertyChanged
{
private int _delta;
public int Delta
{
get { return _delta; }
set { _delta = value; NotifyPropertyChanged("Delta"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Вы можете больше узнать о использовании и внедрении свойств зависимостей в MSDN.
Ответ 2
Просто реализуйте интерфейс INotifyPropertyChanged в своем классе и используйте его, чтобы поднять PropertyChanged для вашего свойства, а затем обновить пользовательский интерфейс. Если вы используете шаблон проекта MVVM, то есть хороший шанс, что у вас уже есть вспомогательный метод, вам нужно только его использовать.
MSDN INotifyPropertyChanged
GalaSoft MVVM Light Toolkit
Ответ 3
ObservableCollection
автоматически генерирует события, но для ваших собственных свойств вы должны сами создавать события.
Хороший пример: http://www.codeproject.com/Tips/228352/Naming-Properties-in-MVVM?display=Print
Я бы предложил использовать mvvm light: http://mvvmlight.codeplex.com, я использовал его в приложениях silverlight и wpf. Очень проста в использовании и обеспечивает систему сообщений между моделью, моделью просмотра и представлением.
Ответ 4
Используя @LBushKin Ответ, я изменил его на
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value; }
set { _value = value; NotifyPropertyChanged("Value"); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
и настроить его:
class MainWindow ...
// a bool with initial value of true
public static Prop<bool> optionBool { get; set; } = new Prop<bool>{ Value = true };
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// connect
DataContext = this;
}
и использовать его:
<Grid ...
<CheckBox Content="Da Check" ... IsChecked="{Binding optionBool.Value}"/>
Ответ 5
Пока мы с этим улучшаем ответ, некоторые из других новых дополнений С# 6.0 и 7.0 помогают сделать его еще более компактным:
public class Prop<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set { _value = value; NotifyPropertyChanged(nameof(_value)); }
}
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(String propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Таким образом, вы не используете какие-либо "внедренные значения" (например, имя свойства) и сохраняете рефакторинг кода безопасным.
Кроме того, нет необходимости в избыточных блоках кода из-за новых функций тела выражения С# 6.0 и 7.0