Aero Framework — передовая библиотека для промышленной и индивидуальной разработки кросс-платформенных XAML-ориентированных приложений с применением концепций MVVM-проектирования. Её основные достоинства — интуитивная ясность, предельная лаконичность, минималистичность и высокое быстродействие.
С версии 2.0 она стала платной для коммерческого использования, но остаётся свободной для учебных целей и проектов с открытым исходным кодом. Стоимость лицензии составляет 30$ на одного разработчика.
Вложив небольшую сумму денег и день-два в углубленное изучение её особенностей, вы сохраните недели и месяцы труда на реальных проектах. Более того, даже если вы опытный разработчик, значительно повысите свой технический уровень, архитектурные навыки и системность мышления. В данный момент всё зависит лишь от вашей усидчивости и трудолюбия. Гарантирую, что оно того стоит.
Первым делом нужно загрузить библиотеку с официального сайта или альтернативных источников:
сайт,
dropbox,
onedrive,
google.drive, — после чего распаковать архив и открыть тестовые проекты HelloAero, BankOnline, Sparrow, — они помогут быстрее войти в курс дела и послужат живыми примерами.
Следует отметить, что библиотека достаточно легко внедряется в уже существующие решения, поэтому буквально сразу может быть использована в деле. Итак, рассмотрим что же в ней примечательного на первый взгляд.
1) Эвокаторы Свойств и Команд (Property and Command Evocators)
Чтобы подписаться на событие уведомления об изменении значения свойства вместо классической конструкции
PropertyChanged += (o, args) =>
{
if (args.PropertyName == "Text") { ... };
}
this[() => Text].PropertyChanged += (o, args) => { ... };
this[MediaCommands.Play].CanExecute += (o, args) => args.CanExecute = /* conditions */;
this[MediaCommands.Play].Executed += (o, args) => { ... };
this[Context.Make].CanExecute += (o, args) => args.CanExecute = /* conditions */;
this[Context.Make].Executed += (o, args) => { ... };
[DataContract]
public class GuyViewModel : ContextObject, IExposable
{
[DataMember]
public int Kisses
{
get { return Get(() => Kisses); }
set { Set(() => Kisses, value); }
}
public void Expose()
{
var girlViewModel = Store.Get<GirlViewModel>();
this[() => Kisses].PropertyChanged += (sender, args) =>
{
Context.Get("KissGirl").RaiseCanExecuteChanged();
Context.Get("KissGuy").RaiseCanExecuteChanged();
};
this[Context.Get("KissGirl")].CanExecute += (sender, args) =>
args.CanExecute = Kisses > girlViewModel.Kisses - 2;
this[Context.Get("KissGirl")].Executed += (sender, args) =>
girlViewModel.Kisses++;
}
}
[DataContract]
public class GirlViewModel : ContextObject, IExposable
{
[DataMember]
public int Kisses
{
get { return Get(() => Kisses); }
set { Set(() => Kisses, value); }
}
public void Expose()
{
var guyViewModel = Store.Get<GuyViewModel>();
this[() => Kisses].PropertyChanged += (sender, args) =>
{
Context.Get("KissGirl").RaiseCanExecuteChanged();
Context.Get("KissGuy").RaiseCanExecuteChanged();
};
this[Context.Get("KissGuy")].CanExecute += (sender, args) =>
args.CanExecute = Kisses > guyViewModel.Kisses - 3;
this[Context.Get("KissGuy")].Executed += (sender, args) =>
guyViewModel.Kisses++;
}
}
WindowStyle="{Smart 'WindowStyle, SingleBorderWindow'}"
ResizeMode="{Smart 'ResizeMode, CanResizeWithGrip'}"
Height="{Smart 'Height, 600'}"
Width="{Smart 'Width, 800'}"
public class ConverterEventArgs : EventArgs
{
public object ConvertedValue { get; set; }
public object Value { get; private set; }
public Type TargetType { get; private set; }
public object Parameter { get; private set; }
public CultureInfo Culture { get; private set; }
public ConverterEventArgs(object value, Type targetType, object parameter, CultureInfo culture)
{
TargetType = targetType;
Parameter = parameter;
Culture = culture;
Value = value;
}
}
public interface IInlineConverter : IValueConverter
{
event EventHandler<ConverterEventArgs> Converting;
event EventHandler<ConverterEventArgs> ConvertingBack;
}
public interface ICompositeConverter : IValueConverter
{
IValueConverter PostConverter { get; set; }
object PostConverterParameter { get; set; }
}
<Grid Rack.Rows="* 20\Auto * 2* */100 * *" Rack.Columns="* 50\*/100 *">
<!--...-->
</Grid>
equals
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition MinHeight="20" Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*" MaxHeight="100"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition MinWidth="100" Width="*" MaxWidth="300"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--...-->
</Grid>
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
К сожалению, не доступен сервер mySQL