【问题标题】:Can I do this without reflection?我可以不经过反思就做到这一点吗?
【发布时间】:2011-09-23 20:26:40
【问题描述】:

对于涉及 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);

我正在为如何做到这一点而苦苦挣扎。有什么想法吗?

扩展(处理更新模型中的 PersonName)

    public static void UpdatePersonNameProperty(this PimDetailVm vm, Expression<Func<PersonName, object>> propertyExpression, string value)
    {
        var pn = vm.Model.GetPersonName();
        var pnProps = pn.GetType().GetProperties();

        var subj = ExprHelper.GetPropertyName(propertyExpression);
        var subjProp = pnProps.Single(pi => pi.Name.Equals(subj));

        var currentVal = subjProp.GetValue(pn, null);

        // split if there is nothing to update
        if(currentVal==null && value==null) return;
        if (currentVal != null && currentVal.Equals(value)) return;

        // update the property
        var capitalized = value == null ? null : value.Capitalize();
        subjProp.SetValue(pn, capitalized, null);

        // update the model
        vm.Model.SetName(pn);

        // broadcast the update
        vm.NotifyOfPropertyChange(subj, value);
    }

PersonName 的某些属性的迷你视图模型

public class PersonNamePropertyTextBox : TextBoxActionData
{
    public PersonNamePropertyTextBox(Func<string> getterFunc, Action<string> setterAction) {
        if (getterFunc == null) throw new ArgumentNullException("getterFunc");
        if (setterAction == null) throw new ArgumentNullException("setterAction");

        GetterFunc = getterFunc;
        SetterAction = setterAction;
    }
}

【问题讨论】:

  • 为什么要避免反射?
  • @CodeInChaos:有趣的问题,我尽量避免像堵车一样的反射。我不喜欢在繁忙的交通中开车,但有时你只需要...
  • @CodeInChaos,所有事情都是平等的——也就是说,如果你可以在有和没有反射的情况下同样好地解决一个问题——不使用反射的解决方案更好,因为它更安全。
  • 我不确定你是否可以在没有反射的情况下做到这一点,但是有一种方法可以使用委托更快地进行反射。看看这个链接,msmvps.com/blogs/jon_skeet/archive/2008/08/09/…
  • 静态反射已经很安全了。当然,如果没有反射的代码与具有反射的代码具有相似的复杂性,那么我会避免它。但是反射的缺点,如果做得好,是非常小的。

标签: c# reflection mvvm expression-trees


【解决方案1】:

尝试实现一个绑定器类来管理绑定。在这种情况下,我使用了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);
    }
}

它会被称为:

LastName = new PersonNamePropertyTextBox(PropertyBinding.To(Model, Model.GetPersonName().LastName, PeopleResources.LastName_Label));

请注意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; }
}

如果没有您的所有类信息以及与您使用的某些变量相关联的强类型,则很难验证,但我认为这应该可以让您摆脱麻烦。

希望这会有所帮助。

【讨论】:

  • 嗨,Bernie,这正是我原则上要求的,但我并不理解。例如, Model.GetPersonName().LastName 不会编译为请求的 Name 参数的 arg。 Name 应该是一个未显示的新包装器吗? PropertyBinding 只是您编写的一个类,还是与框架中的某些内容有关(动态?)。我错过了什么?
  • 啊,是的,我看到了问题所在。您是否可以发布 GetPersonName() 和 PersonName 类型。理想情况下,您将通过一个接口在 PersonName 上实现 Get/Set 函数,这就是我过去的做法。 PropertyBinding 只是一个自定义类。
  • 查看我的更新,了解我是如何实现 PersonName 模型而不知道它是完整实现的。
猜你喜欢
  • 2015-04-11
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多