-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
ViewModelLocationProvider.cs
188 lines (158 loc) · 7.98 KB
/
ViewModelLocationProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
namespace Prism.Mvvm
{
/// <summary>
/// The ViewModelLocationProvider class locates the view model for the view that has the AutoWireViewModelChanged attached property set to true.
/// The view model will be located and injected into the view's DataContext. To locate the view, two strategies are used: First the ViewModelLocationProvider
/// will look to see if there is a view model factory registered for that view, if not it will try to infer the view model using a convention based approach.
/// This class also provide methods for registering the view model factories,
/// and also to override the default view model factory and the default view type to view model type resolver.
/// </summary>
// Documentation on using the MVVM pattern is at http://go.microsoft.com/fwlink/?LinkID=288814&clcid=0x409
public static class ViewModelLocationProvider
{
/// <summary>
/// A dictionary that contains all the registered factories for the views.
/// </summary>
static Dictionary<string, Func<object>> _factories = new Dictionary<string, Func<object>>();
/// <summary>
/// A dictionary that contains all the registered ViewModel types for the views.
/// </summary>
static Dictionary<string, Type> _typeFactories = new Dictionary<string, Type>();
/// <summary>
/// The default view model factory which provides the ViewModel type as a parameter.
/// </summary>
static Func<Type, object> _defaultViewModelFactory = type => Activator.CreateInstance(type);
/// <summary>
/// ViewModelfactory that provides the View instance and ViewModel type as parameters.
/// </summary>
static Func<object, Type, object> _defaultViewModelFactoryWithViewParameter;
/// <summary>
/// Default view type to view model type resolver, assumes the view model is in same assembly as the view type, but in the "ViewModels" namespace.
/// </summary>
static Func<Type, Type> _defaultViewTypeToViewModelTypeResolver =
viewType =>
{
var viewName = viewType.FullName;
viewName = viewName.Replace(".Views.", ".ViewModels.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var suffix = viewName.EndsWith("View") ? "Model" : "ViewModel";
var viewModelName = String.Format(CultureInfo.InvariantCulture, "{0}{1}, {2}", viewName, suffix, viewAssemblyName);
return Type.GetType(viewModelName);
};
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory which provides the ViewModel type as a parameter.</param>
public static void SetDefaultViewModelFactory(Func<Type, object> viewModelFactory)
{
_defaultViewModelFactory = viewModelFactory;
}
/// <summary>
/// Sets the default view model factory.
/// </summary>
/// <param name="viewModelFactory">The view model factory that provides the View instance and ViewModel type as parameters.</param>
public static void SetDefaultViewModelFactory(Func<object, Type, object> viewModelFactory)
{
_defaultViewModelFactoryWithViewParameter = viewModelFactory;
}
/// <summary>
/// Sets the default view type to view model type resolver.
/// </summary>
/// <param name="viewTypeToViewModelTypeResolver">The view type to view model type resolver.</param>
public static void SetDefaultViewTypeToViewModelTypeResolver(Func<Type, Type> viewTypeToViewModelTypeResolver)
{
_defaultViewTypeToViewModelTypeResolver = viewTypeToViewModelTypeResolver;
}
/// <summary>
/// Automatically looks up the viewmodel that corresponds to the current view, using two strategies:
/// It first looks to see if there is a mapping registered for that view, if not it will fallback to the convention based approach.
/// </summary>
/// <param name="view">The dependency object, typically a view.</param>
/// <param name="setDataContextCallback">The call back to use to create the binding between the View and ViewModel</param>
public static void AutoWireViewModelChanged(object view, Action<object, object> setDataContextCallback)
{
// Try mappings first
object viewModel = GetViewModelForView(view);
// try to use ViewModel type
if (viewModel == null)
{
//check type mappings
var viewModelType = GetViewModelTypeForView(view.GetType());
// fallback to convention based
if (viewModelType == null)
viewModelType = _defaultViewTypeToViewModelTypeResolver(view.GetType());
if (viewModelType == null)
return;
viewModel = _defaultViewModelFactoryWithViewParameter != null ? _defaultViewModelFactoryWithViewParameter(view, viewModelType) : _defaultViewModelFactory(viewModelType);
}
setDataContextCallback(view, viewModel);
}
/// <summary>
/// Gets the view model for the specified view.
/// </summary>
/// <param name="view">The view that the view model wants.</param>
/// <returns>The ViewModel that corresponds to the view passed as a parameter.</returns>
private static object GetViewModelForView(object view)
{
var viewKey = view.GetType().ToString();
// Mapping of view models base on view type (or instance) goes here
if (_factories.ContainsKey(viewKey))
return _factories[viewKey]();
return null;
}
/// <summary>
/// Gets the ViewModel type for the specified view.
/// </summary>
/// <param name="view">The View that the ViewModel wants.</param>
/// <returns>The ViewModel type that corresponds to the View.</returns>
private static Type GetViewModelTypeForView(Type view)
{
var viewKey = view.ToString();
if (_typeFactories.ContainsKey(viewKey))
return _typeFactories[viewKey];
return null;
}
/// <summary>
/// Registers the ViewModel factory for the specified view type.
/// </summary>
/// <typeparam name="T">The View</typeparam>
/// <param name="factory">The ViewModel factory.</param>
public static void Register<T>(Func<object> factory)
{
Register(typeof(T).ToString(), factory);
}
/// <summary>
/// Registers the ViewModel factory for the specified view type name.
/// </summary>
/// <param name="viewTypeName">The name of the view type.</param>
/// <param name="factory">The ViewModel factory.</param>
public static void Register(string viewTypeName, Func<object> factory)
{
_factories[viewTypeName] = factory;
}
/// <summary>
/// Registers a ViewModel type for the specified view type.
/// </summary>
/// <typeparam name="T">The View</typeparam>
/// <typeparam name="VM">The ViewModel</typeparam>
public static void Register<T, VM>()
{
var viewType = typeof(T);
var viewModelType = typeof(VM);
Register(viewType.ToString(), viewModelType);
}
/// <summary>
/// Registers a ViewModel type for the specified view.
/// </summary>
/// <param name="viewTypeName">The View type name</param>
/// <param name="viewModelType">The ViewModel type</param>
public static void Register(string viewTypeName, Type viewModelType)
{
_typeFactories[viewTypeName] = viewModelType;
}
}
}