📜 ⬆️ ⬇️

Aero Framework - WPF new breath. Rise above MVVM

Aero Framework is an advanced library for industrial and individual development of cross-platform XAML- oriented applications using the concepts of MVVM- design. Its main advantages are intuitive clarity, utmost brevity, minimalism and high speed.

Since version 2.0, it has become paid for commercial use, but remains free for educational purposes and open source projects. The license cost is $ 30 per developer.

By investing a small amount of money and a day or two in the in-depth study of its features, you save weeks and months of work on real projects. Moreover, even if you are an experienced developer, you will significantly increase your technical level, architectural skills and systematic thinking. At the moment, it all depends on your perseverance and hard work. I guarantee that it is worth it.
')
image

The first thing you need to download the library from the official website or alternative sources:
website ,
dropbox
onedrive
google.drive , - after which you unpack the archive and open the HelloAero , BankOnline , Sparrow test projects - they will help you get up to speed and serve as living examples.

It should be noted that the library is fairly easily incorporated into existing solutions, so it can literally immediately be used in business. So, consider what is remarkable at first glance.

1) Property and Command Evocators

To subscribe to a property value change notification event instead of a classic construction

PropertyChanged += (o, args) => { if (args.PropertyName == "Text") { ... }; } 

enough to use a more concise version based on lambda expressions

 this[() => Text].PropertyChanged += (o, args) => { ... }; 

Expression parsing is performed only once upon initialization, so this does not have a significant effect on performance, but makes the code much more linear and readable.

Handlers for routed and contextual commands are defined in a similar way.

 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) => { ... }; 

Contextual commands are a cross-platform and memory-safe implementation of commands, remotely resembling the logic of routed commands in WPF .

2) Equal Injections through Expansion (Equitable Injections via Exposable Way)

Classical dependency injection in the designer of view-models is not the best practice. Yes, there are many containers that implement this functionality and this approach is common everywhere, but it has a number of drawbacks and imposes big restrictions on the designed system. You can talk about this for a long time, so now we only denote the essence of the problem: injections into the constructor create hierarchical dependencies, that is, if there is a need to get from a low-level twist-model to a high-level one without doubtful decisions, it is impossible. However, there is a way to directly inject the view models without creating hierarchical dependencies, preserving their equality! This is a very important property for the serialization and deserialization of closed object graphs, which leaves it possible to fully save and restore the logical and visual states of the entire application when it is restarted.

Realizing this is very simple and natural. See sample code in the HelloAero project in the Exposable section.

Code example
  [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++; } } 



3) Smart State and Smart Properties (Smart State & Smart Properties)

The JavaScript language implements a very powerful concept of weakly typed properties, as well as the built-in features of simple serialization and deserialization of objects, which makes it indispensable for developing complex dynamic interfaces. In part, these concepts are reflected in the mechanisms of Smart State and Smart Properties .

Take a look at how easily and naturally the sizes and positions of windows are saved in examples of projects to the library, while the twist model is cross-platform and completely clean of interface logic.

Pay attention to the following constructions.

  WindowStyle="{Smart 'WindowStyle, SingleBorderWindow'}" ResizeMode="{Smart 'ResizeMode, CanResizeWithGrip'}" Height="{Smart 'Height, 600'}" Width="{Smart 'Width, 800'}" 


4) Inline & Composite Converters (Inline & Composite Converters)

Sometimes there is a need for access from the converter to the view or its data context. For these purposes, you can apply the pattern IInlineConverter

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

The essence of the method is that instead of creating a new class for the converter, we simply move the Convert and ConvertBack methods to the Code Behind of the view as handlers for the Converting and ConvertingBack events. This gives full access to the view where this instance of the converter is used. An example of use is easy to find in source codes.

The ICompositeConverter pattern allows you to connect converters into chains, which sometimes helps to avoid creating new converter classes. How to use it, you should look at the source code.

  public interface ICompositeConverter : IValueConverter { IValueConverter PostConverter { get; set; } object PostConverterParameter { get; set; } } 


5) Grid racks (Rack for Grid)

Here it is enough to look at the code so that everything becomes clear.

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


Perhaps, for this article is enough, it is an introductory overview. We have considered far from all of the library's capabilities, localization, data validation, binding extensions, other types of converters, syntactic sugar, and many other trifles have remained behind the scenes. If there is interest in the materials, there will be other articles , so do not remain indifferent, join the discussions, express your comments in the comments or by e-mail, share with others.

PS The link is a bit outdated, but still relevant materials.

Source: https://habr.com/ru/post/268151/


All Articles