ViewModel自动具有与通用模型相同的属性

问题描述 投票:0回答:2

我正在尝试在下面的代码中为用例创建代码,其中一般的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);
    }
}
c# mvvm data-binding inotifypropertychanged .net-4.6
2个回答
2
投票

您可以使用Fody自动注入代码,以便在编译时为模型类的所有属性引发PropertyChanged事件。

然后你可以直接绑定到Rectangle而不修改它并显式实现INotifyPropertyChanged接口。

否则,我担心您必须在每个视图模型中逐个定义每个属性,或者在构建之前想出一种自动生成视图模型类的方法。


0
投票

你正在寻找的是这样的东西吗?

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.