Используя F# и Caliburn.Micro вместе
Как я понимаю, Caliburn.Micro выполняет значительную часть работ по автоматическому подключению и монтажу для проекта WPF на основе соглашений; используя MVVM.
Вопрос: Есть ли какие-либо специфичные для C# детали в Caliburn.Micro; которые использовали некоторые C# -только функции? Какие части Caliburn.Micro нельзя использовать с кодом F#? Что я теряю при использовании F#?
2 ответа
К сожалению, Caliburn.Micro и F# не очень хорошо работают вместе.
Например, Caliburn.Micro обрабатывает представления как обычные классы во время сопоставления соглашений (посредством отражения), что справедливо для C# - представления являются частичными классами.
F# не поддерживает частичные классы, а представления - только файлы XAML. Это означает, что они не могут быть решены Caliburn.Micro. Это также означает, что у вас будут проблемы с подключением контейнера IoC в загрузчике, потому что он не сможет создавать представления - по крайней мере, без ручной регистрации в Application.LoadComponent
и тому подобное.
Настройка бустреппера также была проблемой, потому что вы должны указать ключ в App.xaml
, но по какой-то причине этот ключ не соответствовал классу. Bootstrapper<T>
также проходит bool useApplication = true
в BootstrapperBase
по умолчанию - и у F# были разные проблемы в зависимости от того, был установлен этот флаг или нет, к сожалению, я не помню деталей. Это потому, что в F# вы сами подключаете точку входа к приложению, а Caliburn.Micro создан для автоматического перехвата этого шага. Это вызывает конфликты...
Если вы заставите его работать, полностью переопределив механизм разрешения соглашений и согнув любой контейнер IoC по своему желанию, вы получите больше возможностей. На мой взгляд, в настоящее время слишком много трения.
Лично я бы установил базовую основу для приложения на C# с использованием Caliburn.Micro и выполнил "реальную работу" на F#. В качестве альтернативы, я думаю, что вы можете даже иметь модели представлений, написанные на F# в отдельном проекте, представления в C# проекте, тогда вам просто нужно будет отрегулировать, как поиск соглашения работает в загрузчике. Я не совсем уверен в этом подходе, поэтому ваш пробег может меняться и действовать с осторожностью.
Это хороший вопрос. Если вы справитесь с этим, обязательно сообщите нам, как это происходит. Я искал Caliburn для стороннего проекта, но я не добился большого прогресса в этом.
Итак, чтобы начать, то, что вы, возможно, уже наткнулись на:
Перегрузка лямбда-выражения в NotifyOfPropertyChange
Основной метод для вызова событий PropertyChanged имеет два переопределения. Один, который принимает имя свойства в виде строки, а другой - лямбда-выражение. Последний использует хитрый трюк / уродливый хак для извлечения имени свойства из тела выражения. Это дает вам хороший, лаконичный синтаксис в C#, который до некоторой степени проверяется компилятором:
public string SomeProp
{
get { return someField; }
set
{
someField = value;
NotifyOfPropertyChange(() => SomeProp);
}
}
Но это не очень хорошо подходит для F#. Вы можете сделать выбор либо к строковому, либо добавить его в кавычки. Я использовал что-то вроде этого:
let notify<'a> (notifier: PropertyChangedBase) (expr: Expr<'a>) =
let name =
match expr with
| PropertyGet (_, pi, _) -> pi.Name
| _ -> failwith "Can't get property name to notify"
notifier.NotifyOfPropertyChange(name)
Который назывался так:
member this.SomeProp
with get () =
someField
and set(value) =
someField <- value
notify this <@ this.SomeProp @>
Я полагаю, что вы можете сделать еще один шаг вперед и превратить его в свой собственный класс PropertyChanged, построенный поверх PropertyChangedBase.