I am working on a WPF application that follows an MVVM pattern. Inspite of moving the validation into services, I am ending up with a fat viewmodels that runs for several lines of code(in my case close to 1000 lines). I have added the interface for the viewmodel here. I got a few collections exposed as combo and based on the combo selection, I have to perform validation/invoke service/apply filtering to other combos
public interface ISampleViewModel {
ObservableCollection<InstrumentDto> Collection1 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection2 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection3 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection4 { get; set; }
ObservableCollection<TenderViewConfigDetailViewModel> Collection5 { get; set; }
TenderViewConfigDetailViewModel SelectedViewConfigDetail { get; set; }
int SelectedTenderViewIndex { get; set; }
int SelectedInstrumentsViewIndex { get; set; }
SortableCollection<TenderViewToInstrumentViewModel> CurrentInstruments { get; set; }
TenderViewToInstrumentViewModel SelectedInstrumentForTenderView { get; set; }
InstrumentDto SelectedInstrument { get; set; }
bool IsAllInstrumentsFocused { get; set; }
ICommand ApplyChangesCommand { get; }
ICommand AddTenderPanelViewCommand { get; }
ICommand DeleteTenderPanelViewCommand { get; }
ICommand ModifyTenderViewVisiblityCommand { get; }
ICommand AddInstrumentsToPanelViewCommand { get; }
ICommand DeleteInstrumentsFromPanelViewCommand { get; }
ICommand MoveUpTenderListViewCommand { get; }
ICommand MoveDownTenderListViewCommand { get; }
ICommand MoveUpInstrumentsCommand { get; }
ICommand MoveDownInstrumentsCommand { get; }
bool IsValidModel { get; }
void PublishTenderViewConfigChanges(TenderViewConfigDetailViewModel viewModel,EventActionType actionType);
}
The above set of functionality make my viewmodel bulkier. How can I avoid avoid it? I cant think of breaking the functionality into smaller controls as they are dependent? Am I missing something here?
If you have stored in the ViewModel
properties that can be isolated in separate classes, it is best to move them to a separate Model
. Large number of properties pretty loads ViewModel
, for each type of properties you should create your Model
. Although on this occasion there is some debate, I believe there is nothing wrong if in the ViewModel
will be links to several Models
. On this subject you can see this answers:
In MVVM, is every ViewModel coupled to just one Model?
Example of using separate models:
Model
public class MainMenuModel : NotificationObject // Here also implemented INotifyPropertyChanged interface
{
private bool _buttonIsEnabled = true;
public bool ButtonIsEnabled
{
get
{
return _buttonIsEnabled;
}
set
{
_buttonIsEnabled = value;
NotifyPropertyChanged("ButtonIsEnabled");
}
}
}
ViewModel
public class MainMenuViewModel
{
private MainMenuModel _mainMenuModel = null;
public MainMenuModel MainMenuModel
{
get
{
return _mainMenuModel;
}
set
{
_mainMenuModel = value;
}
}
...
public MainMenuViewModel()
{
MainMenuModel = new MainMenuModel();
}
}
View
<Button IsEnabled="{Binding Path=MainMenuModel.ButtonIsEnabled}" ... />
The only thing that can be left on the side of the ViewModel
, it Commands and IDataErrorInfo
interface implementation, although implementation of IDataErrorInfo
can also be moved to the side of the Model
.
Also, if the implementation of Command takes a lot of space, you can create separate function / procedure that can be called such Helper
and place in suitable class. Next, in Command did not write the whole implementation, it's necessary refer to this method.
For example:
private ICommand _findCommand = null;
public ICommand FindCommand
{
get
{
if (_findCommand == null)
{
_findCommand = new RelayCommand(param => this.Find(), null);
}
return _findCommand;
}
}
private void Find()
{
// Here instead of writing large code,
// moving find logic to separate static class
SomeHelper.FindPerson(MainModel.SearchName);
}
Therefore Command in this case is a wrapper for a call method in ViewModel
.