C# 我可以不经思考就这样做吗?

C# 我可以不经思考就这样做吗?,c#,reflection,mvvm,expression-trees,C#,Reflection,Mvvm,Expression Trees,对于涉及Person对象PersonName的六个组件的演示,我添加了一个扩展和一个“迷你视图模型”(PersonNamePropertyTextBox),以减少重复代码并促进数据绑定 因此,在父视图模型的构造函数中,我创建了以下小型视图模型: public PimDetailVm(Person person, ..) { LastName = new PersonNamePropertyTextBox( () => Model.Ge

对于涉及Person对象PersonName的六个组件的演示,我添加了一个扩展和一个“迷你视图模型”(PersonNamePropertyTextBox),以减少重复代码并促进数据绑定

因此,在父视图模型的构造函数中,我创建了以下小型视图模型:

   public PimDetailVm(Person person, ..) 
    {
        LastName = new PersonNamePropertyTextBox(
            () => Model.GetPersonName().LastName, v => this.UpdatePersonNameProperty(pn => pn.LastName, v))
        {
            Label = PeopleResources.LastName_Label
        };

        FirstName = new PersonNamePropertyTextBox(
            () => Model.GetPersonName().FirstName, v => this.UpdatePersonNameProperty(pn => pn.FirstName, v))
        {
            Label = PeopleResources.FirstName_Label
        };

        ... etc.
    }

    public PersonNamePropertyTextBox LastName { get; private set; }
    public PersonNamePropertyTextBox FirstName { get; private set; }
我现在真正希望能够做的是传入当前属性,即“LastName”和标签值,并让迷你视图模型设置适当的Getter/Setter委托,类似于:

LastName = new PersonNamePropertyTextBox(vm=>LastName, PeopleResources.LastName_Label);
不过,我正在为如何做到这一点而挣扎。有什么想法吗

扩展(处理更新模型中的人名)
public static void UpdatePersonNameProperty(此PIMDailVM vm,表达式属性Expression,字符串值)
{
var pn=vm.Model.GetPersonName();
var pnProps=pn.GetType().GetProperties();
var subj=ExprHelper.GetPropertyName(propertyExpression);
var subsprop=pnProps.Single(pi=>pi.Name.Equals(subc));
var currentVal=subprop.GetValue(pn,null);
//如果没有要更新的内容,则进行拆分
if(currentVal==null&&value==null)返回;
如果(currentVal!=null&¤tVal.Equals(value))返回;
//更新属性
var capitalized=value==null?null:value.Capitalize();
subprop.SetValue(pn,大写,空);
//更新模型
vm.Model.SetName(pn);
//广播最新消息
vm.NotifyOfPropertyChange(subc,value);
}
PersonName某些属性的迷你视图模型
公共类PersonNamePropertyTextBox:TextBoxActionData
{
public PersonNamePropertyTextBox(Func getterFunc,Action settraction){
如果(getterFunc==null)抛出新的ArgumentNullException(“getterFunc”);
如果(setteration==null)抛出新的ArgumentNullException(“setteration”);
GetterFunc=GetterFunc;
settraction=settraction;
}
}

尝试实现一个binder类来管理绑定。在本例中,我使用了
PropertyBinding

public class PropertyBinding
{
    public static PropertyBinding To(ViewModel vm, Name name, string label)
    {
        return new PropertyBinding { ViewModel = vm, Getter = new Func<string>(delegate() { return name.Value; }), Setter = new Action<string>(delegate(string value) { name.Value = value; }), Label = label };
    }

    public string Label { get; set; }

    public ViewModel ViewModel { get; set; }

    public Func<string> Getter { get; set; }

    public Action<string> Setter { get; set; }

    public string Value
    {
        get { return this.Get(); }
        set { this.Set(value); }
    }

    internal string Get()
    {
        // Implement UpdatePersonNamePropert here.

        // Maybe convert culture before returning.
        return this.Getter();
    }

    internal void Set(string value)
    {
        // Maybe convert culture before storing.
        this.Setter(value);
    }
}
请注意,
Model.GetPersonName().LastName
必须返回指针类型而不是值类型,否则调用Setter时无法更新LastName。例如:

public sealed class Name
{
    public string Value { get; set; }
}
在本例中,PersonName的实现方式如下所示,但您的实现方式可能有所不同

public class PersonName
{
    public Name LastName { get; set; }

    public Name FirstName { get; set; }
}
如果没有所有的类信息和与您使用的一些变量相关联的强类型,那么很难验证,但我认为这应该可以让您摆脱麻烦


希望这能有所帮助。

为什么要避免反射?@CodeInChaos:有趣的问题,我试图避免反射,就像避免交通堵塞一样。我不喜欢在繁忙的交通中开车,但有时你不得不…@CodeInChaos,一切都是一样的——也就是说,如果你能同样好地解决一个有反射和没有反射的问题——不使用反射的解决方案更好,因为它更安全。我不确定你是否能在没有反射的情况下做到这一点,但是有一种方法可以使用代理使反射更快。看看这个链接,静态反射已经是相当类型安全的了。当然,如果没有反射的代码与有反射的代码具有相似的复杂性,那么我会避免它。但是反思的缺点,做对了是很小的。嗨,伯尼,这正是我在原则上要求的,但我不是在摸索。例如,Model.GetPersonName().LastName不会编译为请求的Name参数的参数。这个名字应该是一个新的包装器吗?PropertyBinding只是您创建的一个类,还是它与框架中的某些内容相关(动态?)。我错过了什么?啊,是的,我看到了问题。您是否能够发布GetPersonName()和PersonName类型。理想情况下,您可以通过一个接口在PersonName上实现Get/Set函数,我过去就是这样做的。PropertyBinding只是一个自定义类。请参阅我的更新,了解我如何在不知道PersonName模型完全实现的情况下实现它。
LastName = new PersonNamePropertyTextBox(PropertyBinding.To(Model, Model.GetPersonName().LastName, PeopleResources.LastName_Label));
public sealed class Name
{
    public string Value { get; set; }
}
public class PersonName
{
    public Name LastName { get; set; }

    public Name FirstName { get; set; }
}