Внедрение свойств в классы .NET после компиляции - PullRequest
1 голос
/ 24 марта 2009

Я хотел бы реализовать часть ViewModel шаблона MVFM WPF без ссылки на сборки WPF. Проблемной частью является маршрутизация команд, которая требует, чтобы ViewModels реализовал свойства типа ICommand, чтобы могли работать привязки команд.

Теперь я могу избежать ICommand и просто объявить свойства как object. Все еще работает, вот и все. Но меня беспокоит то, что Я все еще должен объявить их , и я действительно не хочу, потому что они чувствуют себя как код котельной плиты .

Мои ViewModels сейчас выглядят так:

public class HelloWorldViewModel : ViewModel
{
    [BoundProperty]
    public string Name { get; set; }

    [CommandHandler("SayHello")]
    public bool CanSayHello()
    {
        return Name != "" && Name != null;
    }

    [CommandHandler("SayHello")]
    public void SayHello()
    {
        View.ShowMessage("Hello, {0}!", Name);
    }

    public object SayHello { get; private set; }
}

CommandHandlerAttribute включает обнаружение во время выполнения обработчиков команд (Action и необязательный Func<bool>), в то время как BoundPropertyAttribute действительно аспект , который внедряется в установщик свойств и вызывает INotifyPropertyChanged. Я выполняю это, используя время компиляции IL weaver .

В идеале я бы хотел, чтобы последняя строка (свойство SayHello) тоже была неявной. Не было бы никакого смысла иметь его там в источнике, если бы это не было требованием WPF.

Итак, естественно, я думаю об использовании аспекта CommandHandlerAttribute для внедрения необходимого IL в класс и, по существу, создания свойства после компиляции . Это довольно сложно, хотя хороший ткач IL (например, PostSharp ) может значительно облегчить процесс.

Прежде чем я отправлюсь в это путешествие, я хотел бы услышать, что вы все думаете о моем подходе. Это звук? Есть ли способ лучше? Как бы ты это сделал?

Ответы [ 5 ]

3 голосов
/ 24 марта 2009

Для меня это звучит слишком умно, безусловно. Там слишком много "волшебства" происходит. В частности, мне не нравятся магические строки и другие аспекты вашего атрибута CommandHandler. Тем не менее, если бы я пошел по этому пути, я бы использовал что-то похожее на EventAggregator, но для команд. Итак, SayHello вообще не будет существовать в вашей ViewModel. Что бы магия ни создавала привязки команд к SayHell (), а CanSayHello () вместо этого находят команду в глобальном CommandAggregator. Пока мы используем магические строки для этого, команды в CommandAggregator могли бы лениво создаваться, таким образом, не требуя кодирования «котла» с вашей стороны. Осталось только создать магию XAML (расширение разметки) для указания команды на ICommandSource.

<Button Command="{my:AggregateCommand SayHello}"/>
2 голосов
/ 05 ноября 2013

Советую посмотреть, как это было реализовано, и это поможет:

"Вид магии" Без усилий INotifyPropertyChanged

[http://visualstudiogallery.msdn.microsoft.com/d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a][1]

в качестве примера добавления его к одному свойству:

[Magic] 
public string Name { get { return _name; } set { _name = value; } } 
string _name;

Еще один пример добавления его ко всем свойствам класса:

[Magic] 
public class MyViewModel: INotifyPropertyChanged 
{ 
  public string Name { get; set; } 
  public string LastName { get; set; } 
  ..... 
}
1 голос
/ 24 марта 2009

Через некоторое время после игры с Призмой, но прежде чем показаться MVVM, я придумал стратегию, которая, как мне кажется, все еще имеет смысл:

Я создал реализацию интерфейса ICommand на основе рефлексии. Конструктор принял целевой объект и имя операции. Используя рефлексию, код искал метод с именем «[операция]», свойство или метод с именем «Может [операция]» или «[операция] включен» и событие с именем «Может [операция] изменена» или «[ операция] Включено Изменено ". Требовалось только первое, но отраженный метод / свойство / событие было связано с довольно простой реализацией интерфейса ICommand.

Затем я создал реализацию IValueConverter, которая создаст экземпляр предыдущего класса, передав значение, которое будет преобразовано, в качестве целевого объекта, а параметр преобразователя - имя операции.

Учитывая вышеупомянутые компоненты, я смог, например, привязать свойство Command кнопки непосредственно к источнику операции (вместе с указанием конвертера) и установить для свойства CommandParameter кнопки имя операции. Таким образом, я получил декларативное связывание команд без плотского знания чего-либо из WPF.

0 голосов
/ 30 марта 2009

На мой взгляд, лучшим способом в вашем случае является шаблон Proxy или Decorator. Вы можете использовать низкоуровневые объекты, которые обертываются / украшаются элементами UI / WPF во время выполнения. Это самый простой, но эффективный способ сэкономить ваше время и не беспокоиться о каркасах, инъекциях и т. Д.

Единственное, вам нужно спроектировать небольшую инфраструктуру, чтобы обернуть ваши сущности соответствующими декораторами.

0 голосов
/ 24 марта 2009

Мое личное мнение, что это интересно, но я бы вообще этого избегал.

Избегание кода котельной пластины (или кода, который выглядит как код котельной пластины) имеет последствия. Это может показаться хорошей идеей, поскольку вы не постоянно перепечатываете вещи, но в конечном итоге вы делаете их менее читабельными и понятными.

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

...