C# Prism MVVM ViewModel属性支持字段作为模型';s属性

C# Prism MVVM ViewModel属性支持字段作为模型';s属性,c#,wpf,mvvm,prism,viewmodel,C#,Wpf,Mvvm,Prism,Viewmodel,我是Prism MVVM的新手,尝试创建ViewModel属性,该属性具有模型属性的支持字段 public class SomeViewModel : BindableBase, INavigationAware { private Person model; public Person Model { get { return model; } set { SetProperty(ref m

我是Prism MVVM的新手,尝试创建ViewModel属性,该属性具有模型属性的支持字段

public class SomeViewModel : BindableBase, INavigationAware
    {
        private Person model;
        public Person Model
        {
            get { return model; }
            set { SetProperty(ref model, value); }
        }

        public string DisplayName
        {
            get { return Model.DisplayName; }
            set { SetProperty(ref Model.DisplayName, value); }
        }
但它会在第行生成编译器错误:

set { SetProperty(ref Model.DisplayName, value); }
“属性或索引器不能作为out或ref参数传递”


那么我应该怎么做呢?

您需要手动启动OnPropertyChanged,并在没有助手的情况下设置它

  public string DisplayName
    {
        get { return Model.DisplayName; }
        set 
        {
            Model.DisplayName = value;
            OnPropertyChanged();
        }
    } 

您需要手动提升OnPropertyChanged,并在没有帮助器的情况下设置它

  public string DisplayName
    {
        get { return Model.DisplayName; }
        set 
        {
            Model.DisplayName = value;
            OnPropertyChanged();
        }
    } 

您可以使用
Reflection
并创建类似于
BindableBaseExtended
的东西,它继承自
Prism.Mvvm.BindableBase

public class SomeViewModel : BindableBaseExtended
{
    private Person model;
    public Person Model
    {
        get { return model; }
        set { SetProperty(ref model, value); }
    }
    public string MyProperty
    {
        get { return Model.DisplayName; }
        set { SetProperty(Model, m => m.DisplayName, value); }
    }
}

public class BindableBaseExtended : BindableBase
{
    protected virtual bool SetProperty<TClass, TMember>(TClass target, Expression<Func<TClass, TMember>> expression, TMember value, [CallerMemberName] string propertyName = null)
    {
        var expr = (MemberExpression)expression.Body;
        var prop = (PropertyInfo)expr.Member;
        var propValue = prop.GetValue(target, null);
        if (object.Equals(propValue, value)) return false;

        prop.SetValue(target, value, null);
        this.RaisePropertyChanged(propertyName);
        return true;
    }
    protected virtual bool SetProperty<TClass, TMember>(TClass target, Expression<Func<TClass, TMember>> expression, TMember value, Action onChanged, [CallerMemberName] string propertyName = null)
    {
        var expr = (MemberExpression)expression.Body;
        var prop = (PropertyInfo)expr.Member;
        var propValue = prop.GetValue(target, null);
        if (object.Equals(propValue, value)) return false;

        prop.SetValue(target, value, null);
        onChanged?.Invoke();
        this.RaisePropertyChanged(propertyName);
        return true;
    }
}
公共类SomeViewModel:BindableBaseExtended
{
私人模式;
公众人物模型
{
获取{返回模型;}
set{SetProperty(ref model,value);}
}
公共字符串MyProperty
{
获取{return Model.DisplayName;}
set{SetProperty(Model,m=>m.DisplayName,value);}
}
}
公共类BindableBaseExtended:BindableBase
{
受保护的虚拟bool SetProperty(TClass目标,表达式,TMember值,[CallerMemberName]字符串propertyName=null)
{
var expr=(MemberExpression)expression.Body;
var prop=(PropertyInfo)expr.Member;
var propValue=prop.GetValue(目标,空);
if(object.Equals(propValue,value))返回false;
prop.SetValue(目标、值、空);
this.RaisePropertyChanged(propertyName);
返回true;
}
受保护的虚拟bool SetProperty(TClass目标、表达式、TMember值、操作onChanged、[CallerMemberName]字符串propertyName=null)
{
var expr=(MemberExpression)expression.Body;
var prop=(PropertyInfo)expr.Member;
var propValue=prop.GetValue(目标,空);
if(object.Equals(propValue,value))返回false;
prop.SetValue(目标、值、空);
onChanged?.Invoke();
this.RaisePropertyChanged(propertyName);
返回true;
}
}

您可以使用
反射
并创建类似于
BindableBaseExtended
的东西,它继承自
Prism.Mvvm.BindableBase

public class SomeViewModel : BindableBaseExtended
{
    private Person model;
    public Person Model
    {
        get { return model; }
        set { SetProperty(ref model, value); }
    }
    public string MyProperty
    {
        get { return Model.DisplayName; }
        set { SetProperty(Model, m => m.DisplayName, value); }
    }
}

public class BindableBaseExtended : BindableBase
{
    protected virtual bool SetProperty<TClass, TMember>(TClass target, Expression<Func<TClass, TMember>> expression, TMember value, [CallerMemberName] string propertyName = null)
    {
        var expr = (MemberExpression)expression.Body;
        var prop = (PropertyInfo)expr.Member;
        var propValue = prop.GetValue(target, null);
        if (object.Equals(propValue, value)) return false;

        prop.SetValue(target, value, null);
        this.RaisePropertyChanged(propertyName);
        return true;
    }
    protected virtual bool SetProperty<TClass, TMember>(TClass target, Expression<Func<TClass, TMember>> expression, TMember value, Action onChanged, [CallerMemberName] string propertyName = null)
    {
        var expr = (MemberExpression)expression.Body;
        var prop = (PropertyInfo)expr.Member;
        var propValue = prop.GetValue(target, null);
        if (object.Equals(propValue, value)) return false;

        prop.SetValue(target, value, null);
        onChanged?.Invoke();
        this.RaisePropertyChanged(propertyName);
        return true;
    }
}
公共类SomeViewModel:BindableBaseExtended
{
私人模式;
公众人物模型
{
获取{返回模型;}
set{SetProperty(ref model,value);}
}
公共字符串MyProperty
{
获取{return Model.DisplayName;}
set{SetProperty(Model,m=>m.DisplayName,value);}
}
}
公共类BindableBaseExtended:BindableBase
{
受保护的虚拟bool SetProperty(TClass目标,表达式,TMember值,[CallerMemberName]字符串propertyName=null)
{
var expr=(MemberExpression)expression.Body;
var prop=(PropertyInfo)expr.Member;
var propValue=prop.GetValue(目标,空);
if(object.Equals(propValue,value))返回false;
prop.SetValue(目标、值、空);
this.RaisePropertyChanged(propertyName);
返回true;
}
受保护的虚拟bool SetProperty(TClass目标、表达式、TMember值、操作onChanged、[CallerMemberName]字符串propertyName=null)
{
var expr=(MemberExpression)expression.Body;
var prop=(PropertyInfo)expr.Member;
var propValue=prop.GetValue(目标,空);
if(object.Equals(propValue,value))返回false;
prop.SetValue(目标、值、空);
onChanged?.Invoke();
this.RaisePropertyChanged(propertyName);
返回true;
}
}

那么我还应该手动检查值是否不同?公共字符串DisplayName{get{return Model.DisplayName;}set{if(Model.DisplayName!=value){Model.DisplayName=value;OnPropertyChanged();}}}}通常情况下,propertychanged事件只有在值真正更改时才会触发,因此,是的,您应该检查。但说到数据绑定,没有什么不同,只是2019年1月后遇到这个问题的人需要注意一点——OnPropertyChanged不受欢迎。改用RaisePropertyChanged。除此之外,这是完全准确的。那么我还应该手动检查值是否不同?公共字符串DisplayName{get{return Model.DisplayName;}set{if(Model.DisplayName!=value){Model.DisplayName=value;OnPropertyChanged();}}}}通常情况下,propertychanged事件只有在值真正更改时才会触发,因此,是的,您应该检查。但说到数据绑定,没有什么不同,只是2019年1月后遇到这个问题的人需要注意一点——OnPropertyChanged不受欢迎。改用RaisePropertyChanged。除此之外,这是完全准确的。当然,我可以扩展BindableBase并创建自己的BindableBase类,但有没有不使用反射的方法?如果不想使用反射,则需要在每个ViewModel属性上实现BindableBase.SetProperty的逻辑,以便能够包装模型的属性。但如果你更喜欢可读性,那么这是一种方法。当然我可以扩展BindableBase并创建我自己的BindableBase类,但是有没有不使用反射的方法呢?如果不想使用反射,那么需要在每个ViewModel属性上实现BindableBase.SetProperty的逻辑,以便能够包装模型的属性。但如果你更喜欢可读性,那么这是一种方法。