开发者

Can I do this without reflection?

开发者 https://www.devze.com 2023-04-08 14:04 出处:网络
For a pr开发者_JAVA百科esentation involving six components of a Person object\'s PersonName, I added an extension and a \'mini view model\' (PersonNamePropertyTextBox) to cut down on duplicated code a

For a pr开发者_JAVA百科esentation involving six components of a Person object's PersonName, I added an extension and a 'mini view model' (PersonNamePropertyTextBox) to cut down on duplicated code and facilitate data binding.

So in the constructor of the parent view model, I create these mini view models like:

   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; }

What I would really like now is to be able to do is just pass in the current property, ie "LastName" and the label value, and let the mini view model set the appropriate Getter/Setter delegates, something like:

LastName = new PersonNamePropertyTextBox(vm=>LastName, PeopleResources.LastName_Label);

I am struggling as to how to do this though. Any ideas?

Extension (handle updating the PersonName in the Model)

    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);
    }

Mini View Model for some property of a 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;
    }
}


Try implementing a binder class to manage the binding. In this case I have used 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);
    }
}

It would be called like:

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

Please note that Model.GetPersonName().LastName must return a pointer type not a value type otherwise the LastName can not be updated when the Setter is called. For example:

public sealed class Name
{
    public string Value { get; set; }
}

In this example PersonName is implemented as below however your implmentation may be different.

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

    public Name FirstName { get; set; }
}

Without all your class information and the strong types associated with some of the variables you used it was hard to validate but I think this should get you out of trouble.

Hope this helps.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号