Переход на другую версию Visual Studio, INotifyPropertyChanged

409
13 февраля 2017, 13:25

Добрый день, пользовался VS2016. Сейчас решил перейти на версию 2013, открыл проект на 2013 версии, мне начало выдавать ошибки при работе с INotifyPropertyChanged:

PropertyChanged(this, new PropertyChangedEventArgs(nameof(SelectedItemInListView)));

Ругается на nameof:

Error   1   The name 'nameof' does not exist in the current context D:\WpfApplication7\WpfApplication7\CreateGroup.xaml.cs  47  68  WpfApplication7

В чем может быть проблема? Версию .NET установил так же как и на прошлой студии (4.6.1)

Свойство целиком:

public Item SelectedItemInListBox
    {
        get { return _SelectedItemInListBox; }
        set
        {
            _SelectedItemInListBox = value;
            //сообщаем о том, что элемент изменился
            PropertyChanged(this, new PropertyChangedEventArgs(nameof(SelectedItemInListBox)));
        }
    }
Answer 1

nameof это фича C#6. Visual Studio 2013 поддерживает версии до C#5 включительно. Компилятор просто не понимает, что это за слово.

Answer 2

В дополнение к ответу @Ruslan Artamonov, в C# 5 имеет смысл использовать такую магию:

protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
    if (PropertyChanged != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

Имея этот метод в вашем классе (или его базовом классе), вы можете писать просто

public Item SelectedItemInListBox
{
    get { return _SelectedItemInListBox; }
    set { _SelectedItemInListBox = value; RaisePropertyChanged(); }
}

или лучше

public Item SelectedItemInListBox
{
    get { return _SelectedItemInListBox; }
    set
    {
        if (_SelectedItemInListBox == value)
            return;
        _SelectedItemInListBox = value;
        RaisePropertyChanged();
    }
}

Таким образом вам не нужно упоминать точное имя свойства вовсе, оно установится самостоятельно через магию [CallerMemberName].

Возможно, имеет смысл ещё сократить ваш код, и создать общий базовый класс для всех VM-классов:

class VM : INotifyPropertyChanged
{
    protected bool Set<T>(ref T field, T value,
                         [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;
        field = value;
        RaisePropertyChanged(propertyName);
        return true;
    }
    protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

Имея такой базовый класс, вы можете писать так:

class MyListVM : VM
{
    Item _SelectedItemInListBox;
    public Item SelectedItemInListBox
    {
        get { return _SelectedItemInListBox; }
        set { Set(ref _SelectedItemInListBox, value); }
    }
}

Кстати, для C# 6 (Visual Studio 2015 и старше) можно использовать тот же трюк с более компактной записью:

protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Answer 3

Начиная с 3 версии C# можно использовать также и Expressions

    protected void OnPropertyChanged<T>(Expression<Func<T>> expr)
    {
        var member = (MemberExpression)expr.Body;
        var handler = Volatile.Read(ref PropertyChanged);
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(member.Member.Name));
    }
READ ALSO
Обновить после добавления в БД (MySQL)

Обновить после добавления в БД (MySQL)

Добрый день, подскажите как обновить табличку по клику на кнопку:

364
Не удается записать в ListView

Не удается записать в ListView

Есть класс, содержащий строку String и целое число int

314
Доступ к массиву из другого класса

Доступ к массиву из другого класса

Здравствуйте, только начала изучать C#, столкнулся с такой проблемой

451