Friday, December 3, 2021

The trap of wanting to make it perfect, or #D.MVVM what takes so long?

Hello, my friends!

It's quite some time since my last blog post - I know - it was/is a busy year. 



I regularly get emails asking when my MVVM framework will be ready for shipping. This is a very good question... (It was ready nearly two years ago - my designated release date was 2019-12-06)

What? 

Yes, I'm sorry this is the sad truth because just one week before my estimated release date of the beta version I decides to cancel it.

Why?

As it is/was a source code distribution, after a close look at the code, it was messy and really unreadable. 

So I started a little bit of refactoring.

To demonstrate the power of the framework I also started writing some sample applications for VCL and FMX and also some mockups for unit tests.

Getting more and more into real-world design details, everything was working so far, I found some places that could be better, or in other words: The comfort of the framework was not easy enough to create some special bindings. 

Of course, from the early beginning, the main binding unit was able to bind everything (by "Hand", I mean in Code).

At this point, I could just follow the bad rule: "It compiles, It works, just ship it". 

But I expected more, so I deleted all binding rules and the main binding unit. There has to be a better way. (At this point I also decided, not to stick as close as before to the MS-C# MVVM examples)

Just imagine: You have a ComboBox for "Mr., Mrs, Sir, Dear" this might be a close list (Style: csDropDownList) or just (csDropDown) where you are able to put in a free text.

If you didn't watch any of my MVVM-Youtube Videos. My Framework could bind to "normal" properties at the ViewModel, but I also created my own TProperty<T> fields which are much better than just properties. E.g. all the PropertyChanged or INotifyPropertyChanged events are builtin.

So if you want to set the Item list from the ViewModel (like reading the Items from a database), you probably want to bind to the Itemindex and to the Text-Property and perhaps (on FMX) to the Textpromp property. The UI often has to enable the controls or even set the visibility and last but not least perhaps you want to set the hint text. (In most cases you want to handle the OnChange event or the OnClick)

In the MVVM-Pattern you normally do not set a Visual Control Visibility in the ViewModel, or even the color. This is part of the View on some conditions. Like: ViewModel.CanSave or ViewModel.CriticalState (to show a warning label in red)!

After talking to many Delphi Developer I decides to enable the visual settings also to the TProperty<T>. So if you have

Name : TEdit;

on the View (Form) and a property field like:

fName : TProperty<String>;

you can write

fName.Enabled := false;
fName.Text    := 'Frank';
fName.Hint    := 'could not be changed';

in the ViewModel.

If you think that is not like MVVM should be... Sorry, I don't care!

So it is even possible to Name it EdName:TEdit on the View and set your own naming converter to bind all TEdits with Ed[Name]:TEdit as a prefix to f[Name]:TProperty<String>.

So back to our TComboBox problem:

With

Salutation : TCombobox;

the ViewModel could look like this (Property Version):

{ I skipped the getter/setter here to make the code more simple }

TPersonViewModel = Class(TViewModel)
  private
   // ...
  public
    Property Salutation : String;
    Property SalutationItems : TStrings;
    Property SalutationIndex : Integer;
    Property CanShowSaluation : boolean;
    Property CanEditSalutation : boolean;
end;

Or mixed with command Methods like:

TPersonViewModel = Class(TViewModel)
  public
    procedure SalutationClicked;

    function  CanEditSalutation : boolean;
    function  CanShowSalutation : boolean;
 
    Property Salutation : String;
    Property SalutationItems : TStrings;
    Property SalutationIndex : Integer;
end;

Or with my TProperty<T> fields:

TPersonViewModel = Class(TViewModel)
  private
    fSalutation      : TVisualProperty<String>;
    [ OnValueChanged('SelectionChanged') ] 
    fSalutationIndex : TProperty<Integer>;
    fSalutationItems : TListProperty<String>; 
  protected
    procedure SelectionChanged;
  public
    procedure SalutationClicked;
end;

My goal was/is: To support all these different methods and also bind everything without even one single line of code. Don't get me wrong - also nothing set in the Object Inspector. No double click on an event! Just a barebone Form clicked together nothing more.

That's why I had to reinvent the binding rules syntax!

So one ComboBox must auto bind by name (perhaps with a rename rule) to three different fields! Only one should have the visual parts (that should raise an error if more than one is bound). On value change should automatically call the SelectionChanged procedure, the Index property field should be an Integer nothing else, and the OnChange, OnChangeTracking (FMX), and the OnClick event should be connected to the corresponding fields, properties, or procedures. You should be able to mix my Property-Field with normal Properties. 

On top:

There is one visual component with one OnChange event... Where to bind?

of course to fSalutation:TVisualProperty<String>

and not to the two others. So the syntax for the binding should be able to define where to bind the events...

For the Combobox, the style like 
csDropDownList limits the possibility to bind the control to the string property and in this case the OnChange event should bind to the 

fSalutationIndex:TProperty<Integer>
 

field. (Or just to a SalutationChanged method...)

Not an easy task you can imagine!

I have done some work over the last two years, but the main part of the binding stuff I didn't touch. Or even worse, I no longer understood my own source code. 

I tried my best, but without renaming methods and variables it was impossible to read. I often looked for a distraction so that I would not have to deal with the actual problem. It certainly took me 10 attempts to finally start developing the binding routines again. 

So...

There is good news and bad news!

I think I see light at the end of the tunnel, but I need a few more months to get an alpha version on the road. (Ahh and btw. I developed an IDE-Wizard to create a new #DMVVM application for VCL and FMX also not 100% finished and not tested with D11, yet).

I'm still in my own trap to develop the best MVVM-Framework money can buy...

How to bind Stringgrids or event TreeViews are totally beyond the scope of this blog post...

So please stay tuned...