├── .gitattributes ├── .gitignore ├── LICENSE ├── OpenWeather.sln ├── OpenWeather ├── App.config ├── Application.xaml ├── Application.xaml.vb ├── Commands │ ├── RelayCommand.vb │ └── RelayCommandAsync.vb ├── Controls │ ├── CurrentWeatherControl.xaml │ └── CurrentWeatherControl.xaml.vb ├── Converters │ ├── TemperatureConverter.vb │ └── WeatherIconConverter.vb ├── MainWindow.xaml ├── MainWindow.xaml.vb ├── Models │ └── WeatherForecast.vb ├── My Project │ ├── AssemblyInfo.vb │ ├── MyExtensions │ │ └── MyWpfExtension.vb │ ├── Resources.Designer.vb │ ├── Resources.resx │ ├── Settings.Designer.vb │ └── Settings.settings ├── OpenWeather.vbproj ├── SampleData │ └── SampleWeatherViewModel.vb ├── Services │ ├── DialogService.vb │ ├── IDialogService.vb │ ├── IWeatherService.vb │ └── OpenWeatherMapService.vb ├── Utils │ ├── LocationNotFoundException.vb │ ├── SelectAllTextBehavior.vb │ ├── UnauthorizedApiAccessException.vb │ ├── ViewModelBase.vb │ └── ViewModelLocator.vb ├── ViewModels │ └── WeatherViewModel.vb ├── WeatherIcons │ ├── atmosphere.png │ ├── broken_clouds_day.png │ ├── broken_clouds_night.png │ ├── clear_day.png │ ├── clear_night.png │ ├── cold.png │ ├── drizzle.png │ ├── extreme.png │ ├── few_clouds_day.png │ ├── few_clouds_night.png │ ├── hail.png │ ├── hot.png │ ├── overcast_clouds.png │ ├── rain.png │ ├── snow.png │ ├── thunderstorm.png │ └── windy.png ├── bin │ └── Debug │ │ ├── MahApps.Metro.xml │ │ ├── Microsoft.Practices.ServiceLocation.xml │ │ ├── Microsoft.Practices.Unity.Configuration.xml │ │ ├── Microsoft.Practices.Unity.RegistrationByConvention.xml │ │ ├── Microsoft.Practices.Unity.xml │ │ ├── OpenWeather.exe.config │ │ ├── OpenWeather.vshost.exe.config │ │ ├── OpenWeather.vshost.exe.manifest │ │ └── OpenWeather.xml ├── obj │ └── Debug │ │ ├── Application.baml │ │ ├── Application.g.i.vb │ │ ├── Application.g.vb │ │ ├── Controls │ │ ├── CurrentWeatherControl.baml │ │ ├── CurrentWeatherControl.g.i.vb │ │ └── CurrentWeatherControl.g.vb │ │ ├── GeneratedInternalTypeHelper.g.i.vb │ │ ├── GeneratedInternalTypeHelper.g.vb │ │ ├── MainWindow.baml │ │ ├── MainWindow.g.i.vb │ │ ├── MainWindow.g.vb │ │ ├── OpenWeather.Resources.resources │ │ ├── OpenWeather.g.resources │ │ ├── OpenWeather.vbproj.FileListAbsolute.txt │ │ ├── OpenWeather.xml │ │ ├── OpenWeather_Content.g.i.vb │ │ ├── OpenWeather_MarkupCompile.i.lref │ │ ├── OpenWeather_MarkupCompile.lref │ │ └── weather-windy.baml └── packages.config ├── OpenWeatherCS ├── App.config ├── App.xaml ├── App.xaml.cs ├── Commands │ ├── RelayCommand.cs │ └── RelayCommandAsync.cs ├── Controls │ ├── CurrentWeatherControl.xaml │ └── CurrentWeatherControl.xaml.cs ├── Converters │ ├── TemperatureConverter.cs │ └── WeatherIconConverter.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Models │ └── WeatherForecast.cs ├── OpenWeatherCS.csproj ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── SampleData │ └── SampleWeatherViewModel.cs ├── Services │ ├── DialogService.cs │ ├── IDialogService.cs │ ├── IWeatherService.cs │ └── OpenWeatherMapService.cs ├── Utils │ ├── LocationNotFoundException.cs │ ├── SelectAllTextBehavior.cs │ ├── UnauthorizedApiAccessException.cs │ ├── ViewModelBase.cs │ └── ViewModelLocator.cs ├── ViewModels │ └── WeatherViewModel.cs ├── WeatherIcons │ ├── atmosphere.png │ ├── broken_clouds_day.png │ ├── broken_clouds_night.png │ ├── clear_day.png │ ├── clear_night.png │ ├── cold.png │ ├── drizzle.png │ ├── extreme.png │ ├── few_clouds_day.png │ ├── few_clouds_night.png │ ├── hail.png │ ├── hot.png │ ├── overcast_clouds.png │ ├── rain.png │ ├── snow.png │ ├── thunderstorm.png │ └── windy.png ├── bin │ └── Debug │ │ ├── MahApps.Metro.xml │ │ ├── Microsoft.Practices.ServiceLocation.xml │ │ ├── Microsoft.Practices.Unity.Configuration.xml │ │ ├── Microsoft.Practices.Unity.RegistrationByConvention.xml │ │ ├── Microsoft.Practices.Unity.xml │ │ ├── OpenWeather.exe.config │ │ ├── OpenWeather.vshost.exe.config │ │ └── OpenWeather.vshost.exe.manifest ├── obj │ └── Debug │ │ ├── App.baml │ │ ├── App.g.cs │ │ ├── App.g.i.cs │ │ ├── Controls │ │ ├── CurrentWeatherControl.baml │ │ ├── CurrentWeatherControl.g.cs │ │ └── CurrentWeatherControl.g.i.cs │ │ ├── GeneratedInternalTypeHelper.g.cs │ │ ├── GeneratedInternalTypeHelper.g.i.cs │ │ ├── MainWindow.baml │ │ ├── MainWindow.g.cs │ │ ├── MainWindow.g.i.cs │ │ ├── OpenWeather.g.resources │ │ ├── OpenWeatherCS.Properties.Resources.resources │ │ ├── OpenWeatherCS.csproj.FileListAbsolute.txt │ │ ├── OpenWeatherCS_Content.g.i.cs │ │ ├── OpenWeatherCS_MarkupCompile.i.lref │ │ ├── OpenWeather_MarkupCompile.i.lref │ │ ├── OpenWeather_MarkupCompile.lref │ │ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs │ │ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs │ │ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs └── packages.config └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | *.* linguist-language=csharp 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Meshack Musundi 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. 22 | -------------------------------------------------------------------------------- /OpenWeather.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "OpenWeather", "OpenWeather\OpenWeather.vbproj", "{23FCCB35-CDEC-4F5F-8B53-C05B2250C380}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenWeatherCS", "OpenWeatherCS\OpenWeatherCS.csproj", "{F236F8E1-E09D-4FFA-8899-AB82E1706E95}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {23FCCB35-CDEC-4F5F-8B53-C05B2250C380}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {23FCCB35-CDEC-4F5F-8B53-C05B2250C380}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {23FCCB35-CDEC-4F5F-8B53-C05B2250C380}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {23FCCB35-CDEC-4F5F-8B53-C05B2250C380}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {F236F8E1-E09D-4FFA-8899-AB82E1706E95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {F236F8E1-E09D-4FFA-8899-AB82E1706E95}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {F236F8E1-E09D-4FFA-8899-AB82E1706E95}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {F236F8E1-E09D-4FFA-8899-AB82E1706E95}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /OpenWeather/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /OpenWeather/Application.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | 36 | 37 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 99 | 101 | 102 | 103 | 104 | 105 | 106 | 109 | 110 | 111 | 112 | 113 | 125 | 126 | 127 | 128 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /OpenWeather/Application.xaml.vb: -------------------------------------------------------------------------------- 1 | Class Application 2 | 3 | ' Application-level events, such as Startup, Exit, and DispatcherUnhandledException 4 | ' can be handled in this file. 5 | 6 | End Class 7 | -------------------------------------------------------------------------------- /OpenWeather/Commands/RelayCommand.vb: -------------------------------------------------------------------------------- 1 | Public Class RelayCommand 2 | Implements ICommand 3 | 4 | Private ReadOnly _execute As Action(Of Object) 5 | Private ReadOnly _canExecute As Predicate(Of Object) 6 | 7 | Public Sub New(ByVal execute As Action(Of Object)) 8 | Me.New(execute, Nothing) 9 | End Sub 10 | 11 | Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object)) 12 | If execute Is Nothing Then Throw New ArgumentNullException("execute") 13 | _execute = execute 14 | _canExecute = canExecute 15 | End Sub 16 | 17 | Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute 18 | Return If(_canExecute Is Nothing, True, _canExecute(parameter)) 19 | End Function 20 | 21 | Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged 22 | AddHandler(value As EventHandler) 23 | AddHandler CommandManager.RequerySuggested, value 24 | End AddHandler 25 | 26 | RemoveHandler(value As EventHandler) 27 | RemoveHandler CommandManager.RequerySuggested, value 28 | End RemoveHandler 29 | 30 | RaiseEvent(sender As Object, e As EventArgs) 31 | End RaiseEvent 32 | End Event 33 | 34 | Public Sub Execute(parameter As Object) Implements ICommand.Execute 35 | _execute(parameter) 36 | End Sub 37 | End Class 38 | 39 | Public Class RelayCommand(Of T) 40 | Implements ICommand 41 | 42 | Private ReadOnly _execute As Action(Of T) 43 | Private ReadOnly _canExecute As Predicate(Of T) 44 | 45 | Public Sub New(ByVal execute As Action(Of T)) 46 | Me.New(execute, Nothing) 47 | End Sub 48 | 49 | Public Sub New(ByVal execute As Action(Of T), ByVal canExecute As Predicate(Of T)) 50 | If execute Is Nothing Then 51 | Throw New ArgumentNullException("execute") 52 | End If 53 | 54 | _execute = execute 55 | _canExecute = canExecute 56 | End Sub 57 | 58 | 59 | Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute 60 | Return If(_canExecute Is Nothing, True, _canExecute(CType(parameter, T))) 61 | End Function 62 | 63 | Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged 64 | AddHandler(ByVal value As EventHandler) 65 | AddHandler CommandManager.RequerySuggested, value 66 | End AddHandler 67 | 68 | RemoveHandler(ByVal value As EventHandler) 69 | RemoveHandler CommandManager.RequerySuggested, value 70 | End RemoveHandler 71 | 72 | RaiseEvent(ByVal sender As Object, ByVal e As EventArgs) 73 | End RaiseEvent 74 | End Event 75 | 76 | Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute 77 | _execute(CType(parameter, T)) 78 | End Sub 79 | End Class -------------------------------------------------------------------------------- /OpenWeather/Commands/RelayCommandAsync.vb: -------------------------------------------------------------------------------- 1 | Public Class RelayCommandAsync 2 | Implements ICommand 3 | 4 | Private ReadOnly _execute As Func(Of Task) 5 | Private ReadOnly _canExecute As Predicate(Of Object) 6 | Private isExecuting As Boolean 7 | 8 | Public Sub New(execute As Func(Of Task)) 9 | Me.New(execute, Nothing) 10 | End Sub 11 | 12 | Public Sub New(execute As Func(Of Task), canExecute As Predicate(Of Object)) 13 | _execute = execute 14 | _canExecute = canExecute 15 | End Sub 16 | 17 | Public Function CanExecute(parameter As Object) As Boolean Implements ICommand.CanExecute 18 | If Not isExecuting AndAlso _canExecute Is Nothing Then Return True 19 | Return Not isExecuting AndAlso _canExecute(parameter) 20 | End Function 21 | 22 | Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged 23 | AddHandler(value As EventHandler) 24 | AddHandler CommandManager.RequerySuggested, value 25 | End AddHandler 26 | 27 | RemoveHandler(value As EventHandler) 28 | RemoveHandler CommandManager.RequerySuggested, value 29 | End RemoveHandler 30 | 31 | RaiseEvent(sender As Object, e As EventArgs) 32 | End RaiseEvent 33 | End Event 34 | 35 | Public Async Sub Execute(parameter As Object) Implements ICommand.Execute 36 | isExecuting = True 37 | Try 38 | Await _execute() 39 | Finally 40 | isExecuting = False 41 | End Try 42 | End Sub 43 | End Class 44 | -------------------------------------------------------------------------------- /OpenWeather/Controls/CurrentWeatherControl.xaml: -------------------------------------------------------------------------------- 1 |  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 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /OpenWeather/Controls/CurrentWeatherControl.xaml.vb: -------------------------------------------------------------------------------- 1 | Public Class CurrentWeatherControl 2 | 3 | End Class -------------------------------------------------------------------------------- /OpenWeather/Converters/TemperatureConverter.vb: -------------------------------------------------------------------------------- 1 | Imports System.Globalization 2 | 3 | Public Class TemperatureConverter 4 | Implements IMultiValueConverter 5 | 6 | Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert 7 | Dim icon = CStr(values(0)) 8 | Dim dayTemperature = CDbl(values(1)) 9 | Dim nightTemperature = CDbl(values(2)) 10 | 11 | If icon Is Nothing Then Return Binding.DoNothing 12 | 13 | If icon.ElementAt(2) = "d" Then Return dayTemperature Else Return nightTemperature 14 | End Function 15 | 16 | Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack 17 | Return Binding.DoNothing 18 | End Function 19 | End Class 20 | -------------------------------------------------------------------------------- /OpenWeather/Converters/WeatherIconConverter.vb: -------------------------------------------------------------------------------- 1 | Imports System.Globalization 2 | 3 | Public Class WeatherIconConverter 4 | Implements IMultiValueConverter 5 | 6 | Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IMultiValueConverter.Convert 7 | Dim id = CInt(values(0)) 8 | Dim iconID = CStr(values(1)) 9 | 10 | If iconID Is Nothing Then Return Binding.DoNothing 11 | 12 | Dim timePeriod = iconID.ElementAt(2) ' This is either d or n (day or night) 13 | Dim pack = "pack://application:,,,/OpenWeather;component/WeatherIcons/" 14 | Dim img = String.Empty 15 | 16 | If id >= 200 AndAlso id < 300 Then 17 | img = "thunderstorm.png" 18 | ElseIf id >= 300 AndAlso id < 500 Then 19 | img = "drizzle.png" 20 | ElseIf id >= 500 AndAlso id < 600 Then 21 | img = "rain.png" 22 | ElseIf id >= 600 AndAlso id < 700 Then 23 | img = "snow.png" 24 | ElseIf id >= 700 AndAlso id < 800 Then 25 | img = "atmosphere.png" 26 | ElseIf id = 800 Then 27 | If timePeriod = "d" Then img = "clear_day.png" Else img = "clear_night.png" 28 | ElseIf id = 801 Then 29 | If timePeriod = "d" Then img = "few_clouds_day.png" Else img = "few_clouds_night.png" 30 | ElseIf id = 802 Or id = 803 Then 31 | If timePeriod = "d" Then img = "broken_clouds_day.png" Else img = "broken_clouds_night.png" 32 | ElseIf id = 804 Then 33 | img = "overcast_clouds.png" 34 | ElseIf id >= 900 AndAlso id < 903 Then 35 | img = "extreme.png" 36 | ElseIf id = 903 Then 37 | img = "cold.png" 38 | ElseIf id = 904 Then 39 | img = "hot.png" 40 | ElseIf id = 905 Or id >= 951 Then 41 | img = "windy.png" 42 | ElseIf id = 906 Then 43 | img = "hail.png" 44 | End If 45 | 46 | Dim source As New Uri(pack & img) 47 | 48 | Dim bmp As New BitmapImage 49 | bmp.BeginInit() 50 | bmp.UriSource = source 51 | bmp.EndInit() 52 | 53 | Return bmp 54 | End Function 55 | 56 | Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack 57 | Return Binding.DoNothing 58 | End Function 59 | End Class 60 | -------------------------------------------------------------------------------- /OpenWeather/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /OpenWeather/MainWindow.xaml.vb: -------------------------------------------------------------------------------- 1 | Class MainWindow 2 | 3 | End Class 4 | -------------------------------------------------------------------------------- /OpenWeather/Models/WeatherForecast.vb: -------------------------------------------------------------------------------- 1 | Public Class WeatherForecast 2 | Public Property Description As String 3 | Public Property ID As Integer 4 | Public Property IconID As String 5 | Public Property [Date] As DateTime 6 | Public Property WindType As String 7 | Public Property WindDirection As String 8 | Public Property WindSpeed As Double 9 | Public Property DayTemperature As Double 10 | Public Property NightTemperature As Double 11 | Public Property MaxTemperature As Double 12 | Public Property MinTemperature As Double 13 | Public Property Pressure As Double 14 | Public Property Humidity As Double 15 | End Class -------------------------------------------------------------------------------- /OpenWeather/My Project/AssemblyInfo.vb: -------------------------------------------------------------------------------- 1 | Imports System 2 | Imports System.Reflection 3 | Imports System.Runtime.InteropServices 4 | Imports System.Globalization 5 | Imports System.Resources 6 | Imports System.Windows 7 | 8 | ' General Information about an assembly is controlled through the following 9 | ' set of attributes. Change these attribute values to modify the information 10 | ' associated with an assembly. 11 | 12 | ' Review the values of the assembly attributes 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 'In order to begin building localizable applications, set 23 | 'CultureYouAreCodingWith in your .vbproj file 24 | 'inside a . For example, if you are using US english 25 | 'in your source files, set the to "en-US". Then uncomment the 26 | 'NeutralResourceLanguage attribute below. Update the "en-US" in the line 27 | 'below to match the UICulture setting in the project file. 28 | 29 | ' 30 | 31 | 32 | 'The ThemeInfo attribute describes where any theme specific and generic resource dictionaries can be found. 33 | '1st parameter: where theme specific resource dictionaries are located 34 | '(used if a resource is not found in the page, 35 | ' or application resource dictionaries) 36 | 37 | '2nd parameter: where the generic resource dictionary is located 38 | '(used if a resource is not found in the page, 39 | 'app, and any theme specific resource dictionaries) 40 | 41 | 42 | 43 | 44 | 'The following GUID is for the ID of the typelib if this project is exposed to COM 45 | 46 | 47 | ' Version information for an assembly consists of the following four values: 48 | ' 49 | ' Major Version 50 | ' Minor Version 51 | ' Build Number 52 | ' Revision 53 | ' 54 | ' You can specify all the values or you can default the Build and Revision Numbers 55 | ' by using the '*' as shown below: 56 | ' 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /OpenWeather/My Project/MyExtensions/MyWpfExtension.vb: -------------------------------------------------------------------------------- 1 | #If _MyType <> "Empty" Then 2 | 3 | Namespace My 4 | ''' 5 | ''' Module used to define the properties that are available in the My Namespace for WPF 6 | ''' 7 | ''' 8 | _ 9 | Module MyWpfExtension 10 | Private s_Computer As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Devices.Computer) 11 | Private s_User As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.ApplicationServices.User) 12 | Private s_Windows As New ThreadSafeObjectProvider(Of MyWindows) 13 | Private s_Log As New ThreadSafeObjectProvider(Of Global.Microsoft.VisualBasic.Logging.Log) 14 | ''' 15 | ''' Returns the application object for the running application 16 | ''' 17 | _ 18 | Friend ReadOnly Property Application() As Application 19 | Get 20 | Return CType(Global.System.Windows.Application.Current, Application) 21 | End Get 22 | End Property 23 | ''' 24 | ''' Returns information about the host computer. 25 | ''' 26 | _ 27 | Friend ReadOnly Property Computer() As Global.Microsoft.VisualBasic.Devices.Computer 28 | Get 29 | Return s_Computer.GetInstance() 30 | End Get 31 | End Property 32 | ''' 33 | ''' Returns information for the current user. If you wish to run the application with the current 34 | ''' Windows user credentials, call My.User.InitializeWithWindowsUser(). 35 | ''' 36 | _ 37 | Friend ReadOnly Property User() As Global.Microsoft.VisualBasic.ApplicationServices.User 38 | Get 39 | Return s_User.GetInstance() 40 | End Get 41 | End Property 42 | ''' 43 | ''' Returns the application log. The listeners can be configured by the application's configuration file. 44 | ''' 45 | _ 46 | Friend ReadOnly Property Log() As Global.Microsoft.VisualBasic.Logging.Log 47 | Get 48 | Return s_Log.GetInstance() 49 | End Get 50 | End Property 51 | 52 | ''' 53 | ''' Returns the collection of Windows defined in the project. 54 | ''' 55 | _ 56 | Friend ReadOnly Property Windows() As MyWindows 57 | _ 58 | Get 59 | Return s_Windows.GetInstance() 60 | End Get 61 | End Property 62 | _ 63 | _ 64 | Friend NotInheritable Class MyWindows 65 | _ 66 | Private Shared Function Create__Instance__(Of T As {New, Global.System.Windows.Window})(ByVal Instance As T) As T 67 | If Instance Is Nothing Then 68 | If s_WindowBeingCreated IsNot Nothing Then 69 | If s_WindowBeingCreated.ContainsKey(GetType(T)) = True Then 70 | Throw New Global.System.InvalidOperationException("The window cannot be accessed via My.Windows from the Window constructor.") 71 | End If 72 | Else 73 | s_WindowBeingCreated = New Global.System.Collections.Hashtable() 74 | End If 75 | s_WindowBeingCreated.Add(GetType(T), Nothing) 76 | Return New T() 77 | s_WindowBeingCreated.Remove(GetType(T)) 78 | Else 79 | Return Instance 80 | End If 81 | End Function 82 | _ 83 | _ 84 | Private Sub Dispose__Instance__(Of T As Global.System.Windows.Window)(ByRef instance As T) 85 | instance = Nothing 86 | End Sub 87 | _ 88 | _ 89 | Public Sub New() 90 | MyBase.New() 91 | End Sub 92 | Private Shared s_WindowBeingCreated As Global.System.Collections.Hashtable 93 | Public Overrides Function Equals(ByVal o As Object) As Boolean 94 | Return MyBase.Equals(o) 95 | End Function 96 | Public Overrides Function GetHashCode() As Integer 97 | Return MyBase.GetHashCode 98 | End Function 99 | _ 100 | _ 101 | Friend Overloads Function [GetType]() As Global.System.Type 102 | Return GetType(MyWindows) 103 | End Function 104 | Public Overrides Function ToString() As String 105 | Return MyBase.ToString 106 | End Function 107 | End Class 108 | End Module 109 | End Namespace 110 | Partial Class Application 111 | Inherits Global.System.Windows.Application 112 | _ 113 | _ 114 | Friend ReadOnly Property Info() As Global.Microsoft.VisualBasic.ApplicationServices.AssemblyInfo 115 | _ 116 | Get 117 | Return New Global.Microsoft.VisualBasic.ApplicationServices.AssemblyInfo(Global.System.Reflection.Assembly.GetExecutingAssembly()) 118 | End Get 119 | End Property 120 | End Class 121 | #End If -------------------------------------------------------------------------------- /OpenWeather/My Project/Resources.Designer.vb: -------------------------------------------------------------------------------- 1 | '------------------------------------------------------------------------------ 2 | ' 3 | ' This code was generated by a tool. 4 | ' Runtime Version:4.0.30319.42000 5 | ' 6 | ' Changes to this file may cause incorrect behavior and will be lost if 7 | ' the code is regenerated. 8 | ' 9 | '------------------------------------------------------------------------------ 10 | 11 | Option Strict On 12 | Option Explicit On 13 | 14 | Imports System 15 | 16 | Namespace My.Resources 17 | 18 | 'This class was auto-generated by the StronglyTypedResourceBuilder 19 | 'class via a tool like ResGen or Visual Studio. 20 | 'To add or remove a member, edit your .ResX file then rerun ResGen 21 | 'with the /str option, or rebuild your VS project. 22 | ''' 23 | ''' A strongly-typed resource class, for looking up localized strings, etc. 24 | ''' 25 | _ 29 | Friend Module Resources 30 | 31 | Private resourceMan As Global.System.Resources.ResourceManager 32 | 33 | Private resourceCulture As Global.System.Globalization.CultureInfo 34 | 35 | ''' 36 | ''' Returns the cached ResourceManager instance used by this class. 37 | ''' 38 | _ 39 | Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager 40 | Get 41 | If Object.ReferenceEquals(resourceMan, Nothing) Then 42 | Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("OpenWeather.Resources", GetType(Resources).Assembly) 43 | resourceMan = temp 44 | End If 45 | Return resourceMan 46 | End Get 47 | End Property 48 | 49 | ''' 50 | ''' Overrides the current thread's CurrentUICulture property for all 51 | ''' resource lookups using this strongly typed resource class. 52 | ''' 53 | _ 54 | Friend Property Culture() As Global.System.Globalization.CultureInfo 55 | Get 56 | Return resourceCulture 57 | End Get 58 | Set 59 | resourceCulture = value 60 | End Set 61 | End Property 62 | End Module 63 | End Namespace 64 | -------------------------------------------------------------------------------- /OpenWeather/My Project/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /OpenWeather/My Project/Settings.Designer.vb: -------------------------------------------------------------------------------- 1 | '------------------------------------------------------------------------------ 2 | ' 3 | ' This code was generated by a tool. 4 | ' Runtime Version:4.0.30319.42000 5 | ' 6 | ' Changes to this file may cause incorrect behavior and will be lost if 7 | ' the code is regenerated. 8 | ' 9 | '------------------------------------------------------------------------------ 10 | 11 | Option Strict On 12 | Option Explicit On 13 | 14 | 15 | 16 | _ 19 | Partial Friend NotInheritable Class MySettings 20 | Inherits Global.System.Configuration.ApplicationSettingsBase 21 | 22 | Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings()),MySettings) 23 | 24 | #Region "My.Settings Auto-Save Functionality" 25 | #If _MyType = "WindowsForms" Then 26 | Private Shared addedHandler As Boolean 27 | 28 | Private Shared addedHandlerLockObject As New Object 29 | 30 | _ 31 | Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs) 32 | If My.Application.SaveMySettingsOnExit Then 33 | My.Settings.Save() 34 | End If 35 | End Sub 36 | #End If 37 | #End Region 38 | 39 | Public Shared ReadOnly Property [Default]() As MySettings 40 | Get 41 | 42 | #If _MyType = "WindowsForms" Then 43 | If Not addedHandler Then 44 | SyncLock addedHandlerLockObject 45 | If Not addedHandler Then 46 | AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings 47 | addedHandler = True 48 | End If 49 | End SyncLock 50 | End If 51 | #End If 52 | Return defaultInstance 53 | End Get 54 | End Property 55 | End Class 56 | 57 | Namespace My 58 | 59 | _ 62 | Friend Module MySettingsProperty 63 | 64 | _ 65 | Friend ReadOnly Property Settings() As Global.OpenWeather.MySettings 66 | Get 67 | Return Global.OpenWeather.MySettings.Default 68 | End Get 69 | End Property 70 | End Module 71 | End Namespace 72 | -------------------------------------------------------------------------------- /OpenWeather/My Project/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /OpenWeather/SampleData/SampleWeatherViewModel.vb: -------------------------------------------------------------------------------- 1 | Public Class SampleWeatherViewModel 2 | Public Property Forecast As List(Of WeatherForecast) 3 | Public Property CurrentWeather As WeatherForecast 4 | 5 | Public Sub New() 6 | CurrentWeather = New WeatherForecast With {.Date = DateTime.Now, .Humidity = 82, .ID = 202, 7 | .MaxTemperature = 34.12, .MinTemperature = 20.45, .Pressure = 843.16, .IconID = "11d", 8 | .DayTemperature = 23.55, .NightTemperature = 18.35, .Description = "thunderstorm with heavy rain ", 9 | .WindDirection = "NE", .WindSpeed = 1.85, .WindType = "Light breeze"} 10 | 11 | Forecast = New List(Of WeatherForecast) 12 | Forecast.Add(New WeatherForecast With {.Date = New DateTime(2017, 8, 3), .Humidity = 82, .ID = 310, 13 | .MaxTemperature = 18.33, .MinTemperature = 12.78, .Pressure = 843.16, .IconID = "09d", 14 | .DayTemperature = 23, .Description = "light intensity drizzle rain", .WindDirection = "NE", 15 | .WindSpeed = 1.85, .WindType = "Light breeze"}) 16 | Forecast.Add(New WeatherForecast With {.Date = New DateTime(2017, 8, 4), .Humidity = 82, .ID = 800, 17 | .MaxTemperature = 34.65, .MinTemperature = 20.32, .Pressure = 843.16, .IconID = "10d", 18 | .DayTemperature = 23, .Description = "clear day", .WindDirection = "NE", 19 | .WindSpeed = 1.85, .WindType = "Light breeze"}) 20 | End Sub 21 | End Class 22 | -------------------------------------------------------------------------------- /OpenWeather/Services/DialogService.vb: -------------------------------------------------------------------------------- 1 | Public Class DialogService 2 | Implements IDialogService 3 | 4 | Public Sub ShowNotification(message As String, Optional caption As String = "") Implements IDialogService.ShowNotification 5 | MessageBox.Show(message, caption) 6 | End Sub 7 | 8 | Public Function ShowConfirmationRequest(message As String, Optional caption As String = "") As Boolean Implements IDialogService.ShowConfirmationRequest 9 | Dim result = MessageBox.Show(message, caption, MessageBoxButton.OKCancel) 10 | Return result.HasFlag(MessageBoxResult.OK) 11 | End Function 12 | End Class 13 | -------------------------------------------------------------------------------- /OpenWeather/Services/IDialogService.vb: -------------------------------------------------------------------------------- 1 | Public Interface IDialogService 2 | Sub ShowNotification(message As String, Optional caption As String = "") 3 | Function ShowConfirmationRequest(message As String, Optional caption As String = "") As Boolean 4 | End Interface 5 | -------------------------------------------------------------------------------- /OpenWeather/Services/IWeatherService.vb: -------------------------------------------------------------------------------- 1 | Public Interface IWeatherService 2 | Function GetForecastAsync(ByVal location As String, ByVal days As Integer) As Task(Of IEnumerable(Of WeatherForecast)) 3 | End Interface 4 | -------------------------------------------------------------------------------- /OpenWeather/Services/OpenWeatherMapService.vb: -------------------------------------------------------------------------------- 1 | Imports System.Net.Http 2 | Imports System.IO 3 | Imports System.Net 4 | 5 | Public Class OpenWeatherMapService 6 | Implements IWeatherService 7 | 8 | Private Const APP_ID As String = "PLACE-YOUR-APP-ID-HERE" 9 | Private Const MAX_FORECAST_DAYS As Integer = 5 10 | Private client As HttpClient 11 | 12 | 13 | Public Sub New() 14 | client = New HttpClient 15 | client.BaseAddress = New Uri("http://api.openweathermap.org/data/2.5/") 16 | End Sub 17 | 18 | Public Async Function GetForecastAsync(location As String, days As Integer) As Task(Of IEnumerable(Of WeatherForecast)) Implements IWeatherService.GetForecastAsync 19 | If location Is Nothing Then Throw New ArgumentNullException("Location can't be null.") 20 | If location = String.Empty Then Throw New ArgumentException("Location can't be an empty string.") 21 | If days <= 0 Then Throw New ArgumentOutOfRangeException("Days should be greater than zero.") 22 | If days > MAX_FORECAST_DAYS Then Throw New ArgumentOutOfRangeException($"Days can't be greater than {MAX_FORECAST_DAYS}.") 23 | 24 | Dim query = $"forecast/daily?q={location}&type=accurate&mode=xml&units=metric&cnt={days}&appid={APP_ID}" 25 | Dim response = Await client.GetAsync(query) 26 | 27 | Select Case response.StatusCode 28 | Case HttpStatusCode.Unauthorized 29 | Throw New UnauthorizedApiAccessException("Invalid API key.") 30 | Case HttpStatusCode.NotFound 31 | Throw New LocationNotFoundException("Location not found.") 32 | Case HttpStatusCode.OK 33 | Dim s = Await response.Content.ReadAsStringAsync() 34 | Dim x = XElement.Load(New StringReader(s)) 35 | Dim data = x...