├── .gitignore
├── CHANGELOG.md
├── Documentation
├── logo.png
└── project_structured.png
├── LICENSE.md
├── NuGet
└── MvvmCodeGenerator.nuspec
├── README.md
└── Sources
├── MvvmCodeGenerator.Dev
├── MvvmCodeGenMapper.xml
├── MvvmCodeGenerator.Dev.csproj
└── Program.cs
├── MvvmCodeGenerator.Gen
├── Bootstrap.cs
├── Generation
│ ├── CSharpGenerator.cs
│ └── IGenerator.cs
├── Generators
│ ├── FreshMvvmGenerator.cs
│ ├── MvvmCrossGenerator.cs
│ ├── MvvmLightLibsGenerator.cs
│ ├── MvvmicroGenerator.cs
│ └── PrismCoreGenerator.cs
├── Helpers
│ ├── CommandHelper.cs
│ ├── Constants.cs
│ ├── FileHelper.cs
│ ├── FormatterHelper.cs
│ ├── PropertiesHelper.cs
│ └── TypeExtensions.cs
├── MvvmCodeGenerator.Gen.csproj
├── MvvmCodeGenerator.targets
├── MvvmCodeGeneratorBaseTask.cs
├── MvvmCodeGeneratorCleanTask.cs
├── MvvmCodeGeneratorTask.cs
├── Parsing
│ └── XmlParser.cs
├── Resources
│ ├── Arguments.cs
│ ├── Command.cs
│ ├── Property.cs
│ ├── ResourceFile.cs
│ └── ViewModel.cs
└── Settings.StyleCop
├── MvvmCodeGenerator.sln
└── Xamarin.Sample
├── Models
└── House.cs
├── MvvmCodeGenMapper.xml
└── Xamarin.Sample.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | # globs
2 | Makefile.in
3 | *.userprefs
4 | *.usertasks
5 | config.make
6 | config.status
7 | aclocal.m4
8 | install-sh
9 | autom4te.cache/
10 | *.tar.gz
11 | tarballs/
12 | test-results/
13 |
14 | # Mac bundle stuff
15 | *.dmg
16 | *.app
17 |
18 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
19 | # General
20 | .DS_Store
21 | .AppleDouble
22 | .LSOverride
23 |
24 | # Icon must end with two \r
25 | Icon
26 |
27 |
28 | # Thumbnails
29 | ._*
30 |
31 | # Files that might appear in the root of a volume
32 | .DocumentRevisions-V100
33 | .fseventsd
34 | .Spotlight-V100
35 | .TemporaryItems
36 | .Trashes
37 | .VolumeIcon.icns
38 | .com.apple.timemachine.donotpresent
39 |
40 | # Directories potentially created on remote AFP share
41 | .AppleDB
42 | .AppleDesktop
43 | Network Trash Folder
44 | Temporary Items
45 | .apdisk
46 |
47 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
48 | # Windows thumbnail cache files
49 | Thumbs.db
50 | ehthumbs.db
51 | ehthumbs_vista.db
52 |
53 | # Dump file
54 | *.stackdump
55 |
56 | # Folder config file
57 | [Dd]esktop.ini
58 |
59 | # Recycle Bin used on file shares
60 | $RECYCLE.BIN/
61 |
62 | # Windows Installer files
63 | *.cab
64 | *.msi
65 | *.msix
66 | *.msm
67 | *.msp
68 |
69 | # Windows shortcuts
70 | *.lnk
71 |
72 | # content below from: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
73 | ## Ignore Visual Studio temporary files, build results, and
74 | ## files generated by popular Visual Studio add-ons.
75 | ##
76 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
77 |
78 | # User-specific files
79 | *.suo
80 | *.user
81 | *.userosscache
82 | *.sln.docstates
83 |
84 | # User-specific files (MonoDevelop/Xamarin Studio)
85 | *.userprefs
86 |
87 | # Build results
88 | [Dd]ebug/
89 | [Dd]ebugPublic/
90 | [Rr]elease/
91 | [Rr]eleases/
92 | x64/
93 | x86/
94 | bld/
95 | [Bb]in/
96 | [Oo]bj/
97 | [Ll]og/
98 |
99 | # Visual Studio 2015/2017 cache/options directory
100 | .vs/
101 | # Uncomment if you have tasks that create the project's static files in wwwroot
102 | #wwwroot/
103 |
104 | # Visual Studio 2017 auto generated files
105 | Generated\ Files/
106 |
107 | # MSTest test Results
108 | [Tt]est[Rr]esult*/
109 | [Bb]uild[Ll]og.*
110 |
111 | # NUNIT
112 | *.VisualState.xml
113 | TestResult.xml
114 |
115 | # Build Results of an ATL Project
116 | [Dd]ebugPS/
117 | [Rr]eleasePS/
118 | dlldata.c
119 |
120 | # Benchmark Results
121 | BenchmarkDotNet.Artifacts/
122 |
123 | # .NET Core
124 | project.lock.json
125 | project.fragment.lock.json
126 | artifacts/
127 |
128 | # StyleCop
129 | StyleCopReport.xml
130 |
131 | # Files built by Visual Studio
132 | *_i.c
133 | *_p.c
134 | *_h.h
135 | *.ilk
136 | *.meta
137 | *.obj
138 | *.iobj
139 | *.pch
140 | *.pdb
141 | *.ipdb
142 | *.pgc
143 | *.pgd
144 | *.rsp
145 | *.sbr
146 | *.tlb
147 | *.tli
148 | *.tlh
149 | *.tmp
150 | *.tmp_proj
151 | *_wpftmp.csproj
152 | *.log
153 | *.vspscc
154 | *.vssscc
155 | .builds
156 | *.pidb
157 | *.svclog
158 | *.scc
159 |
160 | # Chutzpah Test files
161 | _Chutzpah*
162 |
163 | # Visual C++ cache files
164 | ipch/
165 | *.aps
166 | *.ncb
167 | *.opendb
168 | *.opensdf
169 | *.sdf
170 | *.cachefile
171 | *.VC.db
172 | *.VC.VC.opendb
173 |
174 | # Visual Studio profiler
175 | *.psess
176 | *.vsp
177 | *.vspx
178 | *.sap
179 |
180 | # Visual Studio Trace Files
181 | *.e2e
182 |
183 | # TFS 2012 Local Workspace
184 | $tf/
185 |
186 | # Guidance Automation Toolkit
187 | *.gpState
188 |
189 | # ReSharper is a .NET coding add-in
190 | _ReSharper*/
191 | *.[Rr]e[Ss]harper
192 | *.DotSettings.user
193 |
194 | # JustCode is a .NET coding add-in
195 | .JustCode
196 |
197 | # TeamCity is a build add-in
198 | _TeamCity*
199 |
200 | # DotCover is a Code Coverage Tool
201 | *.dotCover
202 |
203 | # AxoCover is a Code Coverage Tool
204 | .axoCover/*
205 | !.axoCover/settings.json
206 |
207 | # Visual Studio code coverage results
208 | *.coverage
209 | *.coveragexml
210 |
211 | # NCrunch
212 | _NCrunch_*
213 | .*crunch*.local.xml
214 | nCrunchTemp_*
215 |
216 | # MightyMoose
217 | *.mm.*
218 | AutoTest.Net/
219 |
220 | # Web workbench (sass)
221 | .sass-cache/
222 |
223 | # Installshield output folder
224 | [Ee]xpress/
225 |
226 | # DocProject is a documentation generator add-in
227 | DocProject/buildhelp/
228 | DocProject/Help/*.HxT
229 | DocProject/Help/*.HxC
230 | DocProject/Help/*.hhc
231 | DocProject/Help/*.hhk
232 | DocProject/Help/*.hhp
233 | DocProject/Help/Html2
234 | DocProject/Help/html
235 |
236 | # Click-Once directory
237 | publish/
238 |
239 | # Publish Web Output
240 | *.[Pp]ublish.xml
241 | *.azurePubxml
242 | # Note: Comment the next line if you want to checkin your web deploy settings,
243 | # but database connection strings (with potential passwords) will be unencrypted
244 | *.pubxml
245 | *.publishproj
246 |
247 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
248 | # checkin your Azure Web App publish settings, but sensitive information contained
249 | # in these scripts will be unencrypted
250 | PublishScripts/
251 |
252 | # NuGet Packages
253 | *.nupkg
254 | # The packages folder can be ignored because of Package Restore
255 | **/[Pp]ackages/*
256 | # except build/, which is used as an MSBuild target.
257 | !**/[Pp]ackages/build/
258 | # Uncomment if necessary however generally it will be regenerated when needed
259 | #!**/[Pp]ackages/repositories.config
260 | # NuGet v3's project.json files produces more ignorable files
261 | *.nuget.props
262 | *.nuget.targets
263 |
264 | # Microsoft Azure Build Output
265 | csx/
266 | *.build.csdef
267 |
268 | # Microsoft Azure Emulator
269 | ecf/
270 | rcf/
271 |
272 | # Windows Store app package directories and files
273 | AppPackages/
274 | BundleArtifacts/
275 | Package.StoreAssociation.xml
276 | _pkginfo.txt
277 | *.appx
278 |
279 | # Visual Studio cache files
280 | # files ending in .cache can be ignored
281 | *.[Cc]ache
282 | # but keep track of directories ending in .cache
283 | !*.[Cc]ache/
284 |
285 | # Others
286 | ClientBin/
287 | ~$*
288 | *~
289 | *.dbmdl
290 | *.dbproj.schemaview
291 | *.jfm
292 | *.pfx
293 | *.publishsettings
294 | orleans.codegen.cs
295 |
296 | # Including strong name files can present a security risk
297 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
298 | #*.snk
299 |
300 | # Since there are multiple workflows, uncomment next line to ignore bower_components
301 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
302 | #bower_components/
303 |
304 | # RIA/Silverlight projects
305 | Generated_Code/
306 |
307 | # Backup & report files from converting an old project file
308 | # to a newer Visual Studio version. Backup files are not needed,
309 | # because we have git ;-)
310 | _UpgradeReport_Files/
311 | Backup*/
312 | UpgradeLog*.XML
313 | UpgradeLog*.htm
314 | ServiceFabricBackup/
315 | *.rptproj.bak
316 |
317 | # SQL Server files
318 | *.mdf
319 | *.ldf
320 | *.ndf
321 |
322 | # Business Intelligence projects
323 | *.rdl.data
324 | *.bim.layout
325 | *.bim_*.settings
326 | *.rptproj.rsuser
327 |
328 | # Microsoft Fakes
329 | FakesAssemblies/
330 |
331 | # GhostDoc plugin setting file
332 | *.GhostDoc.xml
333 |
334 | # Node.js Tools for Visual Studio
335 | .ntvs_analysis.dat
336 | node_modules/
337 |
338 | # Visual Studio 6 build log
339 | *.plg
340 |
341 | # Visual Studio 6 workspace options file
342 | *.opt
343 |
344 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
345 | *.vbw
346 |
347 | # Visual Studio LightSwitch build output
348 | **/*.HTMLClient/GeneratedArtifacts
349 | **/*.DesktopClient/GeneratedArtifacts
350 | **/*.DesktopClient/ModelManifest.xml
351 | **/*.Server/GeneratedArtifacts
352 | **/*.Server/ModelManifest.xml
353 | _Pvt_Extensions
354 |
355 | # Paket dependency manager
356 | .paket/paket.exe
357 | paket-files/
358 |
359 | # FAKE - F# Make
360 | .fake/
361 |
362 | # JetBrains Rider
363 | .idea/
364 | *.sln.iml
365 |
366 | # CodeRush personal settings
367 | .cr/personal
368 |
369 | # Python Tools for Visual Studio (PTVS)
370 | __pycache__/
371 | *.pyc
372 |
373 | # Cake - Uncomment if you are using it
374 | # tools/**
375 | # !tools/packages.config
376 |
377 | # Tabs Studio
378 | *.tss
379 |
380 | # Telerik's JustMock configuration file
381 | *.jmconfig
382 |
383 | # BizTalk build output
384 | *.btp.cs
385 | *.btm.cs
386 | *.odx.cs
387 | *.xsd.cs
388 |
389 | # OpenCover UI analysis results
390 | OpenCover/
391 |
392 | # Azure Stream Analytics local run output
393 | ASALocalRun/
394 |
395 | # MSBuild Binary and Structured Log
396 | *.binlog
397 |
398 | # NVidia Nsight GPU debugger configuration file
399 | *.nvuser
400 |
401 | # MFractors (Xamarin productivity tool) working folder
402 | .mfractor/
403 |
404 | # Local History for Visual Studio
405 | .localhistory/
406 |
407 | # Generated code
408 | *.interface.g.cs
409 | *.part.g.cs
410 | *.g.targets
411 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | ## 1.1.3 - 2019-08-19
5 | ### Added
6 | - You can now comment lines in your `MvvmCodeGenMapper.xml`
7 |
8 | ### Fixed
9 | - GeneratorTask task was executed after CoreCompile task instead of before CoreCompile.
10 |
11 | ## 1.1.2 - 2019-08-19
12 | ### Added
13 | - Fix .g.targets issue
14 | - Clean code
15 |
16 | ## 1.1.1 - 2019-08-19
17 | ### Added
18 | - Fix .g.targets issue
19 |
20 | ## 1.1.0 - 2019-08-15
21 | ### Added
22 | - Add Prism Core support.
23 | - Update `Readme.md`
24 |
25 | ## 1.0.0 - 2019-07-26
26 | ### Added
27 | - First stable version of the plugin, now supports for MvvmCross, MvvmLightLibs, Mvvmicro and FreshMvvm.
28 | - Generate your ViewModels : commands and properties.
29 |
30 |
--------------------------------------------------------------------------------
/Documentation/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/damienaicheh/MvvmCodeGenerator/8fdd339ba7c568c0d3da33be29a6760ab13fef90/Documentation/logo.png
--------------------------------------------------------------------------------
/Documentation/project_structured.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/damienaicheh/MvvmCodeGenerator/8fdd339ba7c568c0d3da33be29a6760ab13fef90/Documentation/project_structured.png
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Damien Aicheh
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/NuGet/MvvmCodeGenerator.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MvvmCodeGenerator
6 |
7 |
8 | 1.1.3
9 |
10 |
11 | Damien Aicheh
12 |
13 |
17 | Damien Aicheh
18 |
19 |
20 | https://github.com/damienaicheh/MvvmCodeGenerator
21 |
22 |
23 | MIT
24 |
25 |
26 |
27 | https://raw.githubusercontent.com/damienaicheh/MvvmCodeGenerator/master/Documentation/logo.png
28 |
29 |
33 | true
34 |
35 |
36 | Generate boilerplate code for MvvmLightLibs, MvvmCross, Prism, Mvvmicro and FreshMvvm.
37 |
38 |
42 | Save time by generating boilerplate code for different MVVM framework, this nuget support now: MvvmLightLibs, MvvmCross, Prism, Mvvmicro and FreshMvvm.
43 |
44 |
45 | Copyright ©2019 Damien Aicheh
46 |
47 |
48 | mvvm generator xamarin dotnet command properties mvvmicro mvvmcross mvvmlightlibs freshmvvm prism mvvmcodegen
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | MVVM code generator tool for .NET.
4 |
5 | ## Install
6 |
7 | Available on [NuGet](https://www.nuget.org/packages/MvvmCodeGenerator).
8 |
9 | ## Why ?
10 |
11 | I decided to create this tool to avoid having to always write boilerplate code for my ViewModels. This NuGet is built on top of the [Rosyln .NET compiler](https://github.com/dotnet/roslyn).
12 |
13 | The advantages of using it are :
14 | * Reduce the amount of code in your ViewModels
15 | * The ViewModels only contains the more important code
16 | * Migrate from one MVVM Framework to another easily
17 |
18 | ## Features
19 |
20 | This NuGet allows you to generate your ViewModels with the Properties and Commands specified in your XML file. The code generated will depend on the Mvvm Frameworks you like.
21 |
22 | This tool now support these MVVM Frameworks:
23 |
24 | * [MvvmLightLibs](https://www.nuget.org/packages/MvvmLightLibs/)
25 | * [MvvmCross](https://www.nuget.org/packages/MvvmCross/)
26 | * [Mvvmicro](https://www.nuget.org/packages/Mvvmicro/)
27 | * [FreshMvvm](https://www.nuget.org/packages/FreshMvvm/)
28 | * [Prism.Core](https://www.nuget.org/packages/Prism.Core/)
29 |
30 | ## Tutorial
31 |
32 | You will find a complete tutorial here:
33 | ##### English version :
34 | [https://damienaicheh.github.io/nuget/xamarin/xamarin.forms/dotnet/2019/07/31/a-complete-overview-of-mvvmcodegenerator-en](https://damienaicheh.github.io/nuget/xamarin/xamarin.forms/dotnet/2019/07/31/a-complete-overview-of-mvvmcodegenerator-en)
35 |
36 | ##### French version :
37 | [https://damienaicheh.github.io/nuget/xamarin/xamarin.forms/dotnet/2019/07/31/a-complete-overview-of-mvvmcodegenerator-fr](https://damienaicheh.github.io/nuget/xamarin/xamarin.forms/dotnet/2019/07/31/a-complete-overview-of-mvvmcodegenerator-fr)
38 |
39 | ## Usage
40 | ### Setup
41 |
42 | First of all, install the [NuGet](https://www.nuget.org/packages/MvvmCodeGenerator) package to your .NetStandard project for example.
43 | Then create a new file called `MvvmCodeGenMapper.xml` at the root of your library project. This file will contain the definition of your ViewModels.
44 |
45 | ### Configure your generator
46 |
47 | Now it's time to define which generator we want to use, 4 options are available:
48 | * mvvmlightlibs
49 | * mvvmcross
50 | * mvvmicro
51 | * freshmvvm
52 | * prismcore
53 |
54 | Choose the one you like and declare it inside your `MvvmCodeGenMapper.xml` like this:
55 |
56 | ```xml
57 |
58 |
59 |
60 |
61 | ```
62 |
63 | ### Create your ViewModels
64 |
65 | Let's define the ViewModels inside the `ViewModels` tags. You can define as many `ViewModels` tags as needed. Here is an example:
66 |
67 | ```xml
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | ```
83 |
84 | As you can see above, you can specify a list of ViewModels for a specific namespace and destination folder.
85 |
86 | This XML will generate the 2 ViewModels with their **.g.cs** class associated:
87 |
88 | The `RootViewModel.cs`:
89 | ```csharp
90 | namespace MvvmCodeGenerator.Sample
91 | {
92 | using System;
93 | using System.Collections.Generic;
94 | using System.Threading;
95 | using System.Threading.Tasks;
96 | using GalaSoft.MvvmLight.Command;
97 |
98 | public partial class RootViewModel
99 | {
100 | }
101 | }
102 | ```
103 |
104 | The `RootViewModel.interface.g.cs`:
105 | ```csharp
106 | //------------------------------------------------------------------------------
107 | //
108 | // This code was generated by MvvmCodeGenerator.
109 | // Runtime Version:4.0.30319.42000
110 | //
111 | // Changes to this file may cause incorrect behavior and will be lost if
112 | // the code is regenerated.
113 | //
114 | //------------------------------------------------------------------------------
115 | namespace MvvmCodeGenerator.Sample
116 | {
117 | using System;
118 | using System.Collections.Generic;
119 | using System.Threading;
120 | using System.Threading.Tasks;
121 | using GalaSoft.MvvmLight.Command;
122 |
123 | public interface IRootViewModel : System.ComponentModel.INotifyPropertyChanged
124 | {
125 | System.Boolean IsLoading
126 | {
127 | get;
128 | }
129 | }
130 | }
131 | ```
132 |
133 | The `RootViewModel.part.g.cs`:
134 | ```csharp
135 | //------------------------------------------------------------------------------
136 | //
137 | // This code was generated by MvvmCodeGenerator.
138 | // Runtime Version:4.0.30319.42000
139 | //
140 | // Changes to this file may cause incorrect behavior and will be lost if
141 | // the code is regenerated.
142 | //
143 | //------------------------------------------------------------------------------
144 | namespace MvvmCodeGenerator.Sample
145 | {
146 | using System;
147 | using System.Collections.Generic;
148 | using System.Threading;
149 | using System.Threading.Tasks;
150 | using GalaSoft.MvvmLight.Command;
151 |
152 | public partial class RootViewModel : GalaSoft.MvvmLight.ViewModelBase, MvvmCodeGenerator.Sample.IRootViewModel
153 | {
154 | private System.Boolean isLoading;
155 | ///
156 | // Gets or sets the loader property.
157 | ///
158 | public System.Boolean IsLoading
159 | {
160 | get => this.isLoading;
161 | set => this.Set(ref this.isLoading, value);
162 | }
163 | }
164 | }
165 | ```
166 |
167 | The `DashboardViewModel.cs` where you will implement the Commands declared:
168 |
169 | ```csharp
170 | Folder destination ./MvvmCodeGenerator.Dev/ViewModel
171 | namespace MvvmCodeGenerator.Sample
172 | {
173 | using System;
174 | using System.Collections.Generic;
175 | using System.Threading;
176 | using System.Threading.Tasks;
177 | using GalaSoft.MvvmLight.Command;
178 |
179 | public partial class DashboardViewModel
180 | {
181 | }
182 | }
183 | ```
184 |
185 | The `DashboardViewModel.interface.g.cs`:
186 | ```csharp
187 | //------------------------------------------------------------------------------
188 | //
189 | // This code was generated by MvvmCodeGenerator.
190 | // Runtime Version:4.0.30319.42000
191 | //
192 | // Changes to this file may cause incorrect behavior and will be lost if
193 | // the code is regenerated.
194 | //
195 | //------------------------------------------------------------------------------
196 | namespace MvvmCodeGenerator.Sample
197 | {
198 | using System;
199 | using System.Collections.Generic;
200 | using System.Threading;
201 | using System.Threading.Tasks;
202 | using GalaSoft.MvvmLight.Command;
203 |
204 | public interface IDashboardViewModel : MvvmCodeGenerator.Sample.IRootViewModel
205 | {
206 | System.String Title
207 | {
208 | get;
209 | }
210 |
211 | System.Windows.Input.ICommand BuyCommand
212 | {
213 | get;
214 | }
215 |
216 | System.Boolean IsConsultationCommandRunning
217 | {
218 | get;
219 | }
220 |
221 | System.Windows.Input.ICommand ConsultationCommand
222 | {
223 | get;
224 | }
225 | }
226 | }
227 | ```
228 |
229 | The `DashboardViewModel.part.g.cs`:
230 | ```csharp
231 | //------------------------------------------------------------------------------
232 | //
233 | // This code was generated by MvvmCodeGenerator.
234 | // Runtime Version:4.0.30319.42000
235 | //
236 | // Changes to this file may cause incorrect behavior and will be lost if
237 | // the code is regenerated.
238 | //
239 | //------------------------------------------------------------------------------
240 | namespace MvvmCodeGenerator.Sample
241 | {
242 | using System;
243 | using System.Collections.Generic;
244 | using System.Threading;
245 | using System.Threading.Tasks;
246 | using GalaSoft.MvvmLight.Command;
247 |
248 | public partial class DashboardViewModel : MvvmCodeGenerator.Sample.RootViewModel, MvvmCodeGenerator.Sample.IDashboardViewModel
249 | {
250 | private System.String title;
251 | private System.Boolean isConsultationCommandRunning;
252 | private GalaSoft.MvvmLight.Command.RelayCommand buyCommand;
253 | private GalaSoft.MvvmLight.Command.RelayCommand consultationCommand;
254 | ///
255 | // Gets or sets the title.
256 | ///
257 | public System.String Title
258 | {
259 | get => this.title;
260 | set => this.Set(ref this.title, value);
261 | }
262 |
263 | ///
264 | // Gets or sets the value to know if the associated async command is running.
265 | ///
266 | public System.Boolean IsConsultationCommandRunning
267 | {
268 | get => this.isConsultationCommandRunning;
269 | set => this.Set(ref this.isConsultationCommandRunning, value);
270 | }
271 |
272 | ///
273 | // Gets or sets the command to buy a boat
274 | ///
275 | public System.Windows.Input.ICommand BuyCommand
276 | {
277 | get => this.buyCommand ?? (this.buyCommand = new GalaSoft.MvvmLight.Command.RelayCommand(ExecuteBuyCommand)); // You must implement the following method(s): ExecuteBuyCommand and OnExecuteBuyCommandAsyncError
278 | }
279 |
280 | ///
281 | // Gets or sets the command to consult my orders
282 | ///
283 | public System.Windows.Input.ICommand ConsultationCommand
284 | {
285 | get => this.consultationCommand ?? (this.consultationCommand = new GalaSoft.MvvmLight.Command.RelayCommand(async (value) =>
286 | {
287 | try
288 | {
289 | this.IsConsultationCommandRunning = true;
290 | await ExecuteConsultationCommandAsync(value);
291 | }
292 | catch (System.Exception ex)
293 | {
294 | OnExecuteConsultationCommandAsyncError(ex);
295 | }
296 | finally
297 | {
298 | this.IsConsultationCommandRunning = false;
299 | }
300 | }
301 |
302 | , CanExecuteConsultationCommand)); // You must implement the following method(s): ExecuteConsultationCommandAsync and the CanExecuteConsultationCommand and OnExecuteConsultationCommandAsyncError
303 | }
304 | }
305 | }
306 | ```
307 |
308 | Now you juste have to implement the commands in each *ViewModel.cs* file.
309 |
310 | A *IsRunning* property is added in the case of **MvvmLightLibs** and **FreshMvvm** async commands for you. **MvvmCross** and **Mvvmicro** already have this kind of mechanism.
311 |
312 | ### Define your ViewModels and ItemViewModels
313 |
314 | Each `ViewModel` tag has different properties :
315 |
316 | * **Key** : The ViewModel name prefix
317 | * **Base** : The ViewModel name prefix of the parent class
318 |
319 | If you want to generate an ItemViewModel for each items of a listview for example, just use the `ItemViewModel` tag instead of `ViewModel`. You will have the same properties than the `ViewModel` tag available.
320 |
321 | You can specify the **Properties** and **Commands** for each ViewModels:
322 |
323 | For the **Properties** you have the ability to define it using the `Property` tag:
324 |
325 | * **Name** : The name of the property
326 | * **Description** : The comment associated to the property
327 | * **Type** : The type of the property
328 |
329 | You have different options to specify the **Type** of your property
330 |
331 | Here the list of base types that can be used:
332 |
333 | * **string**
334 | * **int**
335 | * **long**
336 | * **bool**
337 | * **float**
338 | * **object**
339 | * **double**
340 | * **DateTime**
341 | * **DateTimeOffset**
342 | * **TimeSpan**
343 |
344 | If the type you need is not in this list, you can just specify it using the complete namespace for example:
345 |
346 | ```xml
347 |
348 | ```
349 |
350 | You can also declare a list like this:
351 | ```xml
352 |
353 |
354 | ```
355 |
356 | For the **Commands** you have the ability to define:
357 |
358 | * Synchronous command using the `Command` tag
359 | * Asynchronous command using the `AsyncCommand` tag
360 |
361 | Each command tag has different properties:
362 | * **Name** : The name of the command
363 | * **Parameter** : The parameter type of the command
364 | * **CanExecute** : A boolean to know if the command must have a can execute method or not
365 | * **Description** : The comment associated to the command
366 |
367 | ### Visual Studio display
368 |
369 | If you build your project now, you will have this kind of result:
370 | 
371 |
372 | If your files are not grouped correctly like above, please check if the `MvvmCodeGenMapper.g.targets` file was imported correctly in your *.csproj* associated to your project. If it's not the case you can do it manually by adding this line:
373 |
374 | ```xml
375 |
376 | ```
377 |
378 | Relaod your project and you will be good to go.
379 |
380 | You will find a full example in the `Xamarin.Sample` project [here](https://github.com/damienaicheh/MvvmCodeGenerator/tree/master/Sources/Xamarin.Sample)
381 |
382 |
383 | ## Contributions
384 |
385 | Contributions are welcome! If you find a bug or if you want a feature please report it.
386 |
387 | If you want to contribute create a branch from the current master branch and when your code is ready create a pull request.
388 |
389 | ### License
390 |
391 | 
392 |
393 | © [Damien Aicheh](https://damienaicheh.github.io/)
394 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Dev/MvvmCodeGenMapper.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Dev/MvvmCodeGenerator.Dev.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Dev/Program.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Dev
2 | {
3 | using System;
4 | using MvvmCodeGenerator.Gen;
5 |
6 | class Program
7 | {
8 | static void Main(string[] args)
9 | {
10 | Console.WriteLine($"Args:");
11 | foreach (var arg in args)
12 | {
13 | Console.WriteLine($" {arg}");
14 | }
15 |
16 | // Run this command in terminal to test the sample project:
17 |
18 | //dotnet run --project ./MvvmCodeGenerator.Gen/MvvmCodeGenerator.Gen.csproj -i:"./MvvmCodeGenerator.Sample/MvvmCodeGenMapper.xml" -o:"./MvvmCodeGenerator.Sample" -g:mvvmicro
19 | //var inputFile = args[0]?.Split("-i:")[1];
20 | //var outputFolderProject = args[1]?.Split("-o:")[1];
21 | //var content = File.ReadAllText(inputFile);
22 |
23 | // Run the project directly with this configuration:
24 |
25 | var outputFolderProject = "./MvvmCodeGenerator.Dev";
26 |
27 | Arguments arguments = new Arguments
28 | {
29 | OutputFolderProject = outputFolderProject
30 | };
31 |
32 | Bootstrap.Start("./../../../../MvvmCodeGenerator.Dev/MvvmCodeGenMapper.xml", arguments);
33 |
34 | Console.WriteLine("End of generation.");
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Bootstrap.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.IO;
4 | using Microsoft.Build.Utilities;
5 |
6 | ///
7 | /// Bootstrap the generator.
8 | ///
9 | public static class Bootstrap
10 | {
11 | ///
12 | /// Start the generation.
13 | ///
14 | /// The path to the Resource file.
15 | /// The arguments from the project.
16 | /// The default logging system.
17 | public static void Start(string filePath, Arguments arguments, TaskLoggingHelper logger = null)
18 | {
19 | var content = File.ReadAllText(filePath);
20 |
21 | XmlParser xmlParser = new XmlParser();
22 | ResourceFile resourceFile = xmlParser.ReadResourceFile(content);
23 |
24 | if (resourceFile.Generator != null)
25 | {
26 | CSharpGenerator gen = null;
27 |
28 | switch (resourceFile.Generator.ToLower())
29 | {
30 | case "mvvmicro":
31 | gen = new MvvmicroCSharpGenerator(resourceFile.ViewModels, arguments);
32 | break;
33 | case "mvvmlightlibs":
34 | gen = new MvvmLightLibsGenerator(resourceFile.ViewModels, arguments);
35 | break;
36 | case "mvvmcross":
37 | gen = new MvvmCrossGenerator(resourceFile.ViewModels, arguments);
38 | break;
39 | case "freshmvvm":
40 | gen = new FreshMvvmGenerator(resourceFile.ViewModels, arguments);
41 | break;
42 | case "prismcore":
43 | gen = new PrismCoreGenerator(resourceFile.ViewModels, arguments);
44 | break;
45 | }
46 |
47 | gen.Log = logger;
48 | gen.CleanGeneratedFiles();
49 | gen.Generate();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generation/CSharpGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Text;
7 | using System.Xml;
8 | using System.Xml.Linq;
9 | using Microsoft.Build.Utilities;
10 | using Microsoft.CodeAnalysis;
11 | using Microsoft.CodeAnalysis.CSharp;
12 | using Microsoft.CodeAnalysis.CSharp.Syntax;
13 |
14 | ///
15 | /// Base for all generators.
16 | ///
17 | public abstract class CSharpGenerator : IGenerator
18 | {
19 | ///
20 | /// Initializes a new instance of the class.
21 | /// Constructor base for all generators.
22 | ///
23 | /// List of ViewModels to generate.
24 | /// The arguments console.
25 | protected CSharpGenerator(List viewModels, Arguments arguments)
26 | {
27 | this.ViewModels = viewModels;
28 | this.Arguments = arguments;
29 | }
30 |
31 | ///
32 | /// Logger defined in the task.
33 | ///
34 | public TaskLoggingHelper Log { private get; set; }
35 |
36 | ///
37 | /// Define if the generator needs to have a IsRunning property for async commands.
38 | ///
39 | protected bool IsRunningPropertyForCommandNeeded { private get; set; }
40 |
41 | ///
42 | /// Gets or sets The namespace declaration for the current generated class.
43 | ///
44 | /// The namespace declaration.
45 | protected NamespaceDeclarationSyntax NamespaceDeclaration { get; set; }
46 |
47 | ///
48 | /// Gets or sets the current generated class declaration.
49 | ///
50 | /// The class declaration.
51 | protected ClassDeclarationSyntax ClassDeclaration { get; set; }
52 |
53 | ///
54 | /// Gets or sets the current generated interface.
55 | ///
56 | /// The interface declaration.
57 | protected InterfaceDeclarationSyntax InterfaceDeclaration { get; set; }
58 |
59 | private List ViewModels { get; set; }
60 |
61 | private Arguments Arguments { get; set; }
62 |
63 | ///
64 | /// Generate the ViewModels.
65 | ///
66 | public void Generate()
67 | {
68 | foreach (var viewModel in this.ViewModels)
69 | {
70 | this.GenerateViewModelImplementationFile(viewModel);
71 | this.GenerateViewModelInterfaceFile(viewModel);
72 | this.GenerateViewModelPartialFile(viewModel);
73 | }
74 |
75 | this.GenerateTarget(ViewModels, out string generatedTargetFilename);
76 | #if !DEBUG
77 | this.InjectProject(generatedTargetFilename);
78 | #endif
79 | }
80 |
81 | ///
82 | /// Clean previous files.
83 | ///
84 | ///
85 | /// At this time, this method has no effect.
86 | /// If the project has not previously built, or if it has been cleaned, there is no file to delete.
87 | /// And the dedicated task to file generation is not run, due to the cached data state of the project.
88 | ///
89 | public void CleanGeneratedFiles()
90 | {
91 | // Becarefull the cleanTask do the same thing.
92 | FileHelper.ResetTarget(this.Arguments.OutputFolderProject, Constants.GeneratedTargetFileWithoutExtension, Constants.GeneratedTargetFileExtension);
93 | FileHelper.Clean(this.Arguments.OutputFolderProject, "interface.g.cs");
94 | FileHelper.Clean(this.Arguments.OutputFolderProject, "part.g.cs");
95 | }
96 |
97 | ///
98 | /// Get the entire namespace of the command implementation.
99 | ///
100 | /// The namespace of the command.
101 | protected abstract string GetCommandNamespace();
102 |
103 | ///
104 | /// Get the entire namespace of the async command implementation.
105 | ///
106 | /// The namespace of the async command.
107 | protected abstract string GetAsyncCommandNamespace();
108 |
109 | ///
110 | /// Add base ViewModel if it is required by the framework.
111 | ///
112 | /// SyntaxNodeOrToken with the ViewModel base.
113 | protected abstract SyntaxNodeOrToken AddBaseViewModel();
114 |
115 | ///
116 | /// Writes a message into the default logging system.
117 | ///
118 | /// The message to log.
119 | [Conditional("DEBUG")]
120 | protected void LogMessage(string message)
121 | {
122 | if (!string.IsNullOrEmpty(message))
123 | {
124 | Log?.LogMessage(message);
125 | }
126 | }
127 |
128 | ///
129 | /// Create the default namespaces.
130 | ///
131 | /// The namespace of the current class generated.
132 | protected virtual void CreateNamespace(string @namespace)
133 | {
134 | this.NamespaceDeclaration = SyntaxFactory.NamespaceDeclaration(SyntaxFactory.ParseName(@namespace)).NormalizeWhitespace();
135 |
136 | // Add System using statement:
137 | var usings = new[] { "System", "System.Collections.Generic", "System.Threading", "System.Threading.Tasks" };
138 |
139 | foreach (var item in usings)
140 | {
141 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName(item)));
142 | }
143 | }
144 |
145 | ///
146 | /// Get command method syntax, depending on the framework used.
147 | ///
148 | /// The command to generate.
149 | /// The ArgumentListSyntax that represent the command syntax to generate
150 | protected virtual ArgumentListSyntax GetCommandMethodSyntax(Command command)
151 | {
152 | var syntaxeNodeOrToken = new List
153 | {
154 | SyntaxFactory.Argument(SyntaxFactory.IdentifierName(command.FormatExecuteCommandName()))
155 | };
156 |
157 | if (command.HasCanExecute)
158 | {
159 | syntaxeNodeOrToken.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
160 | syntaxeNodeOrToken.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(command.FormatCanExecuteCommandName())));
161 | }
162 |
163 | return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(syntaxeNodeOrToken));
164 | }
165 |
166 | ///
167 | /// Build base class to inherit.
168 | ///
169 | /// Namespace of the class.
170 | /// The class name.
171 | /// The SimpleBaseTypeSyntax of the base class.
172 | protected SimpleBaseTypeSyntax BuildBaseClass(string @namespace, string @class) =>
173 | SyntaxFactory.SimpleBaseType(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName(@namespace), SyntaxFactory.IdentifierName(@class)));
174 |
175 | ///
176 | /// Creates the public properties for each Mvvm library.
177 | ///
178 | /// The public properties.
179 | /// The property to generate.
180 | public virtual PropertyDeclarationSyntax CreatePublicProperties(Property property)
181 | {
182 | return SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(property.Type.FindType()), property.Name)
183 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
184 | .AddAccessorListAccessors(
185 | SyntaxFactory.AccessorDeclaration(
186 | SyntaxKind.GetAccessorDeclaration)
187 | .WithExpressionBody(
188 | SyntaxFactory.ArrowExpressionClause(
189 | SyntaxFactory.MemberAccessExpression(
190 | SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(property.Name.ToCamelCase()))))
191 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
192 | SyntaxFactory.AccessorDeclaration(
193 | SyntaxKind.SetAccessorDeclaration)
194 | .WithExpressionBody(
195 | SyntaxFactory.ArrowExpressionClause(
196 | SyntaxFactory.InvocationExpression(
197 | SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName("Set")))
198 | .WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(
199 | new SyntaxNodeOrToken[]
200 | {
201 | SyntaxFactory.Argument(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(property.Name.ToCamelCase())))
202 | .WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.RefKeyword)), SyntaxFactory.Token(SyntaxKind.CommaToken), SyntaxFactory.Argument(SyntaxFactory.IdentifierName("value"))
203 | })))))
204 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)))
205 | .WithModifiers(FormatterHelper.GenerateComment(property.Comment));
206 | }
207 |
208 | ///
209 | /// Generate command comment to indicate which method associated to the command needs to be implemented.
210 | ///
211 | /// The command.
212 | /// The complete comment to the command.
213 | public virtual string GenerateCommandComment(Command command)
214 | {
215 | var defaultComment = $"// You must implement the following method(s): {command.FormatExecuteCommandName()}";
216 | var isComment = command.HasCanExecute ? $" and the {command.FormatCanExecuteCommandName()}" : string.Empty;
217 | return string.Concat(defaultComment, isComment);
218 | }
219 |
220 | private void GenerateViewModelImplementationFile(ViewModel viewModel)
221 | {
222 | this.CreateNamespace(viewModel.Namespace);
223 | this.CreateClass(viewModel);
224 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddMembers(this.ClassDeclaration);
225 |
226 | // Normalize and get code as string.
227 | var content = this.NamespaceDeclaration.NormalizeWhitespace().ToFullString();
228 |
229 | FileHelper.SaveFileContent(this.Arguments.OutputFolderProject, viewModel.DestinationFolder, content, viewModel.CreateViewModelName(), ".cs", true);
230 | }
231 |
232 | private void GenerateViewModelPartialFile(ViewModel viewModel)
233 | {
234 | this.GenerateViewModel(viewModel);
235 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddMembers(this.ClassDeclaration);
236 | this.NamespaceDeclaration = this.NamespaceDeclaration.AutoGeneratedCommand();
237 |
238 | // Normalize and get code as string.
239 | var content = this.NamespaceDeclaration.NormalizeWhitespace().ToFullString();
240 |
241 | FileHelper.SaveFileContent(this.Arguments.OutputFolderProject, viewModel.DestinationFolder, content, viewModel.CreateViewModelName(), ".part.g.cs", false);
242 | }
243 |
244 | private void GenerateViewModelInterfaceFile(ViewModel viewModel)
245 | {
246 | this.GenerateInterfaceViewModel(viewModel);
247 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddMembers(this.InterfaceDeclaration);
248 | this.NamespaceDeclaration = this.NamespaceDeclaration.AutoGeneratedCommand();
249 |
250 | // Normalize and get code as string.
251 | var content = this.NamespaceDeclaration.NormalizeWhitespace().ToFullString();
252 |
253 | FileHelper.SaveFileContent(this.Arguments.OutputFolderProject, viewModel.DestinationFolder, content, viewModel.CreateViewModelName(), ".interface.g.cs", false);
254 | }
255 |
256 | private void GenerateViewModel(ViewModel viewModel)
257 | {
258 | this.CreateNamespace(viewModel.Namespace);
259 | this.CreateClass(viewModel);
260 | this.AddBaseClass(viewModel);
261 |
262 | var privateFields = new List();
263 | var publicProperties = new List();
264 |
265 | // Create all properties.
266 | if (viewModel.Properties.Count > 0)
267 | {
268 | foreach (var property in viewModel.Properties)
269 | {
270 | privateFields.Add(this.CreatePrivateVariable(property.Type.FindType(), property.Name));
271 | publicProperties.Add(this.CreatePublicProperties(property));
272 | }
273 | }
274 |
275 | // Create all commands.
276 | if (viewModel.Commands.Count > 0)
277 | {
278 | foreach (var command in viewModel.Commands)
279 | {
280 | // This is voluntary done in two separate loops to keep the public and private properties at the top of the file.
281 | if (this.IsRunningPropertyForCommandNeeded && command.IsAsync)
282 | {
283 | privateFields.Add(this.CreatePrivateVariable(typeof(bool).ToString(), command.FormatPropertyIsCommandRunning()));
284 | publicProperties.Add(this.CreatePublicProperties(new Property(command.FormatPropertyIsCommandRunning(), typeof(bool).ToString(), "Gets or sets the value to know if the associated async command is running.", true, true)));
285 | }
286 | }
287 |
288 | foreach (var command in viewModel.Commands)
289 | {
290 | var type = this.GetCommandType(command);
291 | privateFields.Add(this.CreatePrivateVariable(type, command.FormatCommandName()));
292 | publicProperties.Add(this.CreateCommandProperty(command));
293 | }
294 | }
295 |
296 | // Add all private fields to the class.
297 | foreach (var field in privateFields)
298 | {
299 | this.ClassDeclaration = this.ClassDeclaration.AddMembers(SyntaxFactory.FieldDeclaration(field)
300 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)));
301 | }
302 |
303 | // Add all public properties to the class.
304 | foreach (var publicProperty in publicProperties)
305 | {
306 | this.ClassDeclaration = this.ClassDeclaration.AddMembers(publicProperty);
307 | }
308 | }
309 |
310 | private void GenerateInterfaceViewModel(ViewModel viewModel)
311 | {
312 | this.CreateNamespace(viewModel.Namespace);
313 | this.CreateInterface(viewModel);
314 | this.AddBaseInterface(viewModel);
315 |
316 | // Create and add all properties to the interface.
317 | foreach (var property in viewModel.Properties)
318 | {
319 | var field = this.CreatePublicProperty(property.Type.FindType(), property.Name);
320 | this.InterfaceDeclaration = this.InterfaceDeclaration.AddMembers(field);
321 | }
322 |
323 | // Create and add all commands to the interface.
324 | foreach (var command in viewModel.Commands)
325 | {
326 | if (this.IsRunningPropertyForCommandNeeded && command.IsAsync)
327 | {
328 | var commandField = this.CreatePublicProperty(typeof(bool).ToString(), command.FormatPropertyIsCommandRunning());
329 | this.InterfaceDeclaration = this.InterfaceDeclaration.AddMembers(commandField);
330 | }
331 |
332 | var field = this.CreatePublicProperty(typeof(System.Windows.Input.ICommand).ToString(), command.FormatCommandName());
333 | this.InterfaceDeclaration = this.InterfaceDeclaration.AddMembers(field);
334 | }
335 | }
336 |
337 | private void CreateClass(ViewModel viewModel)
338 | {
339 | this.ClassDeclaration = SyntaxFactory.ClassDeclaration(viewModel.CreateViewModelName());
340 | this.ClassDeclaration = this.ClassDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
341 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword));
342 | }
343 |
344 | private void CreateInterface(ViewModel viewModel)
345 | {
346 | this.InterfaceDeclaration = SyntaxFactory.InterfaceDeclaration(string.Concat(viewModel.CreateInterfaceViewModelName()));
347 | this.InterfaceDeclaration = this.InterfaceDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));
348 | }
349 |
350 | private void AddBaseClass(ViewModel viewModel)
351 | {
352 | var baseClass = new List();
353 |
354 | if (viewModel.HasBase)
355 | {
356 | baseClass.Add(this.BuildBaseClass(viewModel.Namespace, viewModel.CreateBaseViewModelName()));
357 | baseClass.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
358 | }
359 | else
360 | {
361 | baseClass.Add(this.AddBaseViewModel());
362 |
363 | if (baseClass.Count > 0)
364 | {
365 | baseClass.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
366 | }
367 | }
368 |
369 | // Add the interface that will be associated with it
370 | baseClass.Add(this.BuildBaseClass(viewModel.Namespace, viewModel.CreateInterfaceViewModelName()));
371 |
372 | this.ClassDeclaration = this.ClassDeclaration.WithBaseList(this.CreateBaseClass(baseClass));
373 | }
374 |
375 | private void AddBaseInterface(ViewModel viewModel)
376 | {
377 | var baseClass = new List();
378 |
379 | if (viewModel.HasBase)
380 | {
381 | baseClass.Add(this.BuildBaseClass(viewModel.Namespace, viewModel.CreateInterfaceBaseViewModelName()));
382 | }
383 | else
384 | {
385 | baseClass.Add(this.BuildBaseClass("System.ComponentModel", "INotifyPropertyChanged"));
386 | }
387 |
388 | this.InterfaceDeclaration = this.InterfaceDeclaration.WithBaseList(this.CreateBaseClass(baseClass));
389 | }
390 |
391 | private PropertyDeclarationSyntax CreatePublicProperty(string type, string name) =>
392 | SyntaxFactory.PropertyDeclaration(SyntaxFactory.IdentifierName(type), SyntaxFactory.Identifier(name))
393 | .WithAccessorList(SyntaxFactory.AccessorList(
394 | SyntaxFactory.SingletonList(SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
395 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)))));
396 |
397 | private VariableDeclarationSyntax CreatePrivateVariable(string type, string name) =>
398 | SyntaxFactory.VariableDeclaration(SyntaxFactory.ParseTypeName(type)).AddVariables(SyntaxFactory.VariableDeclarator(name.ToCamelCase()));
399 |
400 | private BaseListSyntax CreateBaseClass(List baseClasses) =>
401 | SyntaxFactory.BaseList(SyntaxFactory.SeparatedList(baseClasses));
402 |
403 | private PropertyDeclarationSyntax CreateCommandProperty(Command command)
404 | {
405 | var name = command.FormatCommandName();
406 | var type = this.GetCommandType(command);
407 |
408 | return SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(typeof(System.Windows.Input.ICommand).ToString()), name)
409 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
410 | .AddAccessorListAccessors(
411 | SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
412 | .WithExpressionBody(
413 | SyntaxFactory.ArrowExpressionClause(
414 | SyntaxFactory.BinaryExpression(
415 | SyntaxKind.CoalesceExpression,
416 | SyntaxFactory.MemberAccessExpression(
417 | SyntaxKind.SimpleMemberAccessExpression,
418 | SyntaxFactory.ThisExpression(),
419 | SyntaxFactory.IdentifierName(name.ToCamelCase())),
420 | SyntaxFactory.ParenthesizedExpression(
421 | SyntaxFactory.AssignmentExpression(
422 | SyntaxKind.SimpleAssignmentExpression,
423 | SyntaxFactory.MemberAccessExpression(
424 | SyntaxKind.SimpleMemberAccessExpression,
425 | SyntaxFactory.ThisExpression(),
426 | SyntaxFactory.IdentifierName(name.ToCamelCase())),
427 | SyntaxFactory.ObjectCreationExpression(SyntaxFactory.IdentifierName(type))
428 | .WithArgumentList(this.GetCommandMethodSyntax(command)))))))
429 | .WithSemicolonToken(SyntaxFactory.Token(
430 | SyntaxFactory.TriviaList(),
431 | SyntaxKind.SemicolonToken,
432 | SyntaxFactory.TriviaList(SyntaxFactory.Comment(this.GenerateCommandComment(command))))))
433 | .WithModifiers(FormatterHelper.GenerateComment(command.Comment));
434 | }
435 |
436 | private string GetCommandType(Command command)
437 | {
438 | var type = command.IsAsync ? this.GetAsyncCommandNamespace() : this.GetCommandNamespace();
439 | return command.HasParameterType ? $"{type}<{command.ParameterType}>" : type;
440 | }
441 |
442 | private void GenerateTarget(List viewModels, out string generatedTargetFilename)
443 | {
444 | var xml = new XElement("Project");
445 |
446 | xml.Add(new XComment("This file has been generated with MvvmCodeGenerator, do not modify it."));
447 |
448 | var group = new XElement("ItemGroup");
449 |
450 | foreach (var viewModel in viewModels)
451 | {
452 | var name = viewModel.CreateViewModelName();
453 | var vmFolder = viewModel.DestinationFolder;
454 |
455 | var compile = new XElement("Compile");
456 |
457 | if (string.IsNullOrEmpty(vmFolder))
458 | {
459 | compile.Add(new XAttribute("Update", $"{name}.*.g.cs"));
460 | }
461 | else
462 | {
463 | compile.Add(new XAttribute("Update", string.Concat(Path.Combine(vmFolder, name), ".*.g.cs")));
464 | }
465 |
466 | var dependentUpon = new XElement("DependentUpon");
467 | dependentUpon.Add(new XText($"{name}.cs"));
468 | compile.Add(dependentUpon);
469 |
470 | group.Add(compile);
471 | }
472 |
473 | xml.Add(group);
474 |
475 | FileHelper.SaveFileContent(this.Arguments.OutputFolderProject, string.Empty, xml, Constants.GeneratedTargetFileWithoutExtension, Constants.GeneratedTargetFileExtension);
476 | generatedTargetFilename = string.Concat(Constants.GeneratedTargetFileWithoutExtension, Constants.GeneratedTargetFileExtension);
477 | }
478 |
479 | ///
480 | /// Inject the import of the generated project into the original project, if necessary.
481 | ///
482 | /// The name of the project to import.
483 | private void InjectProject(string generatedTargetFilename)
484 | {
485 | LogMessage($@"Generated target filename: ""{generatedTargetFilename}""");
486 | if (!string.IsNullOrEmpty(generatedTargetFilename))
487 | {
488 | XmlDocument document = new XmlDocument();
489 | var projectPath = Arguments.ProjectPath;
490 | document.Load(projectPath);
491 | var node = document.SelectSingleNode($"/Project/Import[@Project='{generatedTargetFilename}']");
492 |
493 | LogMessage($"The generated project {(node == null ? "has not" : "has already")} been imported in the original project");
494 | if (node == null)
495 | {
496 | node = document.CreateElement("Import");
497 | var attribute = document.CreateAttribute("Project");
498 | attribute.Value = generatedTargetFilename;
499 | node.Attributes.Append(attribute);
500 | document.SelectSingleNode("/Project").AppendChild(node);
501 |
502 | XmlWriterSettings settings = new XmlWriterSettings
503 | {
504 | CheckCharacters = true,
505 | CloseOutput = true,
506 | Encoding = new UTF8Encoding(false),
507 | Indent = true,
508 | IndentChars = " ",
509 | NewLineChars = "\r\n",
510 | NewLineHandling = NewLineHandling.None,
511 | NewLineOnAttributes = false,
512 | OmitXmlDeclaration = true
513 | };
514 | using (var stream = new FileStream(projectPath, FileMode.Create, FileAccess.Write, FileShare.None))
515 | {
516 | var xmlWriter = XmlWriter.Create(stream, settings);
517 | using (xmlWriter)
518 | {
519 | LogMessage("Overwrite the original project");
520 | document.WriteContentTo(xmlWriter);
521 | xmlWriter.Flush();
522 | }
523 | }
524 | }
525 | }
526 | }
527 | }
528 | }
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generation/IGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | ///
4 | /// Interface for all code generators.
5 | ///
6 | public interface IGenerator
7 | {
8 | ///
9 | /// Generate the code.
10 | ///
11 | void Generate();
12 |
13 | ///
14 | /// Clean all previous generated files.
15 | ///
16 | void CleanGeneratedFiles();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generators/FreshMvvmGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 |
8 | ///
9 | /// FreshMvvm library CSharp generator.
10 | ///
11 | public class FreshMvvmGenerator : CSharpGenerator
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// List of ViewModels to generate.
17 | /// The build arguments.
18 | public FreshMvvmGenerator(List viewModels, Arguments arguments) : base(viewModels, arguments)
19 | {
20 | this.IsRunningPropertyForCommandNeeded = true;
21 | }
22 |
23 | ///
24 | /// Creates the namespace that add specific using for FreshMvvmGenerator.
25 | ///
26 | /// The namespace of the class.
27 | protected override void CreateNamespace(string @namespace)
28 | {
29 | base.CreateNamespace(@namespace);
30 |
31 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("FreshMvvm")));
32 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("Xamarin.Forms")));
33 | }
34 |
35 | ///
36 | /// Gets the command namespace for FreshMvvm.
37 | ///
38 | /// The command namespace.
39 | protected override string GetAsyncCommandNamespace() => "Xamarin.Forms.Command";
40 |
41 | ///
42 | /// Gets the command namespace for FreshMvvm.
43 | ///
44 | /// The command namespace.
45 | protected override string GetCommandNamespace() => "Xamarin.Forms.Command";
46 |
47 | ///
48 | /// Add base ViewModel if it is required by the framework.
49 | ///
50 | /// SyntaxNodeOrToken with the ViewModel base.
51 | protected override SyntaxNodeOrToken AddBaseViewModel()
52 | {
53 | return this.BuildBaseClass("FreshMvvm", "FreshBasePageModel");
54 | }
55 |
56 | ///
57 | /// Creates the public properties for each Mvvm library.
58 | ///
59 | /// The public properties.
60 | /// The property to generate.
61 | public override PropertyDeclarationSyntax CreatePublicProperties(Property property)
62 | {
63 | return SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(property.Type.FindType()), property.Name)
64 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
65 | .AddAccessorListAccessors(
66 | SyntaxFactory.AccessorDeclaration(
67 | SyntaxKind.GetAccessorDeclaration)
68 | .WithExpressionBody(
69 | SyntaxFactory.ArrowExpressionClause(
70 | SyntaxFactory.MemberAccessExpression(
71 | SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(property.Name.ToCamelCase()))))
72 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
73 | SyntaxFactory.AccessorDeclaration(
74 | SyntaxKind.SetAccessorDeclaration)
75 | .WithBody(
76 | SyntaxFactory.Block(
77 | SyntaxFactory.ExpressionStatement(
78 | SyntaxFactory.AssignmentExpression(
79 | SyntaxKind.SimpleAssignmentExpression,
80 | SyntaxFactory.IdentifierName(property.Name.ToCamelCase()),
81 | SyntaxFactory.IdentifierName("value"))),
82 | SyntaxFactory.ExpressionStatement(
83 | SyntaxFactory.InvocationExpression(
84 | SyntaxFactory.IdentifierName("RaisePropertyChanged"))))))
85 | .WithModifiers(FormatterHelper.GenerateComment(property.Comment));
86 | }
87 |
88 | ///
89 | /// Get command method syntax, depending on the framework used.
90 | ///
91 | /// The command to generate.
92 | /// The ArgumentListSyntax that represent the command syntax to generate
93 | protected override ArgumentListSyntax GetCommandMethodSyntax(Command command)
94 | {
95 | return CommandHelper.GenerateSafeCommandSyntax(command);
96 | }
97 |
98 | ///
99 | /// Generate command comment to indicate which method associated to the command needs to be implemented.
100 | ///
101 | /// The command.
102 | /// The complete comment to the command.
103 | public override string GenerateCommandComment(Command command)
104 | {
105 | var comment = base.GenerateCommandComment(command);
106 | return CommandHelper.AddCommandExceptionComment(command, comment);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generators/MvvmCrossGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using MvvmCodeGenerator.Gen.Helpers;
8 |
9 | ///
10 | /// MvvmCross library CSharp generator.
11 | ///
12 | public class MvvmCrossGenerator : CSharpGenerator
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// List of ViewModels to generate.
18 | /// The build arguments.
19 | public MvvmCrossGenerator(List viewModels, Arguments arguments) : base(viewModels, arguments)
20 | {
21 | }
22 |
23 | ///
24 | /// Creates the namespace that add specific using for Mvvmicro.
25 | ///
26 | /// The namespace of the class.
27 | protected override void CreateNamespace(string @namespace)
28 | {
29 | base.CreateNamespace(@namespace);
30 |
31 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("MvvmCross.Commands")));
32 | }
33 |
34 | ///
35 | /// Get the entire namespace of the command implementation.
36 | ///
37 | /// The namespace of the command.
38 | protected override string GetCommandNamespace() => "MvvmCross.Commands.MvxCommand";
39 |
40 | ///
41 | /// Get the entire namespace of the async command implementation.
42 | ///
43 | /// The namespace of the async command.
44 | protected override string GetAsyncCommandNamespace() => "MvvmCross.Commands.MvxAsyncCommand";
45 |
46 | ///
47 | /// Add base ViewModel if it is required by the framework.
48 | ///
49 | /// SyntaxNodeOrToken with the ViewModel base.
50 | protected override SyntaxNodeOrToken AddBaseViewModel()
51 | {
52 | return this.BuildBaseClass("MvvmCross.ViewModels", "MvxViewModel");
53 | }
54 |
55 | ///
56 | /// Creates the public properties for each Mvvm library.
57 | ///
58 | /// The public properties.
59 | /// The property to generate.
60 | public override PropertyDeclarationSyntax CreatePublicProperties(Property property)
61 | {
62 | return PropertiesHelper.GeneratePropertiesSyntax(property);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generators/MvvmLightLibsGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 |
8 | ///
9 | /// MvvmLightLibs library CSharp generator.
10 | ///
11 | public class MvvmLightLibsGenerator : CSharpGenerator
12 | {
13 | ///
14 | /// Initializes a new instance of the class.
15 | ///
16 | /// List of ViewModels to generate.
17 | /// The build arguments.
18 | public MvvmLightLibsGenerator(List viewModels, Arguments arguments) : base(viewModels, arguments)
19 | {
20 | this.IsRunningPropertyForCommandNeeded = true;
21 | }
22 |
23 | ///
24 | /// Creates the namespace that add specific using for MvvmLightLibs.
25 | ///
26 | /// The namespace of the class.
27 | protected override void CreateNamespace(string @namespace)
28 | {
29 | base.CreateNamespace(@namespace);
30 |
31 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("GalaSoft.MvvmLight.Command")));
32 | }
33 |
34 | ///
35 | /// Gets the command namespace for MvvmLightLibs.
36 | ///
37 | /// The command namespace.
38 | protected override string GetAsyncCommandNamespace() => "GalaSoft.MvvmLight.Command.RelayCommand";
39 |
40 | ///
41 | /// Gets the command namespace for MvvmLightLibs.
42 | ///
43 | /// The command namespace.
44 | protected override string GetCommandNamespace() => "GalaSoft.MvvmLight.Command.RelayCommand";
45 |
46 | ///
47 | /// Add base ViewModel if it is required by the framework.
48 | ///
49 | /// SyntaxNodeOrToken with the ViewModel base.
50 | protected override SyntaxNodeOrToken AddBaseViewModel()
51 | {
52 | return this.BuildBaseClass("GalaSoft.MvvmLight", "ViewModelBase");
53 | }
54 |
55 | ///
56 | /// Get command method syntax, depending on the framework used.
57 | ///
58 | /// The command to generate.
59 | /// The ArgumentListSyntax that represent the command syntax to generate
60 | protected override ArgumentListSyntax GetCommandMethodSyntax(Command command)
61 | {
62 | return CommandHelper.GenerateSafeCommandSyntax(command);
63 | }
64 |
65 | ///
66 | /// Generate command comment to indicate which method associated to the command needs to be implemented.
67 | ///
68 | /// The command.
69 | /// The complete comment to the command.
70 | public override string GenerateCommandComment(Command command)
71 | {
72 | var comment = base.GenerateCommandComment(command);
73 | return CommandHelper.AddCommandExceptionComment(command, comment);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generators/MvvmicroGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 |
7 | ///
8 | /// Mvvmicro library CSharp generator.
9 | ///
10 | public class MvvmicroCSharpGenerator : CSharpGenerator
11 | {
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// List of ViewModels to generate.
16 | /// The build arguments.
17 | public MvvmicroCSharpGenerator(List viewModels, Arguments arguments) : base(viewModels, arguments)
18 | {
19 | }
20 |
21 | ///
22 | /// Creates the namespace that add specific using for Mvvmicro.
23 | ///
24 | /// The namespace of the class.
25 | protected override void CreateNamespace(string @namespace)
26 | {
27 | base.CreateNamespace(@namespace);
28 |
29 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("Mvvmicro")));
30 | }
31 |
32 | ///
33 | /// Gets the command namespace for Mvvmicro.
34 | ///
35 | /// The command namespace.
36 | protected override string GetCommandNamespace() => "Mvvmicro.RelayCommand";
37 |
38 | ///
39 | /// Gets the async command namespace for Mvvmicro.
40 | ///
41 | /// The async command namespace.
42 | protected override string GetAsyncCommandNamespace() => "Mvvmicro.AsyncRelayCommand";
43 |
44 | ///
45 | /// Add base ViewModel if it is required by the framework.
46 | ///
47 | /// SyntaxNodeOrToken with the ViewModel base.
48 | protected override SyntaxNodeOrToken AddBaseViewModel()
49 | {
50 | return this.BuildBaseClass("Mvvmicro", "ViewModelBase");
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Generators/PrismCoreGenerator.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 | using MvvmCodeGenerator.Gen.Helpers;
8 |
9 | ///
10 | /// Prism library CSharp generator.
11 | ///
12 | public class PrismCoreGenerator : CSharpGenerator
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// List of ViewModels to generate.
18 | /// The build arguments.
19 | public PrismCoreGenerator(List viewModels, Arguments arguments) : base(viewModels, arguments)
20 | {
21 | this.IsRunningPropertyForCommandNeeded = true;
22 | }
23 |
24 | ///
25 | /// Creates the namespace that add specific using for PrismGenerator.
26 | ///
27 | /// The namespace of the class.
28 | protected override void CreateNamespace(string @namespace)
29 | {
30 | base.CreateNamespace(@namespace);
31 |
32 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("Prism.Mvvm")));
33 | this.NamespaceDeclaration = this.NamespaceDeclaration.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("Prism.Commands")));
34 | }
35 |
36 | ///
37 | /// Gets the command namespace for Prism.
38 | ///
39 | /// The command namespace.
40 | protected override string GetAsyncCommandNamespace() => "Prism.Commands.DelegateCommand";
41 |
42 | ///
43 | /// Gets the command namespace for Prism.
44 | ///
45 | /// The command namespace.
46 | protected override string GetCommandNamespace() => "Prism.Commands.DelegateCommand";
47 |
48 | ///
49 | /// Add base ViewModel if it is required by the framework.
50 | ///
51 | /// SyntaxNodeOrToken with the ViewModel base.
52 | protected override SyntaxNodeOrToken AddBaseViewModel()
53 | {
54 | return this.BuildBaseClass("Prism.Mvvm", "BindableBase");
55 | }
56 |
57 | ///
58 | /// Get command method syntax, depending on the framework used.
59 | ///
60 | /// The command to generate.
61 | /// The ArgumentListSyntax that represent the command syntax to generate
62 | protected override ArgumentListSyntax GetCommandMethodSyntax(Command command)
63 | {
64 | return CommandHelper.GenerateSafeCommandSyntax(command);
65 | }
66 |
67 | ///
68 | /// Generate command comment to indicate which method associated to the command needs to be implemented.
69 | ///
70 | /// The command.
71 | /// The complete comment to the command.
72 | public override string GenerateCommandComment(Command command)
73 | {
74 | var comment = base.GenerateCommandComment(command);
75 | return CommandHelper.AddCommandExceptionComment(command, comment);
76 | }
77 |
78 | ///
79 | /// Creates the public properties for each Mvvm library.
80 | ///
81 | /// The public properties.
82 | /// The property to generate.
83 | public override PropertyDeclarationSyntax CreatePublicProperties(Property property)
84 | {
85 | return PropertiesHelper.GeneratePropertiesSyntax(property);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/CommandHelper.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using Microsoft.CodeAnalysis;
5 | using Microsoft.CodeAnalysis.CSharp;
6 | using Microsoft.CodeAnalysis.CSharp.Syntax;
7 |
8 | ///
9 | /// This class help to mutualize some code related to the Commands that are the same for multiple frameworks.
10 | ///
11 | public static class CommandHelper
12 | {
13 | ///
14 | /// Generates the safe command syntax using the try / catch to encapsulate the async commands.
15 | ///
16 | /// The safe command syntax.
17 | /// The command.
18 | public static ArgumentListSyntax GenerateSafeCommandSyntax(Command command)
19 | {
20 | var syntaxeNodeOrToken = new List();
21 |
22 | if (command.IsAsync)
23 | {
24 | var methodExpression = SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(command.FormatExecuteCommandName()));
25 |
26 | if (command.HasParameterType)
27 | {
28 | methodExpression = methodExpression.WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(SyntaxFactory.IdentifierName("value")))));
29 | }
30 |
31 | // Wrap the async void command to a try catch using the SafeFireAndForget extension
32 | var arg = SyntaxFactory.ParenthesizedLambdaExpression(
33 | SyntaxFactory.Block(
34 | SyntaxFactory.SingletonList(
35 | SyntaxFactory.TryStatement(
36 | SyntaxFactory.SingletonList(
37 | SyntaxFactory.CatchClause().WithDeclaration(
38 | SyntaxFactory.CatchDeclaration(SyntaxFactory.IdentifierName("System.Exception")).WithIdentifier(SyntaxFactory.Identifier("ex")))
39 | .WithBlock(SyntaxFactory.Block(
40 | SyntaxFactory.SingletonList(SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(command.FormatCommandExceptionName()))
41 | .WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(SyntaxFactory.IdentifierName("ex")))))))))))
42 | .WithFinally(SyntaxFactory.FinallyClause(SyntaxFactory.Block(
43 | SyntaxFactory.SingletonList(
44 | SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
45 | SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(command.FormatPropertyIsCommandRunning())),
46 | SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression)))))))
47 | .WithBlock(
48 | SyntaxFactory.Block(
49 | SyntaxFactory.ExpressionStatement(
50 | SyntaxFactory.AssignmentExpression(
51 | SyntaxKind.SimpleAssignmentExpression,
52 | SyntaxFactory.MemberAccessExpression(
53 | SyntaxKind.SimpleMemberAccessExpression,
54 | SyntaxFactory.ThisExpression(),
55 | SyntaxFactory.IdentifierName(command.FormatPropertyIsCommandRunning())),
56 | SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression))),
57 | SyntaxFactory.ExpressionStatement(SyntaxFactory.AwaitExpression(methodExpression))
58 | ))))).WithAsyncKeyword(SyntaxFactory.Token(SyntaxKind.AsyncKeyword));
59 |
60 | if (command.HasParameterType)
61 | {
62 | arg = arg.WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Parameter(SyntaxFactory.Identifier("value")))));
63 | }
64 |
65 | syntaxeNodeOrToken.Add(SyntaxFactory.Argument(arg));
66 | }
67 | else
68 | {
69 | syntaxeNodeOrToken.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(command.FormatExecuteCommandName())));
70 | }
71 |
72 | if (command.HasCanExecute)
73 | {
74 | syntaxeNodeOrToken.Add(SyntaxFactory.Token(SyntaxKind.CommaToken));
75 | syntaxeNodeOrToken.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(command.FormatCanExecuteCommandName())));
76 | }
77 |
78 | return SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(syntaxeNodeOrToken));
79 | }
80 |
81 | ///
82 | /// Add the command exception comment.
83 | ///
84 | /// The command exception comment.
85 | /// The command.
86 | /// The command comment to complete.
87 | public static string AddCommandExceptionComment(Command command, string comment)
88 | {
89 | return string.Concat($"{comment} and {command.FormatCommandExceptionName()}");
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | ///
4 | /// Manage all constants common to the project.
5 | ///
6 | public static class Constants
7 | {
8 | ///
9 | /// Constant value for the name, wihtout extension, of the target generated file.
10 | ///
11 | public const string GeneratedTargetFileWithoutExtension = "MvvmCodeGenMapper";
12 |
13 | ///
14 | /// Constant value for the file extension of the target generated file.
15 | ///
16 | public const string GeneratedTargetFileExtension = ".g.targets";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/FileHelper.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Xml.Linq;
7 | using Microsoft.Build.Utilities;
8 |
9 | ///
10 | /// File helper class to manage the generation files.
11 | ///
12 | public static class FileHelper
13 | {
14 | ///
15 | /// Logger defined in the task.
16 | ///
17 | public static TaskLoggingHelper Log { private get; set; }
18 |
19 | ///
20 | /// Clean the specified files dependening on their extensions and their folder path.
21 | ///
22 | /// Folder path.
23 | /// The file extensions.
24 | public static void Clean(string folderPath, string extensions)
25 | {
26 | if (Directory.Exists(folderPath))
27 | {
28 | foreach (var file in Directory.GetFiles(folderPath))
29 | {
30 | if (file.EndsWith(extensions, StringComparison.Ordinal))
31 | {
32 | LogMessage($"Cleaning file: { file}");
33 | File.Delete(file);
34 | }
35 | }
36 |
37 | foreach (var file in Directory.GetDirectories(folderPath))
38 | {
39 | Clean(file, extensions);
40 | }
41 | }
42 | }
43 |
44 | ///
45 | /// Saves the content of the file.
46 | ///
47 | /// Output folder.
48 | /// Destination folder.
49 | /// The file content.
50 | /// The File name.
51 | /// The file extension.
52 | public static void SaveFileContent(string outputFolder,string destinationFolder, string content, string fileName, string fileExtension, bool checkIfExist)
53 | {
54 | var folder = Path.Combine(outputFolder, destinationFolder);
55 |
56 | var path = Path.Combine(folder, string.Concat(fileName, fileExtension));
57 |
58 | if (checkIfExist)
59 | {
60 | if (!File.Exists(path))
61 | {
62 | Save(path, content);
63 | }
64 | }
65 | else
66 | {
67 | Save(path, content);
68 | }
69 | }
70 |
71 | ///
72 | /// Saves the content of the file.
73 | ///
74 | /// Output folder.
75 | /// Destination folder.
76 | /// The xml file content.
77 | /// The File name.
78 | /// The file extension.
79 | public static void SaveFileContent(string outputFolder, string destinationFolder, XElement content, string fileName, string fileExtension)
80 | {
81 | var folder = Path.Combine(outputFolder, destinationFolder);
82 |
83 | var path = Path.Combine(folder, string.Concat(fileName, fileExtension));
84 |
85 | using (var memory = new MemoryStream())
86 | {
87 | content.Save(memory);
88 |
89 | memory.Seek(0, SeekOrigin.Begin);
90 |
91 | using (var reader = new StreamReader(memory))
92 | {
93 | var text = reader.ReadToEnd();
94 | Save(path, text);
95 | }
96 | }
97 | }
98 |
99 | ///
100 | /// Reset the target file generated to re-import all ViewModels.
101 | ///
102 | public static void ResetTarget(string outputFolderProject, string generatedTargetFileWithoutExtension, string generatedTargetFileExtension)
103 | {
104 | var xml = new XElement("Project");
105 |
106 | xml.Add(new XComment("This file has been generated with MvvmCodeGenerator, do not modify it."));
107 |
108 | var group = new XElement("ItemGroup");
109 | xml.Add(group);
110 |
111 | SaveFileContent(outputFolderProject, string.Empty, xml, generatedTargetFileWithoutExtension, generatedTargetFileExtension);
112 | string.Concat(generatedTargetFileWithoutExtension, generatedTargetFileExtension);
113 | }
114 |
115 | ///
116 | /// Writes a message into the default logging system.
117 | ///
118 | /// The message to log.
119 | [Conditional("DEBUG")]
120 | private static void LogMessage(string message)
121 | {
122 | if (!string.IsNullOrEmpty(message))
123 | {
124 | Log?.LogMessage(message);
125 | Console.WriteLine(message);
126 | }
127 | }
128 |
129 | ///
130 | /// Save the specified content into the file path.
131 | ///
132 | /// The path to the file to save data.
133 | /// The content of the class.
134 | private static void Save(string path, string content)
135 | {
136 | if (File.Exists(path))
137 | {
138 | File.Delete(path);
139 | }
140 |
141 | var folder = Path.GetDirectoryName(path);
142 |
143 | if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
144 | {
145 | Directory.CreateDirectory(folder);
146 | }
147 |
148 | File.WriteAllText(path, content);
149 |
150 | LogMessage($"Folder destination {folder}");
151 | LogMessage($"Save file {path}");
152 | LogMessage(content);
153 | }
154 |
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/FormatterHelper.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CSharp;
5 | using Microsoft.CodeAnalysis.CSharp.Syntax;
6 |
7 | ///
8 | /// This class help to format the differents properties or files names.
9 | ///
10 | public static class FormatterHelper
11 | {
12 | ///
13 | /// Transform a property name to camel case.
14 | ///
15 | /// The property name.
16 | /// The property in camel case.
17 | public static string ToCamelCase(this string propertyName)
18 | {
19 | return char.ToLowerInvariant(propertyName[0]) + propertyName.Substring(1);
20 | }
21 |
22 | ///
23 | /// Get ViewModel suffix dependeing if it's an ItemViewModel or a ViewModel.
24 | ///
25 | /// Return if it's an ItemViewModel or a ViewModel.
26 | /// The suffix.
27 | public static string GetSuffix(this bool isItem)
28 | {
29 | return isItem ? "ItemViewModel" : "ViewModel";
30 | }
31 |
32 | ///
33 | /// Creates the name of the ViewModel or ItemViewModel.
34 | ///
35 | /// The ViewModel name correctly formatted.
36 | /// The ViewModel name.
37 | public static string CreateViewModelName(this ViewModel viewModel)
38 | {
39 | return viewModel.Key + viewModel.IsItem.GetSuffix();
40 | }
41 |
42 | ///
43 | /// Creates the name of the interface of the ViewModel or ItemViewModel.
44 | ///
45 | /// The interface of the ViewModel name correctly formatted.
46 | /// The interface ViewModel name.
47 | public static string CreateInterfaceViewModelName(this ViewModel viewModel)
48 | {
49 | return string.Concat("I", CreateViewModelName(viewModel));
50 | }
51 |
52 | ///
53 | /// Creates the name of the base ViewModel or ItemViewModel.
54 | ///
55 | /// The ViewModel.
56 | /// The base ViewModel name
57 | public static string CreateBaseViewModelName(this ViewModel viewModel)
58 | {
59 | return viewModel.Base + viewModel.IsItem.GetSuffix();
60 | }
61 |
62 | ///
63 | /// Creates the name of the base interface ViewModel or ItemViewModel.
64 | ///
65 | /// The interface ViewModel.
66 | /// The base interface ViewModel name
67 | public static string CreateInterfaceBaseViewModelName(this ViewModel viewModel)
68 | {
69 | return string.Concat("I", CreateBaseViewModelName(viewModel));
70 | }
71 |
72 | ///
73 | /// Formats the name of the command.
74 | ///
75 | /// The command name.
76 | /// The command.
77 | public static string FormatCommandName(this Command command) => string.Concat(command.Name, "Command");
78 |
79 | ///
80 | /// Formats the name of the command execute method.
81 | ///
82 | /// The command.
83 | /// The command name formatted for an execute method.
84 | public static string FormatExecuteCommandName(this Command command) => string.Concat("Execute", command.FormatCommandName(), command.IsAsync ? "Async" : string.Empty);
85 |
86 | ///
87 | /// Formats the can execute command method associated to the command.
88 | ///
89 | /// The command.
90 | /// The can execute command method name.
91 | public static string FormatCanExecuteCommandName(this Command command) => "CanExecute" + command.FormatCommandName();
92 |
93 | ///
94 | /// Formats command exception name.
95 | ///
96 | /// The command.
97 | /// The can execute command method name.
98 | public static string FormatCommandExceptionName(this Command command) => string.Concat("OnExecute", command.FormatCommandName(), "AsyncError");
99 |
100 | ///
101 | /// Formats the name of the property when the command is running.
102 | ///
103 | /// The property name when the command is running.
104 | /// The command.
105 | public static string FormatPropertyIsCommandRunning(this Command command) => string.Concat("Is", command.FormatCommandName(), "Running");
106 |
107 | ///
108 | /// Generate warning message on top of all the files.
109 | ///
110 | /// The generated warning comment.
111 | /// Namespace declaration.
112 | public static NamespaceDeclarationSyntax AutoGeneratedCommand(this NamespaceDeclarationSyntax namespaceDeclaration)
113 | {
114 | return namespaceDeclaration.WithNamespaceKeyword(
115 | SyntaxFactory.Token(
116 | SyntaxFactory.TriviaList(
117 | new[]{
118 | SyntaxFactory.Comment("//------------------------------------------------------------------------------ "),
119 | SyntaxFactory.Comment("// "),
120 | SyntaxFactory.Comment("// This code was generated by MvvmCodeGenerator."),
121 | SyntaxFactory.Comment($"// Runtime Version:{System.Environment.Version}"),
122 | SyntaxFactory.Comment("// "),
123 | SyntaxFactory.Comment("// Changes to this file may cause incorrect behavior and will be lost if"),
124 | SyntaxFactory.Comment("// the code is regenerated."),
125 | SyntaxFactory.Comment("// "),
126 | SyntaxFactory.Comment("//------------------------------------------------------------------------------")
127 | }),
128 | SyntaxKind.NamespaceKeyword,
129 | SyntaxTriviaList.Empty));
130 | }
131 |
132 | ///
133 | /// Generates the comment from the description inside the MvvmCodeGenMapper.xml.
134 | ///
135 | /// The SyntaxTokenList that represent the comment that will be generated.
136 | /// The comment to generate.
137 | public static SyntaxTokenList GenerateComment(string comment)
138 | {
139 | return SyntaxFactory.TokenList(
140 | SyntaxFactory.Token(
141 | SyntaxFactory.TriviaList(
142 | new[]{
143 | SyntaxFactory.Comment("/// "),
144 | SyntaxFactory.Comment(string.Concat("// ", comment)),
145 | SyntaxFactory.Comment("/// ")
146 | }),
147 | SyntaxKind.PublicKeyword,
148 | SyntaxTriviaList.Empty));
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/PropertiesHelper.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen.Helpers
2 | {
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CSharp;
5 | using Microsoft.CodeAnalysis.CSharp.Syntax;
6 |
7 | ///
8 | /// This class help to mutualize some code related to the Properties that are the same for multiple frameworks.
9 | ///
10 | public static class PropertiesHelper
11 | {
12 | ///
13 | /// Creates the public properties for each Mvvm library.
14 | ///
15 | /// The public properties.
16 | /// The property to generate.
17 | public static PropertyDeclarationSyntax GeneratePropertiesSyntax(Property property)
18 | {
19 | return SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(property.Type.FindType()), property.Name)
20 | .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword))
21 | .AddAccessorListAccessors(
22 | SyntaxFactory.AccessorDeclaration(
23 | SyntaxKind.GetAccessorDeclaration)
24 | .WithExpressionBody(
25 | SyntaxFactory.ArrowExpressionClause(
26 | SyntaxFactory.MemberAccessExpression(
27 | SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(property.Name.ToCamelCase()))))
28 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
29 | SyntaxFactory.AccessorDeclaration(
30 | SyntaxKind.SetAccessorDeclaration)
31 | .WithExpressionBody(
32 | SyntaxFactory.ArrowExpressionClause(
33 | SyntaxFactory.InvocationExpression(
34 | SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName("SetProperty")))
35 | .WithArgumentList(SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(
36 | new SyntaxNodeOrToken[]
37 | {
38 | SyntaxFactory.Argument(SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ThisExpression(), SyntaxFactory.IdentifierName(property.Name.ToCamelCase())))
39 | .WithRefKindKeyword(SyntaxFactory.Token(SyntaxKind.RefKeyword)), SyntaxFactory.Token(SyntaxKind.CommaToken), SyntaxFactory.Argument(SyntaxFactory.IdentifierName("value"))
40 | })))))
41 | .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)))
42 | .WithModifiers(FormatterHelper.GenerateComment(property.Comment));
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Helpers/TypeExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System;
4 |
5 | ///
6 | /// Manage the Type of the different class and properties.
7 | ///
8 | public static class TypeExtensions
9 | {
10 | ///
11 | /// Finds the type of the object defined in the MvvmCodeGenMapper.xml file as a string.
12 | ///
13 | /// The complete namespace with the type of the object for example : System.Boolean.
14 | /// The type name.
15 | public static string FindType(this string name)
16 | {
17 | switch (name)
18 | {
19 | case "string":
20 | return typeof(string).ToString();
21 | case "int":
22 | return typeof(int).ToString();
23 | case "long":
24 | return typeof(long).ToString();
25 | case "bool":
26 | return typeof(bool).ToString();
27 | case "float":
28 | return typeof(float).ToString();
29 | case "object":
30 | return typeof(object).ToString();
31 | case "double":
32 | return typeof(double).ToString();
33 | case "DateTime":
34 | return typeof(DateTime).ToString();
35 | case "DateTimeOffset":
36 | return typeof(DateTimeOffset).ToString();
37 | case "TimeSpan":
38 | return typeof(TimeSpan).ToString();
39 | case var list when name.StartsWith("list ", StringComparison.InvariantCulture):
40 | var paramType = FindType(list.Substring("list ".Length).Trim());
41 | return $"System.Collections.Generic.IList<{paramType}>";
42 | default:
43 | return name;
44 | }
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/MvvmCodeGenerator.Gen.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | PreserveNewest
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/MvvmCodeGenerator.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | <_CleanTaskRequired>true
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/MvvmCodeGeneratorBaseTask.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System;
4 | using System.IO;
5 | using Microsoft.Build.Framework;
6 | using Microsoft.Build.Utilities;
7 |
8 | public abstract class MvvmCodeGeneratorBaseTask : Task
9 | {
10 | #region Properties
11 |
12 | [Required]
13 | public string ProjectPath { get; set; }
14 |
15 | [Required]
16 | public ITaskItem SourceFile { get; set; }
17 |
18 | #endregion
19 |
20 | public override sealed bool Execute()
21 | {
22 | if (!File.Exists(this.SourceFile.ItemSpec))
23 | {
24 | Log.LogError(null, null, null, SourceFile.ItemSpec, 0, 0, 0, 0, $"file {this.SourceFile} not found");
25 | return false;
26 | }
27 |
28 | try
29 | {
30 | return OnExecute();
31 | }
32 | catch (Exception e)
33 | {
34 | Log.LogMessage("Error: {0}", e.Message);
35 | Log.LogError(null, null, null, SourceFile.ItemSpec, 0, 0, 0, 0, $"{e.Message}");
36 | return false;
37 | }
38 | }
39 |
40 | ///
41 | /// Specific work done by each concrete task.
42 | ///
43 | /// true if the task is successful; false otherwise.
44 | protected abstract bool OnExecute();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/MvvmCodeGeneratorCleanTask.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.IO;
4 |
5 | public class MvvmCodeGeneratorCleanTask : MvvmCodeGeneratorBaseTask
6 | {
7 | protected override bool OnExecute()
8 | {
9 | var projectFolder = Path.GetDirectoryName(this.ProjectPath);
10 |
11 | FileHelper.Log = Log;
12 | FileHelper.ResetTarget(projectFolder, Constants.GeneratedTargetFileWithoutExtension, Constants.GeneratedTargetFileExtension);
13 | FileHelper.Clean(projectFolder, "interface.g.cs");
14 | FileHelper.Clean(projectFolder, "part.g.cs");
15 |
16 | return true;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/MvvmCodeGeneratorTask.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.IO;
4 | using System.Xml;
5 |
6 | public class MvvmCodeGeneratorTask : MvvmCodeGeneratorBaseTask
7 | {
8 | protected override bool OnExecute()
9 | {
10 | try
11 | {
12 | Log.LogMessage($"Loading xml : {this.SourceFile.ItemSpec}");
13 |
14 | var projectFolder = Path.GetDirectoryName(this.ProjectPath);
15 | var path = Path.Combine(projectFolder, this.SourceFile.ItemSpec);
16 |
17 | Log.LogMessage($"ProjectFolder: {projectFolder}");
18 | Log.LogMessage($"Path : {path}");
19 |
20 | Arguments arguments = new Arguments
21 | {
22 | ProjectPath = ProjectPath,
23 | OutputFolderProject = projectFolder
24 | };
25 |
26 | Bootstrap.Start(path, arguments, Log);
27 |
28 | Log.LogMessage("End of generation.");
29 |
30 | return true;
31 | }
32 | catch (XmlException xe)
33 | {
34 | Log.LogMessage("Error (xml): {0}", xe.Message);
35 | Log.LogError(null, null, null, SourceFile.ItemSpec, xe.LineNumber, xe.LinePosition, 0, 0, $"{xe.Message}");
36 |
37 | return false;
38 | }
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Parsing/XmlParser.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Xml;
6 |
7 | ///
8 | /// The Xml parser to get C# objects.
9 | ///
10 | public class XmlParser
11 | {
12 | public ResourceFile ReadResourceFile(string content)
13 | {
14 | XmlDocument xml = new XmlDocument();
15 | xml.LoadXml(content);
16 |
17 | XmlNodeList generatorNode = xml.GetElementsByTagName("Generator");
18 | var generator = generatorNode[0].Attributes["Value"]?.Value;
19 |
20 | var viewModels = new List();
21 |
22 | XmlNodeList allViewModelsTag = xml.GetElementsByTagName("ViewModels");
23 |
24 | foreach (XmlElement viewModelTag in allViewModelsTag)
25 | {
26 | var @namespace = viewModelTag.Attributes["Namespace"]?.Value;
27 | var destinationFolder = viewModelTag.Attributes["DestinationFolder"]?.Value ?? string.Empty;
28 | viewModels.AddRange(this.GetViewModels(viewModelTag, @namespace, destinationFolder));
29 | }
30 |
31 |
32 | return new ResourceFile
33 | {
34 | Generator = generator,
35 | ViewModels = viewModels
36 | };
37 | }
38 |
39 | ///
40 | /// Parse the xml to a list of ViewModels.
41 | ///
42 | /// The xml resource file.
43 | /// The destination namespace.
44 | /// The destination folder for the generated files.
45 | /// The list of ViewModels parsed.
46 | private List GetViewModels(XmlElement xml, string @namespace, string destinationFolder)
47 | {
48 | var viewModels = new List();
49 |
50 | var viewModelsTag = xml.GetElementsByTagName("ViewModel");
51 | var itemViewModelsTag = xml.GetElementsByTagName("ItemViewModel");
52 | var allViewModelsTag = viewModelsTag.Cast().Concat(itemViewModelsTag.Cast()).ToList();
53 |
54 | foreach (XmlNode node in allViewModelsTag)
55 | {
56 | var isItemViewModel = node.Name == "ItemViewModel";
57 | var key = node.Attributes["Key"]?.Value;
58 | var baseViewModel = node.Attributes["Base"]?.Value;
59 |
60 | var viewModel = new ViewModel(isItemViewModel, key, baseViewModel, @namespace, destinationFolder);
61 |
62 | if (node.HasChildNodes)
63 | {
64 | foreach (XmlNode child in node.ChildNodes.Cast().Where(n => n.NodeType == XmlNodeType.Element))
65 | {
66 | var name = child.Attributes["Name"]?.Value;
67 | var comment = child.Attributes["Description"]?.Value;
68 |
69 | if (child.Name == "Property")
70 | {
71 | var parameterType = child.Attributes["Type"]?.Value;
72 | viewModel.Properties.Add(new Property(name, parameterType, comment, true, true));
73 | }
74 | else if (child.Name.Contains("Command"))
75 | {
76 | var isAsync = child.Name.Split(new[] { "Command" }, System.StringSplitOptions.None)[0] == "Async";
77 | var canExecute = child.Attributes["CanExecute"]?.Value.ToLower() == "true";
78 | var parameterType = child.Attributes["Parameter"]?.Value;
79 | viewModel.Commands.Add(new Command(isAsync, name, parameterType, comment, canExecute));
80 | }
81 | }
82 | }
83 |
84 | viewModels.Add(viewModel);
85 | }
86 |
87 | return viewModels;
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Resources/Arguments.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | ///
4 | /// This class represent all the build arguments needed to generate the code.
5 | ///
6 | public class Arguments
7 | {
8 | ///
9 | /// Gets or sets the path to the project file.
10 | ///
11 | /// The path to the project file.
12 | public string ProjectPath { get; set; }
13 |
14 | ///
15 | /// Gets or sets the output folder project to generate the class.
16 | ///
17 | /// The output folder project.
18 | public string OutputFolderProject { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Resources/Command.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | ///
4 | /// This class represent the commands define in the Resource.xml files.
5 | ///
6 | public class Command
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | /// If set to true is async.
12 | /// The name of the Command.
13 | /// The type of parameter to pass to it.
14 | /// The comment associated to this command.
15 | /// If set to true can execute.
16 | public Command(bool isAsync, string name, string parameterType, string comment, bool canExecute)
17 | {
18 | this.IsAsync = isAsync;
19 | this.Name = name;
20 | this.ParameterType = parameterType;
21 | this.Comment = comment;
22 | this.HasCanExecute = canExecute;
23 | }
24 |
25 | ///
26 | /// Gets the type of the parameter.
27 | ///
28 | /// The type of the parameter.
29 | public string ParameterType { get; }
30 |
31 | ///
32 | /// Gets a value indicating whether this has parameter type.
33 | ///
34 | /// true if has parameter type; otherwise, false.
35 | public bool HasParameterType => !string.IsNullOrEmpty(this.ParameterType);
36 |
37 | ///
38 | /// Gets the name.
39 | ///
40 | /// The name.
41 | public string Name { get; }
42 |
43 | ///
44 | /// Gets a value indicating whether this is async.
45 | ///
46 | /// true if is async; otherwise, false.
47 | public bool IsAsync { get; }
48 |
49 | ///
50 | /// Gets the comment.
51 | ///
52 | /// The comment.
53 | public string Comment { get; }
54 |
55 | ///
56 | /// Gets a value indicating whether this has can execute.
57 | ///
58 | /// true if has can execute; otherwise, false.
59 | public bool HasCanExecute { get; }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Resources/Property.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | ///
4 | /// This class represent the properties define in the Resource.xml files for the ViewModels.
5 | ///
6 | public class Property
7 | {
8 | ///
9 | /// Initializes a new instance of the class.
10 | ///
11 | /// The name of the property.
12 | /// The type of the property.
13 | /// The comment associated with it.
14 | /// If set to true has get.
15 | /// If set to true has set.
16 | public Property(string name, string type, string comment, bool hasGet, bool hasSet)
17 | {
18 | this.Name = name;
19 | this.Type = type;
20 | this.Comment = comment;
21 | this.HasGet = hasGet;
22 | this.HasSet = hasSet;
23 | }
24 |
25 | ///
26 | /// Gets the name.
27 | ///
28 | /// The name.
29 | public string Name { get; }
30 |
31 | ///
32 | /// Gets the type.
33 | ///
34 | /// The type.
35 | public string Type { get; }
36 |
37 | ///
38 | /// Gets the comment.
39 | ///
40 | /// The comment.
41 | public string Comment { get; }
42 |
43 | ///
44 | /// Gets a value indicating whether this has get.
45 | ///
46 | /// true if has get; otherwise, false.
47 | public bool HasGet { get; }
48 |
49 | ///
50 | /// Gets a value indicating whether this has set.
51 | ///
52 | /// true if has set; otherwise, false.
53 | public bool HasSet { get; }
54 | }
55 | }
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Resources/ResourceFile.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// The model that represent the ResourceFile.
7 | ///
8 | public class ResourceFile
9 | {
10 | ///
11 | /// Generator needed.
12 | ///
13 | public string Generator { get; set; }
14 |
15 | ///
16 | /// The list of ViewModels to generate.
17 | ///
18 | public List ViewModels { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Resources/ViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace MvvmCodeGenerator.Gen
2 | {
3 | using System.Collections.Generic;
4 |
5 | ///
6 | /// This class represent the ViewModel defined in the MvvmCodeGenMapper.xml
7 | ///
8 | public class ViewModel
9 | {
10 | ///
11 | /// Initializes a new instance of the class.
12 | ///
13 | /// If set to true this is an ItemViewModel.
14 | /// The Key correspond to the prefix of the ViewModel.
15 | /// The Base ViewModel if it exist.
16 | /// The namespace of the ViewModel.
17 | /// The Destination folder for the ViewModel.
18 | public ViewModel(bool isItem, string key, string baseViewModel, string @namespace, string destinationFolder)
19 | {
20 | this.Namespace = @namespace;
21 | this.Key = key;
22 | this.Base = baseViewModel;
23 | this.DestinationFolder = destinationFolder;
24 | this.IsItem = isItem;
25 | }
26 |
27 | ///
28 | /// Gets the namespace.
29 | ///
30 | /// The namespace.
31 | public string Namespace { get; }
32 |
33 | ///
34 | /// Gets the key.
35 | ///
36 | /// The key.
37 | public string Key { get; }
38 |
39 | ///
40 | /// Gets the base.
41 | ///
42 | /// The base.
43 | public string Base { get; }
44 |
45 | ///
46 | /// Gets the destination folder.
47 | ///
48 | /// The destination folder.
49 | public string DestinationFolder { get; }
50 |
51 | ///
52 | /// Gets a value indicating whether this has base.
53 | ///
54 | /// true if has base; otherwise, false.
55 | public bool HasBase => !string.IsNullOrEmpty(this.Base);
56 |
57 | ///
58 | /// Gets a value indicating whether this is item.
59 | ///
60 | /// true if is item; otherwise, false.
61 | public bool IsItem { get; }
62 |
63 | ///
64 | /// Gets the properties.
65 | ///
66 | /// The properties.
67 | public List Properties { get; } = new List();
68 |
69 | ///
70 | /// Gets the commands.
71 | ///
72 | /// The commands.
73 | public List Commands { get; } = new List();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.Gen/Settings.StyleCop:
--------------------------------------------------------------------------------
1 |
2 |
3 | NoMerge
4 | en-US
5 |
6 | Dll
7 |
8 |
9 |
10 |
11 |
12 | False
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | False
22 |
23 |
24 |
25 |
26 | False
27 |
28 |
29 |
30 |
31 | https://github.com/damienaicheh/MvvmCodeGenerator
32 | MS-PL
33 | True
34 | True
35 | False
36 |
37 |
38 |
39 |
40 |
41 | as
42 | do
43 | id
44 | if
45 | in
46 | ip
47 | is
48 | mx
49 | my
50 | no
51 | on
52 | to
53 | ui
54 | vs
55 | x
56 | y
57 | z
58 |
59 |
60 |
61 |
62 |
63 | False
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/Sources/MvvmCodeGenerator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvvmCodeGenerator.Gen", "MvvmCodeGenerator.Gen\MvvmCodeGenerator.Gen.csproj", "{291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Sample", "Xamarin.Sample\Xamarin.Sample.csproj", "{9AFF23DF-47D3-4120-87DC-F680877AB278}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvvmCodeGenerator.Dev", "MvvmCodeGenerator.Dev\MvvmCodeGenerator.Dev.csproj", "{57090D7A-D459-44DC-B9FB-7F05F329F8DE}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | Debug|iPhoneSimulator = Debug|iPhoneSimulator
15 | Release|iPhoneSimulator = Release|iPhoneSimulator
16 | Debug|iPhone = Debug|iPhone
17 | Release|iPhone = Release|iPhone
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
25 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
26 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
27 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
28 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
29 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Debug|iPhone.Build.0 = Debug|Any CPU
30 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|iPhone.ActiveCfg = Release|Any CPU
31 | {291A7D13-3FFA-49E8-8DB0-5869A1A8B9C2}.Release|iPhone.Build.0 = Release|Any CPU
32 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
37 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
38 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
39 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
40 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|iPhone.ActiveCfg = Debug|Any CPU
41 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Debug|iPhone.Build.0 = Debug|Any CPU
42 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|iPhone.ActiveCfg = Release|Any CPU
43 | {9AFF23DF-47D3-4120-87DC-F680877AB278}.Release|iPhone.Build.0 = Release|Any CPU
44 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
49 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
50 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
51 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
52 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
53 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Debug|iPhone.Build.0 = Debug|Any CPU
54 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|iPhone.ActiveCfg = Release|Any CPU
55 | {57090D7A-D459-44DC-B9FB-7F05F329F8DE}.Release|iPhone.Build.0 = Release|Any CPU
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/Sources/Xamarin.Sample/Models/House.cs:
--------------------------------------------------------------------------------
1 | namespace Xamarin.Sample.Models
2 | {
3 | public class House
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/Xamarin.Sample/MvvmCodeGenMapper.xml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/Sources/Xamarin.Sample/Xamarin.Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------