Silverlight: Mvvm, INotifyPropertyChanged и свойства
За последнее время я увидел много постов, расказывающих о том как упростить процес создания свойств которые вызывают событие PropertyChanged. Это и codesnippet'ы и атрибуты для генерации кода... Решил написать о своем варианте который не использует ни то ни другое (намного проще).
И так, стандартный код свойства в MVVM:
private string _name;
public string Name
{
get { return _name; }
set
{
if ( _name != value)
{
_name = value;
RaisePropertyChanged("Name");
}
}
}
А теперь если представить что таких полей у вас должно быть 10 - это приведет к тому, что в коде будет очень много лишнего, может даже намного больше чем самой логики... да можно отнести эти все свойства в partial класс, но для каждой модели создавать отдельный partial класс - не рационально (по моему мнению).
В своих проектах я использую следующие решение (я не говорю что это самое лутше/оптимальное решение - но для меня оно самое удобное)
1. Для начала создадим класс DataValue:
public class DataValue : INotifyPropertyChanged
{
protected object _value;
public DataValue(object value)
{
_value = value;
}
public object Value
{
get { return _value; }
set
{
if ( _value != value)
{
_value = value;
RaisePropertyChanged("Value");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Думаю это код понятен....
2. Создадим безовый класс для модели - ModelBase:
public class ModelBase
{
public ModelBase()
{
Values = new Dictionary<string, DataValue>(10, StringComparer.OrdinalIgnoreCase);
}
public Dictionary<string, DataValue> Values { get; private set; }
protected void SetValue<T>(string key, T value)
{
DataValue dataValue;
if (!Values.TryGetValue(key, out dataValue))
Values.Add(key, new DataValue(value));
else
dataValue.Value = value;
}
protected T GetValue<T>(string key)
{
return (T) Values[key].Value;
}
}
Словарь Values - будет хранить все наши значения в одном месте, доступ к определенному значению будет воспроизводиться по строковому ключу. Так как этот словарь не typesafe, создали два метода SetValue и GetValue для простоты. Также обратите внимание при создании словаря, мы указываем StringComparer.OrdinalIgnoreCase - поэтому нам не придеться задумываться о регистре ключа значения.
3. Создаем модель для нашей главной странице - MainPage
public class MainPageModel : ModelBase
{
internal const string VALUENAME = "name";
internal const string VALUEAGE = "age";
public MainPageModel()
{
Initialize();
}
private void Initialize()
{
SetValue(VALUENAME, "Boris");
SetValue(VALUEAGE, 19);
}
}
Модель MainPageModel наследуеться от ранее созданого класса ModelBase.
Создали две константы - ключи значений. Обязательно нижно проинициализировать значения во время создания класса, так как если это сделать пожже, в UI они не подхватяться, так как словарь Values это не ObservableDictionary (стандартного нету).
4. Xaml - MainPage.xaml
Биндинг осуществляется так:
- Только для чтения - {Binding Values[value_key].Value}
- Для чтения и записи - {Binding Values[value_key].Value, Mode=TwoWay}
Основная часть xaml разметки примера:
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Margin="96,125,84,0" Background="White">
<TextBlock Text="{Binding Values[name].Value}" Width="150" Margin="2"/>
<TextBlock Text=", " Margin="2"/>
<TextBlock Text="{Binding Values[age].Value}" Width="50" Margin="2"/>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="77,0,61,112">
<TextBlock Text="name:"/>
<TextBox Text="{Binding Values[name].Value, Mode=TwoWay}" Width="150"/>
<TextBlock Text="age:"/>
<TextBox Text="{Binding Values[age].Value, Mode=TwoWay}" Width="50"/>
</StackPanel>
Выглядеть оно будет так:

Плюсы и минусы:
- "+" Чистота кода, все значения храняться в одном месте
- "+" Возможность добавить дополнительные поля для каждого значения. Например, добавить в класс DataValue такое поле как IsValid.
- "-" Невозможность контролировать (легким способом) значение которое меняеться в DataValue, только когда будет вызвана какая-то функция в модели.
Скачать проект можно тут.
Спасибо, критика и пожелания приветствуються.