For the following reasons, ViewModel also requires multiple and needs to be injected:
1: different data needs to be provided for the View at design time and runtime.
To put it simply, data needs to be simulated during design. Interface Design developers need to bind (including support for Expression Blend binding) to do some simple processing. At the same time, because the simulation data is provided, the UI staff can better design the actual interface.
2: To facilitate Unit Testing
In most cases, ViewModel is combined into the Service class that provides the Service. In a simple application, we can inject a Service class MOCK for unit testing. If so, we can avoid providing multiple viewmodels. However, in some applications, such as Silverlight applications, services are provided by WerbService and WCF, and the interface classes supported by client application services are not allowed, and the client code is automatically generated, in this way, we need to provide multiple viewmodels to support unit testing.
3: provide simulated data for Design
Considering that there need to be multiple VMS, the ui vm needs to have a base class. Assuming that my UI needs to display a list of students, my VM base class is designed as follows:
View sourceprint? Public class MainPageVmBase
{
Public MainPageVmBase ()
{
Click = new DelegateCommand (OnClick );
}
Public IStudent StudentService {get; set ;}
Public IView View {get; set ;}
Private ICommand click;
Public ICommand Click
{
Get {return click ;}
Set {click = value ;}
}
Void OnClick (object arg)
{
View. Title = arg as string;
View. Show ();
}
Private List <Student> studets;
Public List <Student> Studets
{
Get {return studets ;}
Set {studets = value ;}
}
}
If the VM during design needs to provide analog data, the VM is:
View sourceprint? Public class MainPageVmMock: MainPageVmBase
{
Public MainPageVmMock ()
{
Studets = new List <Student> ()
{
New Student () {Name = "d1", Age = 11 },
New Student () {Name = "d2", Age = 22}
};
}
}
To explicitly simulate data during design, we need to use a DesignHelpers class (this class comes from the https://github.com/jeremiahredekop ):
View sourceprint? Public static class DesignHelpers
{
Private static bool? _ DesignMode;
Public static bool DesignMode
{
Get
{
If (! _ DesignMode. HasValue)
{
# If! SILVERLIGHT
_ DesignMode = new bool? (DesignerProperties. GetIsInDesignMode (new System. Windows. DependencyObject ()));
# Else
_ IsInDesignMode = new bool? (DesignerProperties. IsInDesignTool );
# Endif
}
Return _ designMode. Value;
}
}
}
With the processing of this class, we can explicitly simulate data when Expression Blend is bound:
4: ViewModel FACTORY
The VM bound to each UI actually comes from the vm factory class. On the page above, we are bound to the ViewModel attribute in MainPageVmFactory. Each VmFactory also has its own base class, as shown below:
View sourceprint? Public class ViewModelFactory <TViewModelRealBase>
Where TViewModelRealBase: class, new ()
{
Public TViewModelRealBase ViewModel
{
Get;
Set;
}
}
MainPageVmFactory is as follows:
View sourceprint? Public class MainPageVmFactory: ViewModelFactory <MainPageVmBase>
{
Public MainPageVmFactory ()
{
If (DesignHelpers. DesignMode = true)
{
This. ViewModel = new MainPageVmMock ();
}
Else
{
Using (IUnityContainer container = new UnityContainer ())
{
Var section = (UnityConfigurationSection) ConfigurationManager. GetSection ("unity ");
Section. Configure (container, "containerOne ");
This. ViewModel = container. Resolve <MainPageVmBase> ("MainPageVmReal ");
}
}
}
}
We can see that the VM at runtime is obtained through the unity injection method. As mentioned at the beginning of this article, the injection method is used for the convenience of unit testing. The injection is the MainPageVmReal type, which contains the service class that actually provides data, as follows:
View sourceprint? Public class MainPageVmReal: MainPageVmBase
{
Public MainPageVmReal ()
{
// Studets = new List <Student> ()
//{
// New Student () {Name = "r1", Age = 11 },
// New Student () {Name = "r2", Age = 22}
//};
Using (IUnityContainer container = new UnityContainer ())
{
UnityConfigurationSection section = (UnityConfigurationSection) ConfigurationManager. GetSection ("unity ");
Section. Configure (container, "containerOne ");
IStudent service = container. Resolve <IStudent> ("StudentService ");
Studets = service. GetAllStudent () as List <Student>;
}
}
}
In MainPageVmReal, the actual data service class can be the client code of WCF, or anything else. This is not the focus of our attention, so we don't have to worry about the injection code in it.
Running result:
5: Injection
Injection is easy to understand. Writing in the configuration requires the VM type: