Sto lavorando a un'applicazione WPF, cercando di rimanere severa nel separare View, ViewModel e Model.
La mia applicazione ha alcune viste diverse in una gerarchia relativamente piatta. C'è una vista per la modifica di qualcosa che chiamiamo una sostanza e una per le classificazioni, in cui ogni sostanza ha un certo numero di classificazioni.
La mia domanda riguarda le classi ViewModel per le sostanze e le classificazioni, ognuna delle quali è di circa 1000 righe! Il fatto è che il codice è per lo più costituito da proprietà get / set, con qualche logica intrinseca che funziona contro il mio modello, così come alcuni comandi e funzioni private. Quindi potrei facilmente dividere la classe in un gruppo di classi più piccole (come una per GroupBox nella mia vista o in qualsiasi altra cosa) con una classe che possiede istanze dell'altro, per ottenere classi più piccole.
Ma questo non mi sembra significativo, sembra come risolvere un sintomo, come farlo per se stesso. Le dimensioni della classe dipendono chiaramente dal numero di campi relativi alle sostanze e alle classificazioni e non posso fare nulla al riguardo.
Pensi che sia nei guai qui? È normale che le applicazioni WPF siano così dominate, in termini di dimensioni, dal ViewModels? Quanto dovrei essere serio nel limitare le dimensioni delle classi? Potrei ridurlo in modo significativo cambiando il modo in cui scrivo le parentesi graffe, ma penso che ora sia più chiaro che con le parentesi egiziane.
La mia domanda non è in realtà se il mio codice è fangoso o meno (in parte è così), ma piuttosto se si può effettivamente dire che una classe ViewModel è fangosa solo perché è grande. Per dare qualche prospettiva, la mia vista di sostanza ha 7 liste / datagrids / simili, 13 pulsanti, 9 caselle combinate, 5 caselle di controllo, 9 caselle di testo e 3 pulsanti di opzione. Tutto sommato, si tratta di circa 26 righe per controllo. Ci sono alcuni casi in cui c'è interazione tra i diversi controlli, l'impostazione di un valore in un controllo disabiliterà e annullerà un altro ecc.
Alcuni esempi di codice:
public RelayCommand AddSubstanceNumberCommand
{
get
{
return new RelayCommand(
(x) =>
{
var number = new SubstanceNumber();
number.SubstanceID = Id;
number.ModifiedBy = Main.op.LoginName;
number.ModifiedDate = DateTime.Now;
number.CreatedDate = DateTime.Now;
number.Type = Converters.NumberTypeToStringConverter.translation.First(t => t.Value == SelectedNewSubstanceNumberType).Key;
number.NumberText = Validator.Normalize(NewSubstanceNumber, SelectedNewSubstanceNumberType);
var temp = NewSubstanceNumber.Replace("-", "");
number.NumberValue = Int32.Parse(temp.Substring(0, temp.Length - 1));
if (NewSubstanceNumber != null && !SubstanceNumbers.Any(sn => sn.NumberText.Replace(" ", "") == number.NumberText && sn.Type == number.Type))
SubstanceNumbers.Add(number);
NewSubstanceNumber = "";
}, param => this.CanAddSubstanceNumber);
}
}
public ObservableCollection<SubstanceGroup> SubstanceGroups
{
get
{
return Substance.SubstanceGroups;
}
set
{
Substance.SubstanceGroups = value;
OnPropertyChanged("SubstanceGroups");
}
}
public RelayCommand OpenAllClassificationsCommand
{
get
{
return new RelayCommand(
(x) =>
{
// Opening tabs for all classifications that don't already have a tab open
var currentSubstanceTab = Main.SelectedTab;
var classificationTabsNow = currentSubstanceTab.Tabs.Where(t => t.GetType() == typeof(ClassificationViewModel));
var toOpen = Classifications.Where(c => !classificationTabsNow.Any(ctn => ctn.Id == c.SubstanceClassificationID));
toOpen.ToList().ForEach(o => Main.SelectedTab.Tabs.Add(new ClassificationViewModel(Main, o.SubstanceID, o.SubstanceClassificationID, false, new Services.MessageBoxNotifyUserService())));
});
}
}
Ed ecco uno che è particolarmente fangoso e ripetuto:
public OccupationalExposureLimitUnit OccupationalExposureLimitUnit5
{
get
{
if (SubstHasOccExpLimits)
return Substance.OccupationalExposureLimitUnit5;
else if (GroupForLimits != null)
return GroupForLimits.OccupationalExposureLimitUnit5;
return null;
}
set
{
bool hadValue = SubstHasOccExpLimits;
if (value.Name_SV == "")
OccupationalExposureLimitShortTerm2 = null;
Substance.OccupationalExposureLimitUnit5 = value;
if (!hadValue && SubstHasOccExpLimits)
TransferLimitValuesFromGroupToSubstance();
OnPropertyChanged("OccupationalExposureLimitUnit5");
}
}
Questa proprietà include alcune funzionalità di fallback per quando la sostanza non ha un determinato insieme di valori, e alcune modifiche di stato per andare allo stato della sostanza-valore quando l'utente inizia a modificare uno dei valori. Certamente c'è spazio per miglioramenti, ma anche senza di esso, la classe sarebbe un numero di volte superiore alle 200 righe che alcuni consigliano per le dimensioni della classe.