如何使方法可以重用不同的类型

时间:2016-06-23 14:43:06

标签: c# wpf mvvm

我在Visual Studio 2015中使用MVVM Light来构建WPF应用程序。代码中的一种方法在代码中重复了4次,略有变化;唯一的区别是被修改的ObservableCollection的类型和数据服务层上调用的方法。

这是方法,它返回ObservableCollectionStatusViewModel个对象,用于填充ComboBox; StatusVm用于绑定SelectedItem的{​​{1}},被设置为集合中的第一项,并且是#34;空白":

ComboBox

这里是private async Task<ObservableCollection<StatusViewModel>> GetStatuses() { var result = new ObservableCollection<StatusViewModel>(); var blank = new StatusViewModel { StatusId = -1, Status = null, Description = null, IsActive = false, CreatedDate = DateTime.Now }; result.Add(blank); var dataService = new MyDataService(); foreach (var c in await dataService.GetStatuses()) result.Add(c); StatusVm = result.SingleOrDefault(c => c.StatusId.Equals(-1)); return result; } 的私有字段和公共属性:

StatusVm

现在想象上面再重复3次,还有3种VM类型!如何将private StatusViewModel _statusVm; public StatusViewModel StatusVm { get { return _statusVm; } set { if (Equals(value, _statusVm)) return; _statusVm = value; RaisePropertyChanged(); } } 转换为可以采用不同视图模型类型并在数据服务上调用适当方法的方法?谢谢。

更新:以下是其他类型的属性和方法:

GetStatuses()

2 个答案:

答案 0 :(得分:3)

您可以为常用属性创建界面。

internal interface IStatusViewModel {
        int StatusId { get; set; }
        string Status { get; set; }
        string Description { get; set; }
        bool IsActive { get; set; }
        DateTime CreatedDate { get; set; }
}

在需要检索

状态的类中实现接口
internal class MroViewModel : IStatusViewModel {
        public int StatusId { get; set; }
        public string Status { get; set; }
        public string Description { get; set; }
        public bool IsActive { get; set; }
        public DateTime CreatedDate { get; set; }
}

使方法静态并传递服务函数,该函数将调用适当的方法来检索旧状态。

public static async Task<ObservableCollection<T>> GetStatuses<T>(
    Func<MyDataService, Task<IEnumerable<T>>> retrieveStatusesAction)
    where T : IStatusViewModel, new()
{
    var result = new ObservableCollection<T>();
    var blank = new T
    {
        StatusId = -1,
        Status = null,
        Description = null,
        IsActive = false,
        CreatedDate = DateTime.Now
    };
    result.Add(blank);

    var dataService = new MyDataService();
    foreach (var c in await retrieveStatusesAction(dataService))
        result.Add(c);

    // TODO Implement Expression<Func<TSource, TResult>> projection for assigning to VM
    StatusVm = result.SingleOrDefault(c => c.StatusId.Equals(-1));

    return result;
}

然后你会这样调用这个方法:

GetStatuses((service) => service.GetMro());

我没有对此进行测试,需要使用表达式编译来分配StatusVm。我现在将看看如何做到这一点,但这个想法就在那里。

对于表达式和属性赋值: Property selector Expression<Func<T>>. How to get/set value to selected property

- 编辑 -

VM分配的类似内容:

    public static async Task<ObservableCollection<T>> GetStatuses<T, TContainer>(
        TContainer instance,
        Expression<Func<TContainer, T>> viewModelProjection,
        Func<MyDataService, Task<IEnumerable<T>>> retrieveStatusesAction)
        where T : IStatusViewModel, new()
    {
        var result = new ObservableCollection<T>();
        var blank = new T
        {
            StatusId = -1,
            Status = null,
            Description = null,
            IsActive = false,
            CreatedDate = DateTime.Now
        };
        result.Add(blank);

        var dataService = new MyDataService();
        foreach (var c in await retrieveStatusesAction(dataService))
            result.Add(c);

        var vmStatus = result.SingleOrDefault(c => c.StatusId.Equals(-1));

        // Warning: Check casted values, this is unsafe
        var vm = (PropertyInfo)((MemberExpression)viewModelProjection.Body).Member;
        vm.SetValue(instance, vmStatus, null);

        return result;
    }

然后你会调用这样的方法:

await GetStatuses(this, inst => inst.MroVm, (service) => service.GetMro());

如果你不熟悉表情,我会解释。 第一个参数是视图模型实例所在的对象。第二个参数从该对象中选择与需要更改的视图模型对应的属性。最后一个参数是获取服务并返回检索状态的适当方法的函数 - 这就像指向C ++中函数的指针。

这将编译,但不确定它是否会按预期运行。这应该。如果您有任何问题,请在评论中写下来。

答案 1 :(得分:1)

您可以定义接口并尝试returnStrategy的组合,如下所示(为简单起见,我跳过async / await):

Factory

我实际上并没有在这里使用工厂,但您可以轻松创建虚拟机。