Реализация в модели (в паттерне MVVM), каждой публичной переменной так:
private bool _isGraphSet;
public bool isGraphSet {
get { return _isGraphSet; }
private set { _isGraphSet = value; OnPropertyChanged("isGraphSet"); }
}
Совсем не радует. Есть ли способы сделать все более человечески?
Я бы предложил воспользоваться такой заготовкой.
Для начала, вы определяете базовый класс для ваших 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) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged;
}
Затем, в ваших VM-классах вы пишете вот так:
class GraphVM : VM
{
private bool _isGraphSet;
public bool isGraphSet {
get { return _isGraphSet; }
private set { Set(ref _isGraphSet, value); }
}
}
К IL-weaver'ам наподобие Fody у меня неоднозначное отношение.
С одной стороны, AOP — это как бы хорошо и правильно.
С другой стороны, с Fody возникают баги. Хуже того, поскольку кодогенерация происходит за сценой, вряд ли получится влёгкую отлаживать связанные с этим проблемы, если что-то пошло не так: у вас ведь нету исходного кода!
Поэтому я бы подождал, пока в C# не будет реализовано replace/original (вот и вот), чтобы иметь над кодогенерацией полный контроль с возможностью пошаговой отладки.
Когда-то написал вот такой велосипед с использованием Castle DynamicProxy, который перехватывает вызов сеттера свойств в моделях представления и автоматически дергает PropertyChanged
:
// Базовый класс для всех VM
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
internal virtual void RaisePropertyChanged(string propertyName)
{
var evt = PropertyChanged;
if (evt != null)
evt(this, new PropertyChangedEventArgs(propertyName));
}
// Создание прокси к VM с помощью Castle.DynamicProxy
public static T Create<T>() where T : ViewModelBase
{
var generator = new ProxyGenerator();
return generator.CreateClassProxy<T>(new PropertyChangedInterceptor());
}
}
// Тестовая VM. Ручного кода, как видите, совсем нет
public class TestViewModel : ViewModelBase
{
public virtual string TestProperty { get; set; }
}
// Перехватчик обращений к свойствам
public class PropertyChangedInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var proxy = invocation.Proxy as ViewModelBase;
if (proxy != null && IsSetter(invocation.Method)) {
// если происходит вызов сеттера свойства в VM
// то получаем текущее значение свойства
// и, если оно изменилось, вызываем PropertyChanged
PropertyInfo property = GetPropertyBySetter(invocation.Method);
object currentValue = property.GetValue(proxy, null);
object newValue = invocation.Arguments[0];
if (IsModified(currentValue, newValue)) {
invocation.Proceed();
proxy.RaisePropertyChanged(property.Name);
}
} else {
invocation.Proceed();
}
}
public static bool IsModified(object currentValue, object newValue)
{
if (ReferenceEquals(currentValue, null))
return !ReferenceEquals(newValue, null);
return !currentValue.Equals(newValue);
}
public static PropertyInfo GetPropertyBySetter(MethodInfo mi)
{
return mi.DeclaringType.GetProperties().FirstOrDefault(p => p.GetSetMethod() == mi);
}
public static bool IsSetter(MethodInfo mi)
{
return mi.DeclaringType.GetProperties().Any(p => p.GetSetMethod() == mi);
}
}
Несмотря на то, что теперь в моделях представления вообще нет лишнего кода, мне самому до сих пор кое-что не нравится. Буду благодарен, если кто-нибудь покритикует это решение.
DataContext = ViewModelBase.Create<TestViewModel>()
). При этом конструктор сделать приватным нельзя (иначе возникнет исключение в ProxyGenerator
).property.GetValue(proxy, null)
инициирует рекурсивный вызов метода Intercept
(вроде бы обратиться напрямую к backing field автосвойства через рефлексию без хаков нельзя).RaisePropertyChanged
торчит наружу.Доброго времени суток! У меня есть dll написанная на C#Я дизассемблировал исходники этой dll с помощью ildasm
Здравствуйте! Подскажите пожалуйста как в WinForme сделать так чтобы программа считывала данные с файлаtxt и преобразовывала их в числа? А после...