封装一个ViewModel的基类AbstractViewModel,继承自ViewModel

提供泛型参数,传入具体类的.class即可拿到MutableLiveData实例。

注:以类的.class为key,所以获取到的MutableLiveData具有唯一性(其他AbstractViewModel子类不在此列)。

例如:
 

// ViewModel子类

public class MyViewModel extends AbstractViewModel {

      public void query() {

             getMutableLiveData(String.class).postValue("dfafafdafafdafda");

      }

}

// 加入观察者

MyViewModel viewModel = ViewModelProviders.of(activity).get(MyViewModel.class);

MutableLiveData<String> liveData = viewModel.getMutableLiveData(String.class);

liveData.observe(owner,  new Observer<String>() {

      public void onChange(String str) {

            Log.d(str);

      }

});

此方式是所有MyViewModel中注册到String.class的观察者都能收到通知。

避免此问题的解决方案例子: 

// 加入将String内容封闭到一个类中。

static class StringBean {

    private String value;

    StringBean(String value) {

        this.value = value;

    }

    public String getValue() {return value);}

}

// ViewModel子类

public class MyViewModel extends AbstractViewModel {

      public void query() {

             getMutableLiveData(StringBean.class).postValue(new StringBean("string bean object"));

      }

}

// 加入观察者

MyViewModel viewModel = ViewModelProviders.of(activity).get(MyViewModel.class);

MutableLiveData<StringBean> liveData = viewModel.getMutableLiveData(StringBean.class);

liveData.observe(owner,  new Observer<StringBean>() {

      public void onChange(StringBean bean) {

             Log.d(bean.getValue());
      }

});

 

封装ViewModel的基类源代码:

 


/**
 * 定义了包含不同类型的MutableLiveData实例,效果如MutableLiveData<T>和MutableLiveData<List<T>>
 */
public class AbstractViewModel extends ViewModel {

    /*
        分两个map是为了MutableLiveData<T>和MutableLiveData<List<T>>不会互相覆盖,因为Key值都是T类型的.class
     */

    /**
     * 此map直接存储实例MutableLiveData(泛型T)
     */
    private Map<Class<?>, MutableLiveData<?>> map = new HashMap<>();

    /**
     * 此map直接存储实例MutableLiveData(List包含泛型T)
     */
    private Map<Class<?>, MutableLiveData<?>> map2 = new HashMap<>();

    /**
     * 创建一个类型是T的MutableLiveData实例
     * @param t T类的.class
     * @param <T> T类型
     * @return MutableLiveData实例
     */
    @SuppressWarnings("unchecked")
    public <T> MutableLiveData<T> getMutableLiveData(Class<T> t) {
        MutableLiveData<?> liveData = map.get(t);

        if (liveData == null) {
            liveData = new MutableLiveData<T>();
            map.put(t, liveData);
        }
        return (MutableLiveData<T>) liveData;
    }

    /**
     * 创建一个类型是List的MutableLiveData实例
     * @param t T类的.class
     * @param <T> T类型
     * @return MutableLiveData实例
     */
    @SuppressWarnings("unchecked")
    public <T> MutableLiveData<List<T>> getMutableLiveDataList(Class<T> t) {
        MutableLiveData<?> liveData = map2.get(t);

        if (liveData == null) {
            liveData = new MutableLiveData<List<T>>();
            map2.put(t, liveData);
        }
        return (MutableLiveData<List<T>>) liveData;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用 Prism 框架进行 WPF 开发时,可以使用 `ErrorsContainer` 来进行数据验证。`ErrorsContainer` 一个 Prism 框架提供的数据验证,可以将数据验证错误信息保存在 `Errors` 字典中,并且可以绑定到 UI 上进行显示。 以下是将 `ErrorsContainer` 封装到 View Model 基类里的代码示例: ```csharp using Prism.Mvvm; using Prism.Commands; using Prism.Validation; public abstract class BaseViewModel : BindableBase, IValidatableBindableBase { protected ErrorsContainer<string> errorsContainer; public BaseViewModel() { errorsContainer = new ErrorsContainer<string>(OnErrorsChanged); } public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public System.Collections.IEnumerable GetErrors(string propertyName) { return errorsContainer.GetErrors(propertyName); } public bool HasErrors { get { return errorsContainer.HasErrors; } } protected virtual void OnErrorsChanged([CallerMemberName] string propertyName = null) { ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); } protected void ValidateProperty<T>(Expression<Func<T>> propertyExpression, T value) { var propertyName = ((MemberExpression)propertyExpression.Body).Member.Name; errorsContainer.ClearErrors(propertyName); Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = propertyName }); } protected void ValidateObject() { errorsContainer.ClearErrors(); Validator.ValidateObject(this, new ValidationContext(this, null, null)); } protected bool SetPropertyAndValidate<T>(ref T field, T value, Expression<Func<T>> propertyExpression) { if (EqualityComparer<T>.Default.Equals(field, value)) { return false; } field = value; RaisePropertyChanged(propertyExpression); ValidateProperty(propertyExpression, value); return !HasErrors; } } ``` 在这个基类中,我们继承了 Prism.Mvvm 中的 `BindableBase` ,并实现了 `IValidatableBindableBase` 接口。在构造函数中,我们初始化了 `ErrorsContainer` 对象,并将 `OnErrorsChanged` 方法作为参数传入。`OnErrorsChanged` 方法会在数据验证错误信息发生变化时被调用,我们可以在这个方法中更新 UI。 在 `GetErrors` 方法中,我们通过传入的属性名来获取对应的验证错误信息。在 `HasErrors` 属性中,我们判断当前是否存在验证错误信息。 在 `ValidateProperty` 方法中,我们通过传入的属性表达式和属性值来进行属性验证,并将验证结果保存到 `ErrorsContainer` 中。在 `ValidateObject` 方法中,我们通过对整个对象进行验证,并将验证结果保存到 `ErrorsContainer` 中。 最后,在 `SetPropertyAndValidate` 方法中,我们通过传入的字段引用、属性表达式和属性值来进行属性赋值并进行验证。 使用这个基类的子在进行数据验证时,只需要在属性的 set 方法中调用 `SetPropertyAndValidate` 方法,并传入对应的字段引用、属性表达式和属性值即可。同时,在 UI 中绑定数据时,需要使用 `ErrorsContainer` 中的 `GetErrors` 方法来获取对应的错误信息,并将结果绑定到 UI 上进行显示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值