RadicalFx / Radical.Windows

Radical is an infrastructure framework whose primary role is to help in the development of composite WPF applications based on the Model View ViewModel pattern.
http://www.radicalframework.com/
MIT License
3 stars 2 forks source link

NetCore 3.1 AbstractMementoViewModel Property error #324

Closed Aurelio67 closed 3 years ago

Aurelio67 commented 3 years ago

Buongiorno Mauro, ho ripreso i test con il NetCore 3.1 e con AbstractMementoViewModel mi da questo errore: (con AbstractViewModel funziona correttamente senza errori):

1) Definisco una property:

public ObservableCollection<LayoutModel> ListaLayout
{
    get => GetPropertyValue(() => ListaLayout);
    set => SetPropertyValue(() => ListaLayout, value);
}

2) Vado a popolarla con una query usando entity che mi riporta una List (La query è uguale per entrambi gli Abstract) facendo in questo modo:

   public void CaricaLayoutView(string layoutName)
    {
        try
        {
            ListaLayout = new ObservableCollection<LayoutModel>(Generali.CaricaLayoutView(_sharedService.Option, _sharedService.UteId, EnumLayoutView.RuoliView.ToString()));
            ItemLayout = !string.IsNullOrEmpty(layoutName) ? ListaLayout.FirstOrDefault(r => r.LayoutName == layoutName) : ListaLayout.FirstOrDefault(r => r.LayoutPrincipale);
        }
        catch (Exception ex)
        {
            MessageUtility.MessageOk(this, nameof(CaricaLayoutView), ex.GetFullMessage(), _conventionsHandler);
        }

    }

Se eredito da AbstractViewModel tutto funziona correttamente, mentre se eredito da AbstractMementoViewModel mi genera questa eccezione quanto ritorna dalla query che va ad attribuire la List alla Observable;

at Radical.Linq.ExpressionExtensions.FindMemberExpression(Expression exp) at Radical.Linq.ExpressionExtensions.FindMemberExpression(Expression exp) at Radical.Linq.ExpressionExtensions.FindMemberExpression(Expression exp) at Radical.Linq.ExpressionExtensions.GetMemberName[T,TProperty](Expression1 source) at Radical.Validation.Validator1.<>c__DisplayClass2_0.b__0(ValidationRule1 rule) at System.Linq.Enumerable.WhereListIterator1.MoveNext() at Radical.Linq.EnumerableExtensions.ForEach[T](IEnumerable1 list, Action1 action) at Radical.Validation.Validator1.OnValidate(ValidationContext1 context) at Radical.Validation.Validator1.ValidateProperty(T entity, String propertyName) at Radical.Windows.Validation.DataAnnotationValidationService1.OnValidateProperty(String propertyName) at Radical.Windows.Validation.AbstractValidationService.ValidateProperty(String propertyName) at Radical.Windows.Presentation.AbstractMementoViewModel.ValidateProperty(String propertyName, ValidationBehavior behavior) at Radical.Windows.Presentation.AbstractMementoViewModel.ValidateProperty(String propertyName) at Radical.Windows.Presentation.AbstractMementoViewModel.OnPropertyChanged(PropertyChangedEventArgs e) at Radical.Model.Entity.OnPropertyChanged(String propertyName) at Radical.Model.Entity.SetPropertyValueCore[T](String propertyName, T data, PropertyValueChanged1 pvc) at Radical.Model.Entity.SetPropertyValue[T](String propertyName, T data, PropertyValueChanged1 pvc) at Radical.Model.MementoEntity.SetPropertyValue[T](String propertyName, T data, PropertyValueChanged1 pvc) at Radical.Model.Entity.SetPropertyValue[T](Expression1 property, T data) at ARevolution.Presentation.Accessi.RuoliEditViewModel.set_ListaLayout(ObservableCollection`1 value) in C:\ProgettiNetCore\ARevolution\ARevolution\Presentation\Accessi\RuoliEditViewModel.cs:line 95 at ARevolution.Presentation.Accessi.RuoliEditViewModel.CaricaLayoutView(String layoutName) in C:\ProgettiNetCore\ARevolution\ARevolution\Presentation\Accessi\RuoliEditViewModel.cs:line 646

image

Grazie 1000 come al solito.

Aurelio

mauroservienti commented 3 years ago

Ciao @Aurelio67, dallo stack trace deduco ci sia abilitata la validazione. Ci fai vedere il pezzetto di codice che la abilita in cui definisci il ValidationService? Oppure la validazione non è abilitata? Ci diresti anche che versioni dei pacchetti nuget stai usando?

Grazie.

Aurelio67 commented 3 years ago

Buongiorno Mauro, ti allego il Constructor del ViewModel

`public RuoliEditViewModel(ISharedService sharedService, IConventionsHandler conventionHandler, IMessageBroker messageBroker) { _sharedService = sharedService; _conventionsHandler = conventionHandler; _messageBroker = messageBroker; _db = new ARevolutionMyContext(_sharedService.Option.Options); MyMessageQueue = new SnackbarMessageQueue();

        //Inizializzo le proprietà
        SetInitialPropertyValue(() => TagView, new TagModel { RecordModificato = false, Id = Guid.NewGuid(), ViewName = nameof(RuoliEditView), TipoView = ViewTypeEnum.ViewEdit, Title = "Ruolo", GroupParent = IntToEnum.GetEnumDescription(GroupParentEnum.Accessi) });
        SetInitialPropertyValue(() => IsEditLayout, false);
        SetInitialPropertyValue(() => BtnSave, false);
        SetInitialPropertyValue(() => Zoom, 100);

        //Gestione Layout
        GetPropertyMetadata(() => IsEditLayout)
            .AddCascadeChangeNotifications(() => CanDeleteLayout)
            .AddCascadeChangeNotifications(() => CanLayoutPrincipale)
            .AddCascadeChangeNotifications(() => CanDeleteLayoutPrincipale)
            .AddCascadeChangeNotifications(() => CanEditLayout)
            .AddCascadeChangeNotifications(() => CanNewLayout);

        GetPropertyMetadata(() => ItemLayout)
            .AddCascadeChangeNotifications(() => CanDeleteLayout)
            .AddCascadeChangeNotifications(() => CanLayoutPrincipale)
            .AddCascadeChangeNotifications(() => CanDeleteLayoutPrincipale)
            .AddCascadeChangeNotifications(() => CanEditLayout);

        //ad ogni cambiamentodel modello aggiorno le varie properties o i command
        _memento.TrackingServiceStateChanged += (s, e) =>
        {
            TagView.RecordModificato = _memento.IsChanged;
            BtnSave = Validate(ValidationBehavior.TriggerValidationErrorsOnFailure).IsValid;
        };

        //quando si accettano i cambiamenti (save), attribuisco i valori delle properties alla row che deve essere salvata
        _memento.AcceptingChanges += (s, e) =>
        {
            Record.RuoUteCod = RuoUteCod;
            Record.RuoUteDes = RuoUteDes;
            Record.RuoUteIsSospeso = RuoUteIsSospeso;

        };

        //faccio in modo che quando cambi il valore di una proprietà, notifichi anche un'altra proprietà
        GetPropertyMetadata(() => BtnSave)
            .AddCascadeChangeNotifications(() => CanSaveAndClose)
            .AddCascadeChangeNotifications(() => CanSaveAndNew)
            .AddCascadeChangeNotifications(() => CanSave);

        ValidationService = new DataAnnotationValidationService<RuoliEditViewModel>(this)
            .AddRule
            (model => !string.IsNullOrEmpty(RuoUteCod),
                rule: ctx => ctx.Failed("*Campo obbligatorio")
            )
            .AddRule(model => !string.IsNullOrEmpty(RuoUteDes),
                ctx=> ctx.Failed("*Campo obbligatorio"));

    }`

Ho preso gli ultimi packages da nuget: Radical 2.1 Radical Windows 2.1

E' la prima volta che utilizzo questo modo di validazione sicuramente non lo so' utilizzare bene, ho sempre utilizzato il framework e li non era cosi.

Thanks

Aurelio

mauroservienti commented 3 years ago

Così su due piedi mi sembra che il problema possa essere nelle custom rule che hai definito nel DataAnnotationValidationService.

Una custom rule dovrebbe essere nella forma: "proprietà da validare", "regola". Quindi nel tuo scenario una cosa del tipo (scrivo direttamente qui quindi verifica prima):

ValidationService = new DataAnnotationValidationService<RuoliEditViewModel>(this)
            .AddRule(
                 property: m => m.RuoUteCod,
                 rule: ctx => string.IsNullOrEmpty(RuoUteCod) ? ctx.Failed("*Campo obbligatorio") : ctx.Succeeded())
            .AddRule(
                 property: m => m.RuoUteDes,
                 rule: ctx=> string.IsNullOrEmpty(RuoUteDes) ? ctx.Failed("*Campo obbligatorio") : ctx.Succeeded());
mauroservienti commented 3 years ago

Aggiungo che usando il DataAnnotationValidationService puoi ottenere più facilmente lo stesso risultato decorando le proprietà con gli attributi offerti dal motore di data annotation del framework stesso, quindi una cosa del tipo:

[Required]
public string RuoUteDes
{
   get => GetPropertyValue(() => RuoUteDes);
   set => SetPropertyValue(() => RuoUteDes, value);
}

e non ti serve definire nessuna custom rule.

Aurelio67 commented 3 years ago

Scusami ma sicuramente ero abbastanza "rinco" per aver dimenticato il nome della property da validare: ValidationService = new DataAnnotationValidationService<RuoliEditViewModel>(this) .AddRule( property: m => m.RuoUteDes, rule: ctx => string.IsNullOrEmpty(RuoUteDes) ? ctx.Failed("*Campo obbligatorio") : ctx.Succeeded());

Ora funziona, ho provato anche la DataAnnotationValidationService Required, tutto ok..

Dopo questa dovrei essere riuscito a convertire tutta l'applicazione in Core, ti sapro' dire se tutto funziona ok.

Grazie 1000 come sempre..

Aurelio

mauroservienti commented 3 years ago

Grazie a te!