Могу ли я сделать это без размышлений? - PullRequest
3 голосов
/ 24 сентября 2011

Для презентации, включающей шесть компонентов PersonName объекта Person, я добавил расширение и «мини-модель представления» (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» и значение метки, и позволить модели мини-вида установить соответствующий метод получения / установки делегаты, что-то вроде:

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

1 Ответ

1 голос
/ 27 сентября 2011

Попробуйте реализовать класс связывателя для управления связыванием. В этом случае я использовал 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 должен возвращать тип указателя, а не тип значения, иначе LastName не может быть обновлено при вызове Setter. Например:

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

В этом примере PersonName реализован, как показано ниже, однако ваша реализация может отличаться.

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

    public Name FirstName { get; set; }
}

Без всей информации о вашем классе и строгих типов, связанных с некоторыми из используемых вами переменных, это было трудно проверить, но я думаю, что это должно избавить вас от неприятностей.

Надеюсь, это поможет.

...