ViewModel, которая автоматически обладает теми же свойствами, что и универсальная модель - PullRequest
0 голосов
/ 27 марта 2019

Я пытаюсь создать код для варианта использования в приведенном ниже коде, где универсальный класс ViewModel «захватывает» все свойства из своей модели и представляет свойства с тем же именем и типом, а также запускает PropertyChanged событие для привязки данных.

Есть ли способ сделать это?Я использую .NET 4.6.

public class Rectangle
{
    public double Width {get; set;}
    public double Height {get; set;}
}

public class RectangleViewModel : MagicViewModel<Rectangle>
{
    public RectangleViewModel(Rectangle model) 
        : base(model){ }
}

public class MagicViewModel<TModel> : INotifyPropertyChanged
{
    protected readonly TModel _model;

    public MagicViewModel(TModel model)
    {
        _model = model;
    }

    // inpc implementation

    // what else?
}

public class Program
{
    public static void Main(string[] args)
    {
        var vm = new RectangleViewModel(new Rectangle());
        var calls = 0;
        vm.PropertyChanged += (sender, args) => calls++;
        vm.Height = 10;  // magic happened here
        Debug.Assert(calls > 0);
    }
}

Ответы [ 2 ]

2 голосов
/ 27 марта 2019

Вы можете использовать Fody для автоматического ввода кода, который вызывает событие PropertyChanged для всех свойств классов модели в время компиляции .

Тогда вы можете напрямую связать с Rectangle, не изменяя его, и явно реализовать интерфейс INotifyPropertyChanged.

В противном случае я боюсь, что вам придется определять каждое свойство по одномуодин, в каждой модели представления или придумать способ автоматической генерации классов модели представления перед сборкой.

0 голосов
/ 27 марта 2019

Это то, что вы ищете?

using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;

public class Rectangle : INotifyPropertyChanged
{
    private double height;

    public double Width { get; set; }
    public double Height { get => height; set => SetField(ref height, value); }

    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    #endregion
}

public class RectangleViewModel : MagicViewModel<Rectangle>
{
    public RectangleViewModel(Rectangle model)
        : base(model)
    {
        this.model = model;
        model.PropertyChanged += (s, e) => OnPropertyChanged(e.PropertyName);
    }

    private Rectangle model;

    public Rectangle Model { get => model; set => SetField(ref model, value); }
}

public class MagicViewModel<TModel> : INotifyPropertyChanged
{
    protected readonly TModel _model;

    public MagicViewModel(TModel model)
    {
        _model = model;
    }

    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    #endregion
}

public class Program
{
    public static void Main(string[] args)
    {
        var vm = new RectangleViewModel(new Rectangle());
        var calls = 0;
        vm.PropertyChanged += (sender, propChangedArgs) => calls++;
        vm.Model.Height = 10;  // magic happened here
        Debug.Assert(calls > 0);
    }
}
...