├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ignore.travis.yml ├── logo.png └── src ├── XamU.Core ├── Collections │ ├── GroupedObservableCollection.cs │ ├── ObservableDictionary.cs │ ├── OptimizedObservableCollection.cs │ └── RefreshingCollection.cs ├── Extensions │ ├── CollectionExtensions.cs │ ├── ExceptionExtensions.cs │ └── TaskExtensions.cs ├── Interfaces │ ├── IAsyncDelegateCommand.cs │ ├── IDelegateCommand.cs │ ├── IDependencyService.cs │ ├── IInitViewModel.cs │ ├── IMessageVisualizerService.cs │ └── INavigationService.cs ├── Mvvm │ ├── AsyncDelegateCommand.cs │ ├── DelegateCommand.cs │ ├── PropertyObserver.cs │ └── SimpleViewModel.cs ├── XamU.Core-old.csproj └── XamU.Core.csproj ├── XamU.Infrastructure.Tests ├── DependencyServiceWrapperTests.cs ├── ObservableDictionaryTests.cs ├── XamU.Infrastructure.Tests.csproj └── XamUInfrastructureTests.cs ├── XamU.Infrastructure.sln └── XamU.Infrastructure ├── Behaviors ├── BindingContextBehavior.cs ├── EffectBehavior.cs ├── EventToCommandBehavior.cs ├── NumericValidationBehavior.cs └── PickerBindBehavior.cs ├── Commands ├── NavigateBackCommand.cs ├── NavigateToCommand.cs └── NavigationCommands.cs ├── Controls └── ItemsControl.cs ├── Converters ├── BooleanToColorConverter.cs ├── BooleanToImageSourceConverter.cs ├── DebugConverter.cs ├── EventArgsConverter.cs ├── ImageResourceConverter.cs ├── IntegerToBooleanConverter.cs ├── NotBooleanConverter.cs ├── NullOrEmptyBooleanConverter.cs └── StreamToImageSourceConverter.cs ├── Extensions ├── ColorExtensions.cs └── ElementExtensions.cs ├── Interfaces └── INavigationPageService.cs ├── Layout └── WrapLayout.cs ├── MarkupExtensions ├── DependencyServiceExtension.cs ├── ImageResourceExtension.cs └── RelativeBindingContext.cs ├── NamedDataTemplateSelector.cs ├── Services ├── DependencyServiceWrapper.cs ├── FormsMessageVisualizerService.cs ├── FormsNavigationPageService.cs └── XamUInfrastructure.cs ├── XamU.Infrastructure-old.csproj └── XamU.Infrastructure.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | *.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.pfx 193 | *.publishsettings 194 | node_modules/ 195 | orleans.codegen.cs 196 | 197 | # Since there are multiple workflows, uncomment next line to ignore bower_components 198 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 199 | #bower_components/ 200 | 201 | # RIA/Silverlight projects 202 | Generated_Code/ 203 | 204 | # Backup & report files from converting an old project file 205 | # to a newer Visual Studio version. Backup files are not needed, 206 | # because we have git ;-) 207 | _UpgradeReport_Files/ 208 | Backup*/ 209 | UpgradeLog*.XML 210 | UpgradeLog*.htm 211 | 212 | # SQL Server files 213 | *.mdf 214 | *.ldf 215 | 216 | # Business Intelligence projects 217 | *.rdl.data 218 | *.bim.layout 219 | *.bim_*.settings 220 | 221 | # Microsoft Fakes 222 | FakesAssemblies/ 223 | 224 | # GhostDoc plugin setting file 225 | *.GhostDoc.xml 226 | 227 | # Node.js Tools for Visual Studio 228 | .ntvs_analysis.dat 229 | 230 | # Visual Studio 6 build log 231 | *.plg 232 | 233 | # Visual Studio 6 workspace options file 234 | *.opt 235 | 236 | # Visual Studio LightSwitch build output 237 | **/*.HTMLClient/GeneratedArtifacts 238 | **/*.DesktopClient/GeneratedArtifacts 239 | **/*.DesktopClient/ModelManifest.xml 240 | **/*.Server/GeneratedArtifacts 241 | **/*.Server/ModelManifest.xml 242 | _Pvt_Extensions 243 | 244 | # Paket dependency manager 245 | .paket/paket.exe 246 | paket-files/ 247 | 248 | # FAKE - F# Make 249 | .fake/ 250 | 251 | # JetBrains Rider 252 | .idea/ 253 | *.sln.iml 254 | 255 | # CodeRush 256 | .cr/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.2.0] 2 | ### Breaking changes 3 | - We had to change the `FormsNavigationPageService` to support re-locating the `NavigationPage` for Android when it relaunches the Activity. Because of that, we cannot support setting the `Navigation` property - if you are using this, it will now throw a `NotSupportedException` and you will need to provide your own implementation of the service. 4 | - The `DependencyServiceExtension` now uses the wrapper - so it can create objects and inject dependencies. This means you do not need to register ViewModel objects. 5 | - Updated the Xamarin.Forms package. 6 | 7 | ## XamU.Core [2.1.1] 8 | - Fix bug in `ObservableDictionary` so it's property raising `PropertyChange` notifications on `Item[key]` to allow Forms to see it. 9 | 10 | ## XamU.Infrastructure [2.1.0] 11 | - Allows `XamUInfrastructure.Init` to be called multiple times for native Android initialization in an Activity. 12 | - Fixed a bug in `ObservableCollection` to ensure it always reports change notifications even when `MassUpdate` is not being used. 13 | - Added unit tests to check new features. 14 | 15 | ## [2.0.0] 16 | ### Breaking changes 17 | - New property on `IntegerToBoolean` which allows for a test of `One` vs. `Zero`. 18 | - The `NavigateAsync` methods on `INavigationService` have been split into multiple methods instead of default parameters. 19 | - There's a new interface `IViewModelNavigationInit` which is used to initialize a ViewModel post-creation. 20 | - `FormsNavigationPageService` supports the new ViewModel initialization support. 21 | - `SimpleViewModel` implements the new `IViewModelNavigationInit` interface and forwards it to a virtual method. 22 | - `SimpleViewModel.RaisePropertyChanged` is now virtual and used to raise all property changes so it can be overridden. 23 | - A new version of `IDependencyService.Get` is available which takes a `DependencyScope` parameter to determine whether a new instance or global instance is returned. 24 | 25 | ## [1.6.0] 26 | ### Breaking changes 27 | - Refined namespaces - might need to change some `using` statements. 28 | - Removed `BindablePicker` as the support is now included in Xamarin.Forms. The source is still in the repo if anyone needs it. 29 | 30 | ### Other changes 31 | - Simplified and cleaned up some code 32 | - Added a few new converters 33 | - Added `WrapLayout` from Xamarin docs 34 | - Added support to `ItemsControl` to replace the panel 35 | 36 | ## [1.5.0] 37 | - Replaced PCL support with .NET Standard 1.0 and 2.0 38 | - Added `Orientation` and `Spacing` properties to `ItemsControl` 39 | - Fixed bug in `ItemsControl` when the `DataTemplate` is applied _after_ the `ItemsSource` 40 | 41 | ## [1.1.0] 42 | - Added support for PCL and .NET Standard 43 | - Added ability to reset navigation stack 44 | 45 | ## [1.0.161128] 46 | - Add class constraint to Register method of IDependencyService 47 | 48 | ## [1.0.161104] 49 | - Unify versions 50 | 51 | ## [1.0.160930] 52 | - Added new `Register` method to `IDependencyService` to allow instance registration. 53 | 54 | ## [1.0.160916] 55 | - Initial release of Core - broken out from **XamU.Infrastructure.dll** with no dependencies on Xamarin.Forms. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Xamarin University Infrastructure 2 | 3 | :+1::tada: Thanks for taking the time to contribute! :tada::+1: 4 | 5 | The following is a set of guidelines for contributing to the Xamarin University public repository on GitHub. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. 6 | 7 | #### Table Of Contents 8 | 9 | [What should I know before I get started?](#what-should-i-know-before-i-get-started) 10 | * [Code of Conduct](#code-of-conduct) 11 | 12 | [How Can I Contribute?](#how-can-i-contribute) 13 | * [Reporting Bugs](#reporting-bugs) 14 | * [Adding Samples](#adding-samples-and-tests) 15 | * [New Functionality](#new-functionality) 16 | 17 | [C# Style Guide](https://msdn.microsoft.com/en-us/library/ff926074.aspx) 18 | 19 | ## What should I know before I get started? 20 | 21 | ### Code of Conduct 22 | 23 | This project adheres to the Contributor Covenant [code of conduct](http://contributor-covenant.org/version/1/4/). By participating, you are expected to uphold this code. Please report unacceptable behavior to [smmark@microsoft.com](mailto:smmark@microsoft.com). 24 | 25 | ## How Can I Contribute? 26 | 27 | ### Reporting Bugs 28 | 29 | This section guides you through submitting a bug report. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer:, and find related reports :mag_right:. 30 | 31 | Before creating bug reports, please check the existing issues to verify that the problem has not been reported already. When you are creating a bug report, please use a clear and descriptive title and include as many details as possible. We recommend the following template: 32 | 33 | ``` 34 | [Short description of problem here] 35 | 36 | ** To reproduce ** 37 | 1. [First Step] 38 | 2. [Second Step] 39 | 3. [Other Steps...] 40 | 41 | **Expected behavior:** 42 | 43 | [Describe expected behavior here] 44 | 45 | **Actual behavior:** 46 | 47 | [Describe observed behavior here] 48 | 49 | **Screenshots** 50 | 51 | [Add any screen shots to show the issue] 52 | 53 | **OS and version:** [Enter OS name and version here] 54 | 55 | **Installed NuGet packages:** 56 | 57 | [List of other NuGet packages you are usinghere] 58 | 59 | **Additional information:** 60 | 61 | [Other things we need to know] 62 | ``` 63 | 64 | ### Adding Samples and Tests 65 | 66 | We welcome samples and unit tests which show off how to use a feature in the library. When submitting a sample, we prefer that: 67 | 68 | - The sample be small and self-contained. 69 | - Show off a specific class or set of related classes. 70 | - Be well commented to explain what is happening. 71 | 72 | You can add samples to the [samples](samples) folder. 73 | 74 | ### New Functionality 75 | 76 | We also welcome new functionality and classes! Make sure to include some documentation for any new classes or functionality added. It's also helpful to submit unit tests or some sort of sample to show off how to use the new feature/functionality. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Xamarin University Infrastructure Library 2 | 3 | The MIT License (MIT) 4 | 5 | Copyright (c) .NET Foundation Contributors 6 | 7 | All rights reserved. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Xamarin University Infrastructure Library 2 | 3 | ![Build Status](https://xamu-labs.visualstudio.com/_apis/public/build/definitions/454c2b9a-92a4-4467-a3ea-f1a914619cf3/3/badge) 4 | 5 | This is a set of useful classes for Xamarin and Xamarin.Forms development which are used in a varity of labs in Xamarin University. 6 | 7 | You can use it in source form by cloning this repository (or just grabbing the pieces you want to use), or as a binary through two NuGet packages: [Core](https://www.nuget.org/packages/XamarinUniversity.Core/) and [Infrastructure](https://www.nuget.org/packages/XamarinUniversity.Infrastructure/) which also adds Core. 8 | 9 | The library includes examples of behaviors, MVVM, custom controls, binding value converters, type extensions, XAML markup extensions and helpful collections for data binding. 10 | 11 | ## Add the NuGet packages to your project 12 | To add the library to your project as an updatable binary, you can use NuGet with the following package: 13 | 14 | ``` 15 | PM > Install-Package XamarinUniversity.Infrastructure 16 | ``` 17 | 18 | This will also add the **Core** library which provides the bare minimum for MVVM development - with no Xamarin.Forms dependencies. You can add this library on it's own if you prefer - this is useful if you segregate your ViewModels out to a separate assembly and don't want to take a dependency on Xamarin.Forms: 19 | 20 | ``` 21 | PM > Install-Package XamarinUniversity.Core 22 | ``` 23 | 24 | ## Helpful links 25 | 26 | * [Change log](https://github.com/xamarinhq/xamu-infrastructure/blob/master/CHANGELOG.md) 27 | 28 | * [NuGet package](https://www.nuget.org/packages/XamarinUniversity.Infrastructure/) 29 | 30 | * [Documentation](https://github.com/xamarinhq/xamu-infrastructure/wiki) 31 | 32 | * [License](https://github.com/xamarinhq/xamu-infrastructure/blob/master/LICENSE) 33 | 34 | * [Contribution Guide](https://github.com/xamarinhq/xamu-infrastructure/blob/master/CONTRIBUTING.md) 35 | 36 | Copyright (C) 2016-2018 Xamarin University, Microsoft 37 | -------------------------------------------------------------------------------- /ignore.travis.yml: -------------------------------------------------------------------------------- 1 | solution: src/XamU.Infrastructure.sln 2 | language: csharp 3 | dist: trusty 4 | sudo: required 5 | mono: none 6 | dotnet: 2.0.0 7 | script: 8 | - cd src/XamU.Core 9 | - dotnet build -c Release XamU.Core.csproj 10 | - cd ../XamU.Infrastructure 11 | - dotnet build -c Release XamU.Infrastructure.csproj -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xamarinhq/xamu-infrastructure/bb4b000019441384739ff46ca35b145b3cc8fd6d/logo.png -------------------------------------------------------------------------------- /src/XamU.Core/Collections/GroupedObservableCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // GroupedObservableCollection.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.ComponentModel; 28 | using System.Collections.Generic; 29 | using System.Diagnostics; 30 | 31 | namespace XamarinUniversity.Infrastructure 32 | { 33 | /// 34 | /// This is a simple observable collection which has a GroupBy key which can 35 | /// be used to populate a ListView with grouping turned on 36 | /// 37 | /// The type to use for the grouping key 38 | /// The type to use for the items 39 | [DebuggerDisplay ("Count={Count}")] 40 | public class GroupedObservableCollection : OptimizedObservableCollection 41 | { 42 | // Data 43 | bool hasItems; 44 | 45 | /// 46 | /// The read-only grouping key. 47 | /// 48 | /// The group title. 49 | public TKey Key { get; } 50 | 51 | /// 52 | /// Simple property to allow us to collapse a group when it has no items. 53 | /// 54 | /// true if has items; otherwise, false. 55 | public bool HasItems { 56 | get => hasItems; 57 | 58 | set { 59 | if (hasItems != value) { 60 | hasItems = value; 61 | OnPropertyChanged (new PropertyChangedEventArgs (nameof (HasItems))); 62 | } 63 | } 64 | } 65 | 66 | /// 67 | /// Initializes a grouped collection. 68 | /// 69 | public GroupedObservableCollection (TKey key) 70 | { 71 | Key = key; 72 | } 73 | 74 | /// 75 | /// Initializes the grouped collection with a set of items. 76 | /// 77 | /// Grouping key value 78 | /// Set of items for this group 79 | public GroupedObservableCollection (TKey key, IEnumerable items) 80 | : base(items) 81 | { 82 | Key = key; 83 | } 84 | 85 | /// 86 | /// Handles the PropertyChanged notification. We use this to catch changes 87 | /// to the Count and then update the property. 88 | /// 89 | /// EventArgs 90 | protected override void OnPropertyChanged (PropertyChangedEventArgs e) 91 | { 92 | base.OnPropertyChanged (e); 93 | if (e.PropertyName == nameof (Count)) { 94 | HasItems = Count > 0; 95 | } 96 | } 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /src/XamU.Core/Collections/OptimizedObservableCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // OptimizedObservableCollection.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Collections.ObjectModel; 30 | using System.Collections.Specialized; 31 | using System.ComponentModel; 32 | using System.Diagnostics; 33 | 34 | namespace XamarinUniversity.Infrastructure 35 | { 36 | /// 37 | /// ObservableCollection implementation which supports 38 | /// turning off notifications for mass updates through 39 | /// the method. 40 | /// 41 | /// Class type to hold 42 | /// 43 | /// 44 | /// var coll = new OptimizedObservableCollection<string>(); 45 | /// ... 46 | /// using (BeginMassUpdate ()) { 47 | /// foreach (var value in names) 48 | /// coll.Add (value); 49 | /// } 50 | /// 51 | /// 52 | [DebuggerDisplay ("Count={Count}")] 53 | public class OptimizedObservableCollection : ObservableCollection 54 | { 55 | bool shouldRaiseNotifications = true; 56 | 57 | /// 58 | /// Init a new instance of the collection. 59 | /// 60 | public OptimizedObservableCollection () 61 | { 62 | } 63 | 64 | /// 65 | /// Initialize a new instance of the collection from an existing data set. 66 | /// 67 | /// Collection. 68 | public OptimizedObservableCollection (IEnumerable collection) 69 | : base(collection) 70 | { 71 | } 72 | 73 | /// 74 | /// This method turns off notifications until the returned object 75 | /// is Disposed. At that point, the entire collection is invalidated. 76 | /// 77 | /// IDisposable 78 | public IDisposable BeginMassUpdate () 79 | { 80 | return new MassUpdater (this); 81 | } 82 | 83 | /// 84 | /// Turn off the collection changed notification 85 | /// 86 | /// E. 87 | protected override void OnCollectionChanged (NotifyCollectionChangedEventArgs e) 88 | { 89 | if (shouldRaiseNotifications) 90 | base.OnCollectionChanged (e); 91 | } 92 | 93 | /// 94 | /// Turn off the property changed notification 95 | /// 96 | /// E. 97 | protected override void OnPropertyChanged (PropertyChangedEventArgs e) 98 | { 99 | if (shouldRaiseNotifications) 100 | base.OnPropertyChanged (e); 101 | } 102 | 103 | /// 104 | /// IDisposable class which turns off updating 105 | /// 106 | class MassUpdater : IDisposable 107 | { 108 | readonly OptimizedObservableCollection parent; 109 | public MassUpdater (OptimizedObservableCollection parent) 110 | { 111 | this.parent = parent; 112 | parent.shouldRaiseNotifications = false; 113 | } 114 | 115 | #if DEBUG 116 | ~MassUpdater () 117 | { 118 | Debug.Assert (true, "Did not dispose returned object from OptimizedObservableCollection.BeginMassUpdate!"); 119 | } 120 | #endif 121 | 122 | 123 | public void Dispose () 124 | { 125 | parent.shouldRaiseNotifications = true; 126 | parent.OnPropertyChanged (new PropertyChangedEventArgs ("Count")); 127 | parent.OnPropertyChanged (new PropertyChangedEventArgs ("Item[]")); 128 | parent.OnCollectionChanged (new NotifyCollectionChangedEventArgs (NotifyCollectionChangedAction.Reset)); 129 | } 130 | } 131 | } 132 | } 133 | 134 | -------------------------------------------------------------------------------- /src/XamU.Core/Collections/RefreshingCollection.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RefreshingCollection.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.ComponentModel; 30 | using System.Diagnostics; 31 | using System.Threading.Tasks; 32 | 33 | namespace XamarinUniversity.Infrastructure 34 | { 35 | /// 36 | /// Provides an ObservableCollection which is backed by an asynchronous "fill" 37 | /// method. You can then "refresh" the data at any time and have the collection 38 | /// make callbacks when starting and completing the refresh. 39 | /// 40 | /// Object type for the collection 41 | [DebuggerDisplay("Count={Count}")] 42 | public class RefreshingCollection : OptimizedObservableCollection 43 | { 44 | private bool isRefreshing; 45 | private readonly Func>> refreshDataFunc; 46 | 47 | /// 48 | /// True when the collection is refreshing. 49 | /// Can databind this to a ListView.IsRefreshing property to control 50 | /// when it's refreshing. 51 | /// 52 | public bool IsRefreshing 53 | { 54 | get { return isRefreshing; } 55 | protected set 56 | { 57 | if (isRefreshing != value) 58 | { 59 | isRefreshing = value; 60 | OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsRefreshing))); 61 | } 62 | } 63 | } 64 | 65 | /// 66 | /// This delegate is called BEFORE a refresh is initated 67 | /// 68 | /// The before refresh. 69 | public Func, object> BeforeRefresh { get; set; } 70 | 71 | /// 72 | /// This delegate is called during a refresh to possibly merge the collection. 73 | /// If this is not implemented, then the collection is replaced. 74 | /// 75 | public Action, IEnumerable> Merge { get; set; } 76 | 77 | /// 78 | /// This delegate is called AFTER a refresh completes and the contents are replaced. 79 | /// 80 | /// The after refresh. 81 | public Action, object> AfterRefresh { get; set; } 82 | 83 | /// 84 | /// This delegate is called if a refresh throws an exception. 85 | /// 86 | /// The refresh failed. 87 | public Func, Exception, Task> RefreshFailed { get; set; } 88 | 89 | /// 90 | /// Create a new Refreshing Collection. 91 | /// 92 | /// Method which returns the data for the collection 93 | public RefreshingCollection(Func>> refreshFunc) 94 | { 95 | this.refreshDataFunc = refreshFunc ?? throw new ArgumentNullException(nameof(refreshFunc)); 96 | } 97 | 98 | /// 99 | /// Create a new Refreshing Collection. 100 | /// 101 | /// Method which returns the data for the collection 102 | /// Initial data to fill collection with 103 | public RefreshingCollection(Func>> refreshFunc, IEnumerable initialData) 104 | : base(initialData) 105 | { 106 | this.refreshDataFunc = refreshFunc ?? throw new ArgumentNullException(nameof(refreshFunc)); 107 | } 108 | 109 | /// 110 | /// Refreshes the data in the collection. The refresh method is invoked and 111 | /// this method will replace all the data in the collection with the data coming 112 | /// back from the refresh method. 113 | /// 114 | /// Awaitable task 115 | public async Task RefreshAsync() 116 | { 117 | object refreshParameter = null; 118 | IsRefreshing = true; 119 | 120 | try 121 | { 122 | if (BeforeRefresh != null) 123 | { 124 | refreshParameter = BeforeRefresh.Invoke(this); 125 | } 126 | 127 | var results = await refreshDataFunc(); 128 | if (results != null) 129 | { 130 | using (base.BeginMassUpdate()) 131 | { 132 | if (Merge == null) // replace the entire collection 133 | { 134 | base.Clear(); 135 | foreach (var item in results) 136 | { 137 | base.Add(item); 138 | } 139 | } 140 | else 141 | { 142 | Merge.Invoke(this, results); 143 | } 144 | } 145 | } 146 | } 147 | catch (Exception ex) 148 | { 149 | if (RefreshFailed != null) 150 | { 151 | await RefreshFailed.Invoke(this, ex); 152 | } 153 | } 154 | finally 155 | { 156 | IsRefreshing = false; 157 | AfterRefresh?.Invoke(this, refreshParameter); 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/XamU.Core/Extensions/ExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ExceptionExtensions.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Text; 29 | 30 | namespace XamarinUniversity.Infrastructure 31 | { 32 | /// 33 | /// Extensions for the global Exception type 34 | /// 35 | public static class ExceptionExtensions 36 | { 37 | /// 38 | /// Flatten the exception and inner exception data. 39 | /// 40 | /// Exception 41 | /// Any string prefix to add 42 | /// True to include stack trace at end 43 | /// String with Message and all InnerException messages appended together 44 | public static string Flatten(this Exception ex, string header = "", bool includeStackTrace = false) 45 | { 46 | StringBuilder sb = new StringBuilder(header); 47 | 48 | Exception current; 49 | AggregateException aex = ex as AggregateException; 50 | if (aex != null) 51 | { 52 | sb.AppendLine (nameof(AggregateException)); 53 | aex = aex.Flatten (); 54 | for (int i = 0; i < aex.InnerExceptions.Count; i++) { 55 | current = aex.InnerExceptions [i]; 56 | sb.AppendLine (current.Flatten ($"{i}: ", includeStackTrace)); 57 | } 58 | } 59 | else 60 | { 61 | current = ex; 62 | while (current != null) { 63 | sb.AppendFormat ("{0} : {1}", current.GetType(), current.Message); 64 | if (includeStackTrace) 65 | sb.Append (ex.StackTrace); 66 | else sb.AppendLine (); 67 | 68 | current = current.InnerException; 69 | if (current != null && includeStackTrace) 70 | sb.AppendLine (); 71 | } 72 | } 73 | 74 | return sb.ToString(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/XamU.Core/Extensions/TaskExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // TaskExtensions.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Diagnostics; 28 | using System.Runtime.CompilerServices; 29 | using System.Threading; 30 | using System.Threading.Tasks; 31 | using System; 32 | 33 | namespace XamarinUniversity.Infrastructure 34 | { 35 | /// 36 | /// Extensions for the System.Threading.Tasks.Task type. 37 | /// 38 | public static class TaskExtensions 39 | { 40 | /// 41 | /// This method can be used to ignore the result of a Task without 42 | /// losing the ability to throw the exception if the task fails. 43 | /// 44 | /// 45 | /// 46 | /// Task.Run(() => ...).IgnoreResult(); 47 | /// 48 | /// 49 | /// Task to ignore 50 | /// Optional handler for the exception; if null then method throws on UI thread. 51 | /// Caller name 52 | /// Line number. 53 | public static void IgnoreResult(this Task task, Action faultHandler = null, [CallerMemberName] string member = "", [CallerLineNumber] int lineNumber = 0) 54 | { 55 | task.ContinueWith(tr => 56 | { 57 | Debug.WriteLine ("Encountered {0} at {1}, line #{2}", 58 | task.Exception.GetType (), member, lineNumber); 59 | Debug.WriteLine(task.Exception.Flatten()); 60 | 61 | if (faultHandler != null) 62 | { 63 | faultHandler.Invoke (task.Exception); 64 | } 65 | else 66 | { 67 | Debug.WriteLine ("WARNING: exception {0} was ignored!", task.Exception.GetType ()); 68 | } 69 | 70 | }, CancellationToken.None, 71 | TaskContinuationOptions.OnlyOnFaulted, 72 | TaskScheduler.FromCurrentSynchronizationContext()); 73 | } 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/IAsyncDelegateCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IAsyncDelegateCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Threading.Tasks; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// Extension of ICommand which exposes a raise execute handler and async support. 33 | /// 34 | public interface IAsyncDelegateCommand : IDelegateCommand 35 | { 36 | /// 37 | /// Executes the command and returns the async Task. 38 | /// 39 | /// async result 40 | /// Parameter. 41 | Task ExecuteAsync (object parameter); 42 | } 43 | 44 | /// 45 | /// Extension of ICommand which exposes a raise execute handler. 46 | /// 47 | public interface IAsyncDelegateCommand : IAsyncDelegateCommand 48 | { 49 | /// 50 | /// Executes the command and returns the async Task. 51 | /// 52 | /// async result 53 | /// Parameter. 54 | Task ExecuteAsync (T parameter); 55 | } 56 | } -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/IDelegateCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IDelegateCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Windows.Input; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// Extension of ICommand which exposes a raise execute handler. 33 | /// 34 | public interface IDelegateCommand : ICommand 35 | { 36 | /// 37 | /// Call this to raise the CanExecuteChanged event. 38 | /// 39 | void RaiseCanExecuteChanged (); 40 | } 41 | } -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/IDependencyService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IDependencyService.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | namespace XamarinUniversity.Infrastructure 28 | { 29 | /// 30 | /// Type of dependency creation to perform 31 | /// 32 | public enum DependencyScope 33 | { 34 | /// 35 | /// Use a single instance (cached off) 36 | /// 37 | Global, 38 | /// 39 | /// Create a new instance of the dependency 40 | /// 41 | NewInstance 42 | } 43 | 44 | /// 45 | /// Interface to wrap a ServiceLocator 46 | /// 47 | public interface IDependencyService 48 | { 49 | /// 50 | /// Register a specific type as an abstraction 51 | /// 52 | /// The class to register 53 | void Register () where T : class, new(); 54 | 55 | /// 56 | /// Register a specific abstraction associated to a type. 57 | /// 58 | /// The abstraction 59 | /// The implementation 60 | void Register () where T : class where TImpl : class, T, new(); 61 | 62 | /// 63 | /// Register a specific instance of an abstraction. 64 | /// 65 | /// Abstraction type 66 | /// Instance to use 67 | void Register(T impl) where T : class; 68 | 69 | /// 70 | /// Retrieve a specific implementation from the locator. 71 | /// Defaults to DependencyScope.Global 72 | /// 73 | /// Type to look for 74 | T Get() where T : class; 75 | 76 | /// 77 | /// Retrieve a specific implementation from the locator. 78 | /// 79 | /// Type to look for 80 | /// Global or new instance 81 | /// 82 | /// Note: the scope parameter is only used when the object was registered as a type and not an instance. 83 | /// - In the case of an instance registration, that same instance is always returned. 84 | /// - In the case of no registration found, a newly created object is always returned. 85 | /// 86 | T Get(DependencyScope scope) where T : class; 87 | } 88 | } -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/IInitViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace XamarinUniversity.Infrastructure 7 | { 8 | /// 9 | /// Optional interface for ViewModels which supports 10 | /// initialization when being used with a Navigation 11 | /// 12 | public interface IViewModelNavigationInit 13 | { 14 | /// 15 | /// Method called to initialize a ViewModel 16 | /// 17 | /// Task (might be completed) 18 | Task IntializeAsync(object stateParameter); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/IMessageVisualizerService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IMessageVisualizerService.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Threading.Tasks; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// Interface to display UI "MessageBox" style prompts. 33 | /// 34 | public interface IMessageVisualizerService 35 | { 36 | /// 37 | /// Show a message on the UI 38 | /// 39 | /// Async result (true/false) 40 | /// Title 41 | /// Message 42 | /// Text for OK button 43 | /// Optional text for Cancel button 44 | Task ShowMessage( 45 | string title, string message, string ok, string cancel = null); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/XamU.Core/Interfaces/INavigationService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // INavigationService.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Threading.Tasks; 30 | 31 | namespace XamarinUniversity.Infrastructure 32 | { 33 | /// 34 | /// Interface to manage navigation in the application. 35 | /// 36 | public interface INavigationService 37 | { 38 | /// 39 | /// Key comparer for navigation keys. Change this if you 40 | /// use a complex key which doesn't support direct equality. 41 | /// 42 | IEqualityComparer KeyComparer { get; set; } 43 | 44 | /// 45 | /// Event raised when NavigateAsync is used. 46 | /// 47 | event EventHandler Navigated; 48 | 49 | /// 50 | /// Event raised when a GoBackAsync operation occurs. 51 | /// 52 | event EventHandler NavigatedBack; 53 | 54 | /// 55 | /// Pops all pages off the stack up to the first one. 56 | /// 57 | Task PopToRootAsync(); 58 | 59 | /// 60 | /// Navigate to a page using the known key. 61 | /// 62 | /// The async. 63 | /// Navigation key. 64 | Task NavigateAsync(object key); 65 | 66 | /// 67 | /// Navigate to a page using the known key. 68 | /// The state object (if not null) will be assigned as the BindingContext 69 | /// if the View doesn't assign it as part of construction. If there _is_ a BindingContext, 70 | /// then the state will be passed to the IViewModelNavigationInit.IntializeAsync implementation. 71 | /// 72 | /// Task 73 | /// Navigation key. 74 | /// State (can be ViewModel, or state passed to IViewModelNavigationInit) 75 | Task NavigateAsync(object key, object state); 76 | 77 | /// 78 | /// Returns true/false whether we can go backwards on the Nav Stack. 79 | /// 80 | /// true if can go back; otherwise, false. 81 | bool CanGoBack { get; } 82 | 83 | /// 84 | /// Pops the last page off the stack and navigates to it. 85 | /// 86 | /// Async response 87 | Task GoBackAsync(); 88 | 89 | /// 90 | /// Push a page onto the modal stack. 91 | /// 92 | /// Async response 93 | /// Navigation key. 94 | Task PushModalAsync(object key); 95 | 96 | /// 97 | /// Push a page onto the modal stack. 98 | /// 99 | /// Async response 100 | /// Navigation key. 101 | /// State (can be ViewModel, or state passed to IViewModelNavigationInit) 102 | Task PushModalAsync(object key, object state); 103 | 104 | /// 105 | /// Pops the last page off the modal stack 106 | /// 107 | /// Async response 108 | Task PopModalAsync(); 109 | 110 | /// 111 | /// Register an action to take when a specific navigation is requested. 112 | /// 113 | /// Navigation Key 114 | /// Action to perform 115 | void RegisterAction(object key, Action action); 116 | 117 | /// 118 | /// Register an action to take when a specific navigation is requested. 119 | /// 120 | /// Navigation Key 121 | /// Action to perform 122 | void RegisterAction(object key, Action action); 123 | 124 | /// 125 | /// Unregister a specific key 126 | /// 127 | /// Navigation Key 128 | void Unregister(object key); 129 | } 130 | } -------------------------------------------------------------------------------- /src/XamU.Core/Mvvm/AsyncDelegateCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // AsyncDelegateCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Threading.Tasks; 29 | 30 | namespace XamarinUniversity.Infrastructure 31 | { 32 | /// 33 | /// A base ICommand implementation that supports async/await. 34 | /// 35 | public class AsyncDelegateCommand : IAsyncDelegateCommand 36 | { 37 | /// 38 | /// Delegate to call when CanExecute method is called. 39 | /// 40 | protected readonly Predicate canExecute; 41 | 42 | /// 43 | /// Delegate to call when Execute is called. 44 | /// 45 | protected Func asyncExecute; 46 | 47 | /// 48 | /// Event which is raised when the state of this command has changed. 49 | /// 50 | public event EventHandler CanExecuteChanged; 51 | 52 | /// 53 | /// Creates a new async delegate command. 54 | /// 55 | /// Method to call when command is executed. 56 | public AsyncDelegateCommand(Func execute) 57 | : this(_ => execute(), null) 58 | { 59 | } 60 | 61 | /// 62 | /// Creates a new async delegate command. 63 | /// 64 | /// Method to call when command is executed. 65 | public AsyncDelegateCommand(Func execute) 66 | : this(execute, null) 67 | { 68 | } 69 | 70 | /// 71 | /// Creates a new async delegate command. 72 | /// 73 | /// Method to call when command is executed. 74 | /// Method to call to determine whether command is valid. 75 | public AsyncDelegateCommand(Func execute, Func canExecute) 76 | : this(_ => execute(), _ => canExecute()) 77 | { 78 | } 79 | 80 | /// 81 | /// Creates a new async delegate command. 82 | /// 83 | /// Method to call when command is executed. 84 | /// Method to call to determine whether command is valid. 85 | public AsyncDelegateCommand(Func asyncExecute, 86 | Predicate canExecute) 87 | { 88 | this.asyncExecute = asyncExecute; 89 | this.canExecute = canExecute; 90 | } 91 | 92 | /// 93 | /// Raise the CanExecuteChanged handler. 94 | /// 95 | public void RaiseCanExecuteChanged() 96 | { 97 | CanExecuteChanged?.Invoke(this, EventArgs.Empty); 98 | } 99 | 100 | /// 101 | /// Returns whether the command is possible right now. 102 | /// 103 | /// true, if execute was caned, false otherwise. 104 | /// Parameter. 105 | public bool CanExecute(object parameter) 106 | { 107 | return canExecute == null || canExecute (parameter); 108 | } 109 | 110 | /// 111 | /// Executes the command. 112 | /// 113 | /// Parameter. 114 | public async void Execute(object parameter) 115 | { 116 | await ExecuteAsync(parameter); 117 | } 118 | 119 | /// 120 | /// Executes the command and returns an awaitable task. 121 | /// 122 | /// The async. 123 | /// Parameter. 124 | public async Task ExecuteAsync(object parameter) 125 | { 126 | await asyncExecute(parameter); 127 | } 128 | } 129 | 130 | /// 131 | /// A generic ICommand implementation that supports async/await. 132 | /// 133 | public class AsyncDelegateCommand : IAsyncDelegateCommand 134 | { 135 | /// 136 | /// Delegate to call when CanExecute method is called. 137 | /// 138 | protected readonly Predicate canExecute; 139 | 140 | /// 141 | /// Delegate to call when Execute method is called. 142 | /// 143 | protected Func asyncExecute; 144 | 145 | /// 146 | /// Event to raise when the state of the command has changed. 147 | /// 148 | public event EventHandler CanExecuteChanged; 149 | 150 | /// 151 | /// Creates a new async delegate command. 152 | /// 153 | /// Method to call when command is executed. 154 | public AsyncDelegateCommand(Func execute) 155 | : this(execute, null) 156 | { 157 | } 158 | 159 | /// 160 | /// Creates a new async delegate command. 161 | /// 162 | /// Method to call when command is executed. 163 | /// Method to determine whether command is valid. 164 | public AsyncDelegateCommand(Func asyncExecute, 165 | Predicate canExecute) 166 | { 167 | this.asyncExecute = asyncExecute; 168 | this.canExecute = canExecute; 169 | } 170 | 171 | /// 172 | /// Raises the CanExecuteChanged event. 173 | /// 174 | public void RaiseCanExecuteChanged() 175 | { 176 | CanExecuteChanged?.Invoke(this, EventArgs.Empty); 177 | } 178 | 179 | /// 180 | /// Returns whether the command is valid at this moment. 181 | /// 182 | /// true, if execute was caned, false otherwise. 183 | /// Parameter. 184 | public bool CanExecute(object parameter) 185 | { 186 | return (canExecute == null) || canExecute((T)parameter); 187 | } 188 | 189 | /// 190 | /// Executes the command. 191 | /// 192 | /// Parameter. 193 | public async void Execute(object parameter) 194 | { 195 | await ExecuteAsync((T)parameter); 196 | } 197 | 198 | /// 199 | /// Executes the command. 200 | /// 201 | /// Parameter. 202 | async Task IAsyncDelegateCommand.ExecuteAsync(object parameter) 203 | { 204 | await asyncExecute ((T)parameter); 205 | } 206 | 207 | /// 208 | /// Executes the command. 209 | /// 210 | /// Parameter. 211 | public async Task ExecuteAsync(T parameter) 212 | { 213 | await asyncExecute(parameter); 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/XamU.Core/Mvvm/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DelegateCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// Implementation of ICommand using delegates. 33 | /// This is preferred over Command in Forms so it can be mocked/replaced 34 | /// in the ViewModel and have your VM not take a dependency on Forms. 35 | /// 36 | public sealed class DelegateCommand : IDelegateCommand 37 | { 38 | /// 39 | /// Delegate to call when the Execute method is called. 40 | /// 41 | readonly Action command; 42 | 43 | /// 44 | /// Delegate to call when the CanExecute method is called. 45 | /// 46 | readonly Func canExecute; 47 | 48 | /// 49 | /// Event to raise when the state of the command has changed. 50 | /// 51 | public event EventHandler CanExecuteChanged; 52 | 53 | /// 54 | /// Creates a new DelegateCommand. 55 | /// 56 | /// Delegate to call for command 57 | public DelegateCommand (Action command) : this (command, null) 58 | { 59 | } 60 | 61 | /// 62 | /// Creates a new DelegateCommand. 63 | /// 64 | /// Delegate to call for command 65 | public DelegateCommand (Action command) : this (command, null) 66 | { 67 | } 68 | 69 | /// 70 | /// Creates a new DelegateCommand. 71 | /// 72 | /// Delegate to call for command 73 | /// Delegate to call for CanExecute 74 | public DelegateCommand (Action command, Func test) 75 | { 76 | if (command == null) 77 | throw new ArgumentNullException ("command", "Command cannot be null."); 78 | this.command = delegate { 79 | command (); 80 | }; 81 | if (test != null) { 82 | this.canExecute = delegate { 83 | return test (); 84 | }; 85 | } 86 | } 87 | 88 | /// 89 | /// Creates a new DelegateCommand. 90 | /// 91 | /// Delegate to call for command 92 | /// Delegate to call for CanExecute 93 | public DelegateCommand (Action command, Func test) 94 | { 95 | if (command == null) 96 | throw new ArgumentNullException ("command", "Command cannot be null."); 97 | 98 | this.command = command; 99 | this.canExecute = test; 100 | } 101 | 102 | /// 103 | /// Raises the CanExecuteChanged event. 104 | /// 105 | public void RaiseCanExecuteChanged () 106 | { 107 | this.CanExecuteChanged?.Invoke (this, EventArgs.Empty); 108 | } 109 | 110 | /// 111 | /// Checks to see if the command is valid. 112 | /// 113 | /// true, if execute was caned, false otherwise. 114 | /// Parameter. 115 | public bool CanExecute (object parameter) 116 | { 117 | return (this.canExecute == null) || this.canExecute (parameter); 118 | } 119 | 120 | /// 121 | /// Executes the command. 122 | /// 123 | /// Parameter. 124 | public void Execute (object parameter) 125 | { 126 | this.command (parameter); 127 | } 128 | } 129 | 130 | /// 131 | /// Generic form of the DelegateCommand with a parameter. 132 | /// 133 | public sealed class DelegateCommand : IDelegateCommand 134 | { 135 | /// 136 | /// Delegate to call when the Execute method is called. 137 | /// 138 | readonly Action command; 139 | 140 | /// 141 | /// Delegate to call when the CanExecute method is called. 142 | /// 143 | readonly Func canExecute; 144 | 145 | /// 146 | /// Event to raise when the state of the command has changed. 147 | /// 148 | public event EventHandler CanExecuteChanged; 149 | 150 | /// 151 | /// Creates a new Delegate command 152 | /// 153 | /// Delegate to invoke 154 | public DelegateCommand (Action command) : this (command, null) 155 | { 156 | } 157 | 158 | /// 159 | /// Creates a new Delegate command 160 | /// 161 | /// Delegate to invoke 162 | /// Delegate for CanExecute 163 | public DelegateCommand (Action command, Func test) 164 | { 165 | if (command == null) 166 | throw new ArgumentNullException ("command", "Command cannot be null."); 167 | 168 | this.command = command; 169 | this.canExecute = test; 170 | } 171 | 172 | /// 173 | /// Raises the CanExecuteChanged event. 174 | /// 175 | public void RaiseCanExecuteChanged () 176 | { 177 | this.CanExecuteChanged?.Invoke (this, EventArgs.Empty); 178 | } 179 | 180 | /// 181 | /// Returns whether the command is valid. 182 | /// 183 | /// true, if execute was caned, false otherwise. 184 | /// Parameter. 185 | public bool CanExecute (object parameter) 186 | { 187 | return (this.canExecute == null) || this.canExecute ((T)parameter); 188 | } 189 | 190 | /// 191 | /// Executes the command. 192 | /// 193 | /// Parameter. 194 | public void Execute (object parameter) 195 | { 196 | this.command ((T)parameter); 197 | } 198 | } 199 | } 200 | 201 | -------------------------------------------------------------------------------- /src/XamU.Core/Mvvm/SimpleViewModel.cs: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleViewModel.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.ComponentModel; 29 | using System.Linq.Expressions; 30 | using System.Reflection; 31 | using System.Runtime.CompilerServices; 32 | using System.Threading.Tasks; 33 | 34 | namespace XamarinUniversity.Infrastructure 35 | { 36 | /// 37 | /// This is a simple base class for MVVM. 38 | /// 39 | public class SimpleViewModel : INotifyPropertyChanged, IViewModelNavigationInit 40 | { 41 | #if NETSTANDARD1_0 42 | // .NET Standard 1.0 doesn't support Task.CompletedTask :( 43 | private readonly static Task CompletedTask = Task.FromResult(0); 44 | #endif 45 | 46 | /// 47 | /// Event to raise when a property is changed. 48 | /// 49 | public event PropertyChangedEventHandler PropertyChanged; 50 | 51 | /// 52 | /// Inform any bindings that ALL property values must be read. 53 | /// 54 | protected void RaiseAllPropertiesChanged() 55 | { 56 | // By convention, an empty string indicates all properties are invalid. 57 | this.RaisePropertyChanged(string.Empty); 58 | } 59 | 60 | /// 61 | /// Raises a specific property change event using an expression. 62 | /// 63 | /// Property expr. 64 | /// The 1st type parameter. 65 | protected void RaisePropertyChanged(Expression> propExpr) 66 | { 67 | var prop = (PropertyInfo)((MemberExpression)propExpr.Body).Member; 68 | this.RaisePropertyChanged(prop.Name); 69 | } 70 | 71 | /// 72 | /// Raises a specific property change event using a string for the property name. 73 | /// 74 | /// Property name. 75 | protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName= "") 76 | { 77 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 78 | } 79 | 80 | /// 81 | /// Changes a field's value and raises property change notifications. 82 | /// 83 | /// true, if property value was set, false otherwise. 84 | /// Storage field. 85 | /// New value. 86 | /// Property expr. 87 | /// The 1st type parameter. 88 | protected bool SetPropertyValue(ref T storageField, T newValue, Expression> propExpr) 89 | { 90 | if (Equals(storageField, newValue)) 91 | return false; 92 | 93 | storageField = newValue; 94 | var prop = (PropertyInfo)((MemberExpression)propExpr.Body).Member; 95 | this.RaisePropertyChanged(prop.Name); 96 | 97 | return true; 98 | } 99 | 100 | /// 101 | /// Changes a field's value and raises property change notifications. 102 | /// 103 | /// true, if property value was set, false otherwise. 104 | /// Storage field. 105 | /// New value. 106 | /// Property name. 107 | /// The 1st type parameter. 108 | protected bool SetPropertyValue(ref T storageField, T newValue, [CallerMemberName] string propertyName = "") 109 | { 110 | if (Equals(storageField, newValue)) 111 | return false; 112 | 113 | storageField = newValue; 114 | this.RaisePropertyChanged(propertyName); 115 | 116 | return true; 117 | } 118 | 119 | /// 120 | /// Method called to initialize a ViewModel when using the INavigationService.NavigateAsync 121 | /// built-in implementation. 122 | /// 123 | /// State parameter passed to NavigateAsync 124 | /// Task (might be completed) 125 | protected virtual Task IntializeAsync(object stateParameter) 126 | { 127 | #if NETSTANDARD1_0 128 | return CompletedTask; 129 | #else 130 | return Task.CompletedTask; 131 | #endif 132 | } 133 | 134 | /// 135 | /// Implementation of the IViewModelNavigationInit.IntializeAsync method. 136 | /// 137 | /// State parameter passed to NavigateAsync 138 | /// Task (might be completed) 139 | Task IViewModelNavigationInit.IntializeAsync(object stateParameter) 140 | { 141 | // Pass to virtual implementation for derived classes to override. 142 | return this.IntializeAsync(stateParameter); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/XamU.Core/XamU.Core-old.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C} 7 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 8 | Library 9 | XamU.Core 10 | XamU.Core 11 | v4.5 12 | Profile259 13 | 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug 21 | DEBUG; 22 | prompt 23 | 4 24 | 25 | 26 | true 27 | bin\Release 28 | TRACE 29 | prompt 30 | 4 31 | bin\Release\XamU.Core.xml 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll 58 | 59 | 60 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll 61 | 62 | 63 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll 64 | 65 | 66 | 67 | 68 | 69 | 70 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/XamU.Core/XamU.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;uap10.0.16299 6 | netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71; 7 | 2.2.0 8 | XamarinUniversity.Core 9 | Xamarin University Core Library 10 | Microsoft, Xamarin University 11 | Xamarin University Core Library 12 | XamarinUniversity.Core 13 | https://github.com/xamarinhq/xamu-infrastructure/blob/master/LICENSE 14 | https://github.com/xamarinhq/xamu-infrastructure 15 | https://raw.githubusercontent.com/xamarinhq/xamu-infrastructure/master/logo.png 16 | true 17 | This library provides a set of .NET classes for XAML based MVVM development. 18 | MVVM Core library for XAML development 19 | https://github.com/xamarinhq/xamu-infrastructure/blob/master/CHANGELOG.md 20 | https://github.com/xamarinhq/xamu-infrastructure 21 | mvvm;ios;xamarin;android;winphone;uwp;windows;wpf;macos 22 | XamU.Core 23 | Microsoft, Xamarin University 24 | Copyright (C) 2017-2018 Microsoft, Xamarin University 25 | true 26 | 2.2.0.0 27 | 2.2.0.0 28 | 29 | 30 | 31 | full 32 | true 33 | 34 | 35 | 36 | pdbonly 37 | true 38 | 39 | 40 | 41 | $(DefineConstants);PLATFORM_ANDROID 42 | 43 | 44 | 45 | $(DefineConstants);PLATFORM_MAC 46 | 47 | 48 | 49 | $(DefineConstants);PLATFORM_IOS 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Windows Mobile Extensions for the UWP 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure.Tests/DependencyServiceWrapperTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Xamarin.Forms; 4 | using XamarinUniversity.Services; 5 | 6 | namespace XamU.Infrastructure.Tests 7 | { 8 | [TestClass] 9 | public class DependencyServiceWrapperTests 10 | { 11 | public interface IService1 { } 12 | 13 | public class ServiceClass1 : IService1 14 | { 15 | } 16 | 17 | public class ServiceClass2 18 | { 19 | public IService1 Service1 { get; } 20 | 21 | public ServiceClass2(IService1 service1) 22 | { 23 | Service1 = service1; 24 | } 25 | } 26 | 27 | [TestInitialize] 28 | public void Setup() 29 | { 30 | Xamarin.Forms.Mocks.MockForms.Init(); 31 | DependencyService.Register(); 32 | } 33 | 34 | [TestMethod] 35 | public void CheckGetMethod() 36 | { 37 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 38 | 39 | var instance = wrapper.Get(); 40 | Assert.IsNotNull(instance); 41 | Assert.IsInstanceOfType(instance, typeof(ServiceClass1)); 42 | } 43 | 44 | [TestMethod] 45 | public void CheckGetDefaultMethod() 46 | { 47 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 48 | 49 | var instance1 = wrapper.Get(); 50 | Assert.IsNotNull(instance1); 51 | 52 | var instance2 = wrapper.Get(); 53 | Assert.IsNotNull(instance2); 54 | 55 | Assert.AreEqual(instance1, instance2); 56 | } 57 | 58 | [TestMethod] 59 | public void CheckGetInstanceMethod() 60 | { 61 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 62 | 63 | var instance1 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.NewInstance); 64 | Assert.IsNotNull(instance1); 65 | 66 | var instance2 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.NewInstance); 67 | Assert.IsNotNull(instance2); 68 | 69 | Assert.AreNotEqual(instance1, instance2); 70 | } 71 | 72 | 73 | [TestMethod] 74 | public void CheckGetGlobalMethod() 75 | { 76 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 77 | 78 | var instance1 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.Global); 79 | Assert.IsNotNull(instance1); 80 | 81 | var instance2 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.Global); 82 | Assert.IsNotNull(instance2); 83 | 84 | Assert.AreEqual(instance1, instance2); 85 | } 86 | 87 | [TestMethod] 88 | public void CreateObjectWithDefaultParameters() 89 | { 90 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 91 | 92 | var instance1 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.Global); 93 | Assert.IsNotNull(instance1); 94 | 95 | var instance2 = wrapper.Get(); 96 | Assert.IsNotNull(instance2); 97 | Assert.AreEqual(instance1, instance2.Service1); 98 | } 99 | 100 | [TestMethod] 101 | public void CreateObjectWithLocalParameters() 102 | { 103 | DependencyServiceWrapper wrapper = new DependencyServiceWrapper(); 104 | 105 | var instance1 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.NewInstance); 106 | Assert.IsNotNull(instance1); 107 | 108 | var instance2 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.Global); 109 | Assert.IsNotNull(instance2); 110 | 111 | var instance3 = wrapper.Get(XamarinUniversity.Infrastructure.DependencyScope.NewInstance); 112 | Assert.IsNotNull(instance3); 113 | Assert.AreNotEqual(instance1, instance3.Service1); 114 | Assert.AreNotEqual(instance2, instance3.Service1); 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure.Tests/ObservableDictionaryTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Collections.Specialized; 5 | using System.Linq; 6 | using System.Text; 7 | using Microsoft.VisualStudio.TestTools.UnitTesting; 8 | using XamarinUniversity.Infrastructure; 9 | 10 | namespace XamU.Infrastructure.Tests 11 | { 12 | /// 13 | ///This is a test class for ObservableDictionaryTest and is intended 14 | ///to contain all ObservableDictionaryTest Unit Tests. It only tests 15 | /// the new features -- not the entire Dictionary semantics. 16 | /// 17 | [TestClass] 18 | public class ObservableDictionaryTests 19 | { 20 | private readonly string[] changedProperties = {"Count", "Keys", "Values"}; 21 | 22 | [TestMethod] 23 | public void AddStringTest() 24 | { 25 | var target = new ObservableDictionary(); 26 | 27 | bool hitChange = false; 28 | const string key = "Hello"; 29 | const int value = 10; 30 | 31 | target.PropertyChanged += (s, e) => { Assert.IsTrue(e.PropertyName == $"Item[{key}]" || changedProperties.Contains(e.PropertyName)); }; 32 | 33 | target.CollectionChanged += (s, e) => 34 | { 35 | hitChange = true; 36 | Assert.AreSame(target, s); 37 | Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action); 38 | var item = (KeyValuePair)e.NewItems[0]; 39 | Assert.AreEqual(key, item.Key); 40 | Assert.AreEqual(value, item.Value); 41 | }; 42 | 43 | target[key] = value; 44 | Assert.IsTrue(hitChange); 45 | } 46 | 47 | [TestMethod] 48 | public void AddTest() 49 | { 50 | var target = new ObservableDictionary(); 51 | 52 | bool hitChange = false; 53 | const int key = 10; 54 | const string value = "Hello"; 55 | 56 | target.PropertyChanged += (s, e) => { Assert.IsTrue(e.PropertyName == $"Item[{key}]" || changedProperties.Contains(e.PropertyName)); }; 57 | 58 | target.CollectionChanged += (s, e) => 59 | { 60 | hitChange = true; 61 | Assert.AreSame(target, s); 62 | Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action); 63 | var item = (KeyValuePair)e.NewItems[0]; 64 | Assert.AreEqual(key, item.Key); 65 | Assert.AreEqual(value, item.Value); 66 | }; 67 | 68 | target[key] = value; 69 | Assert.IsTrue(hitChange); 70 | } 71 | 72 | [TestMethod()] 73 | public void ReplaceTest() 74 | { 75 | var target = new ObservableDictionary(); 76 | 77 | bool hitChange = false; 78 | const int key = 10; 79 | const string value = "Hello"; 80 | const string value2 = "World"; 81 | 82 | target[key] = value; 83 | 84 | target.PropertyChanged += (s, e) => { Assert.IsTrue(e.PropertyName == $"Item[{key}]" || changedProperties.Contains(e.PropertyName)); }; 85 | 86 | target.CollectionChanged += (s, e) => 87 | { 88 | hitChange = true; 89 | Assert.AreSame(target, s); 90 | Assert.AreEqual(NotifyCollectionChangedAction.Replace, e.Action); 91 | var oldItem = (KeyValuePair)e.OldItems[0]; 92 | Assert.AreEqual(key, oldItem.Key); 93 | Assert.AreEqual(value, oldItem.Value); 94 | var newItem = (KeyValuePair)e.NewItems[0]; 95 | Assert.AreEqual(key, newItem.Key); 96 | Assert.AreEqual(value2, newItem.Value); 97 | }; 98 | 99 | target[key] = value2; 100 | Assert.IsTrue(hitChange); 101 | } 102 | 103 | [TestMethod()] 104 | public void ClearTest() 105 | { 106 | var target = new ObservableDictionary(); 107 | 108 | bool hitChange = false; 109 | const int key = 10; 110 | const string value = "Hello"; 111 | 112 | target[key] = value; 113 | 114 | target.PropertyChanged += (s, e) => { Assert.IsTrue(changedProperties.Contains(e.PropertyName)); }; 115 | 116 | target.CollectionChanged += (s, e) => 117 | { 118 | hitChange = true; 119 | Assert.AreSame(target, s); 120 | Assert.AreEqual(NotifyCollectionChangedAction.Reset, e.Action); 121 | }; 122 | 123 | target.Clear(); 124 | 125 | Assert.IsTrue(hitChange); 126 | } 127 | 128 | [TestMethod()] 129 | public void RemoveTest() 130 | { 131 | var target = new ObservableDictionary(); 132 | 133 | bool hitChange = false; 134 | const int key = 10; 135 | const string value = "Hello"; 136 | 137 | target[key] = value; 138 | 139 | target.PropertyChanged += (s, e) => { Assert.IsTrue(e.PropertyName == $"Item[{key}]" || changedProperties.Contains(e.PropertyName)); }; 140 | 141 | target.CollectionChanged += (s, e) => 142 | { 143 | hitChange = true; 144 | Assert.AreSame(target, s); 145 | Assert.AreEqual(NotifyCollectionChangedAction.Remove, e.Action); 146 | var oldItem = (KeyValuePair)e.OldItems[0]; 147 | Assert.AreEqual(key, oldItem.Key); 148 | Assert.AreEqual(value, oldItem.Value); 149 | }; 150 | 151 | target.Remove(key); 152 | 153 | Assert.IsTrue(hitChange); 154 | } 155 | 156 | [TestMethod] 157 | public void AlternateDictionary() 158 | { 159 | var target = new ObservableDictionary(new ConcurrentDictionary()); 160 | bool hitChange = false; 161 | const int key = 10; 162 | const string value = "Hello"; 163 | 164 | target.CollectionChanged += (s, e) => 165 | { 166 | hitChange = true; 167 | Assert.AreSame(target, s); 168 | Assert.AreEqual(NotifyCollectionChangedAction.Add, e.Action); 169 | var item = (KeyValuePair)e.NewItems[0]; 170 | Assert.AreEqual(key, item.Key); 171 | Assert.AreEqual(value, item.Value); 172 | }; 173 | 174 | target[key] = value; 175 | Assert.IsTrue(hitChange); 176 | } 177 | 178 | [TestMethod] 179 | public void MassUpdateTest() 180 | { 181 | var target = new ObservableDictionary(); 182 | 183 | bool hitChange = false; 184 | 185 | target.CollectionChanged += (s, e) => 186 | { 187 | hitChange = true; 188 | }; 189 | 190 | using (target.BeginMassUpdate()) 191 | { 192 | target[1] = "Hello"; 193 | target[2] = "World"; 194 | target[3] = "Testing.."; 195 | 196 | Assert.IsFalse(hitChange); 197 | } 198 | 199 | Assert.IsTrue(hitChange); 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure.Tests/XamU.Infrastructure.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure.Tests/XamUInfrastructureTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using XamarinUniversity.Infrastructure; 6 | using XamarinUniversity.Services; 7 | 8 | namespace XamU.Infrastructure.Tests 9 | { 10 | [TestClass] 11 | public class XamUInfrastructureTests 12 | { 13 | [TestInitialize] 14 | public void Reset() 15 | { 16 | // Reset private field. 17 | XamUInfrastructure.Reset(); 18 | } 19 | 20 | [TestMethod] 21 | public void CheckThatDefaultDependencyServiceSetsServiceLocator() 22 | { 23 | var ds = XamUInfrastructure.Init(); 24 | Assert.IsNotNull(XamUInfrastructure.ServiceLocator); 25 | Assert.AreSame(ds, XamUInfrastructure.ServiceLocator); 26 | } 27 | 28 | [TestMethod] 29 | public void CheckThatSuppliedDependencyServiceSetsServiceLocator() 30 | { 31 | var ds1 = new MockDependencService(); 32 | var ds2 = XamUInfrastructure.Init(ds1); 33 | Assert.IsNotNull(XamUInfrastructure.ServiceLocator); 34 | Assert.AreSame(ds1, ds2); 35 | } 36 | 37 | [TestMethod] 38 | public void RegisterNavigationAddsBothInterfaces() 39 | { 40 | var mds = new MockDependencService(); 41 | var sl = XamUInfrastructure.Init(mds, RegisterBehavior.Navigation); 42 | 43 | Assert.IsTrue(mds.HasType(typeof(INavigationPageService))); 44 | Assert.IsTrue(mds.HasType(typeof(INavigationService))); 45 | Assert.IsFalse(mds.HasType(typeof(IMessageVisualizerService))); 46 | Assert.IsTrue(mds.HasType(typeof(IDependencyService))); 47 | } 48 | 49 | [TestMethod] 50 | public void RegisterVisualizaerAddsInterface() 51 | { 52 | var mds = new MockDependencService(); 53 | var sl = XamUInfrastructure.Init(mds, RegisterBehavior.MessageVisualizer); 54 | 55 | Assert.IsFalse(mds.HasType(typeof(INavigationPageService))); 56 | Assert.IsFalse(mds.HasType(typeof(INavigationService))); 57 | Assert.IsTrue(mds.HasType(typeof(IMessageVisualizerService))); 58 | Assert.IsTrue(mds.HasType(typeof(IDependencyService))); 59 | } 60 | 61 | [TestMethod] 62 | public void CheckThatUsingServiceLocatorBeforeInitThrowsException() 63 | { 64 | var sl = XamUInfrastructure.ServiceLocator; 65 | Assert.IsNotNull(sl); 66 | Assert.IsNotNull(XamUInfrastructure.ServiceLocator); 67 | Assert.ThrowsException(() => XamUInfrastructure.Init(new MockDependencService())); 68 | } 69 | 70 | [TestMethod] 71 | public void AllowMultipleInitCalls() 72 | { 73 | var ds = XamUInfrastructure.Init(); 74 | var ds2 = XamUInfrastructure.Init(); 75 | Assert.AreSame(ds,ds2); 76 | } 77 | 78 | class MockDependencService : IDependencyService 79 | { 80 | readonly List registeredTypes = new List(); 81 | 82 | public bool HasType(Type type) 83 | { 84 | return registeredTypes.Contains(type); 85 | } 86 | 87 | public void Register() where T : class, new() 88 | { 89 | registeredTypes.Add(typeof(T)); 90 | } 91 | 92 | public void Register() where T : class where TImpl : class, T, new() 93 | { 94 | registeredTypes.Add(typeof(T)); 95 | } 96 | 97 | public void Register(T impl) where T : class 98 | { 99 | registeredTypes.Add(typeof(T)); 100 | } 101 | 102 | public T Get() where T : class 103 | { 104 | throw new NotImplementedException(); 105 | } 106 | 107 | public T Get(DependencyScope scope) where T : class 108 | { 109 | throw new NotImplementedException(); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.27703.2000 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XamU.Infrastructure", "XamU.Infrastructure\XamU.Infrastructure.csproj", "{67F9D3A8-F71E-4428-913F-C37AE82CDB24}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XamU.Core", "XamU.Core\XamU.Core.csproj", "{8F2F8275-08CE-4884-8BFA-F059EEE2BB1C}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamU.Infrastructure.Tests", "XamU.Infrastructure.Tests\XamU.Infrastructure.Tests.csproj", "{E039844A-C9D4-4FC7-9CB3-05BBA10F9C6F}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {E039844A-C9D4-4FC7-9CB3-05BBA10F9C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {E039844A-C9D4-4FC7-9CB3-05BBA10F9C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {E039844A-C9D4-4FC7-9CB3-05BBA10F9C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {E039844A-C9D4-4FC7-9CB3-05BBA10F9C6F}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {BDE61DED-8003-40AB-949A-4ECABC0F66CE} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Behaviors/BindingContextBehavior.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BindingContextBehavior.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | using System.Diagnostics; 30 | 31 | namespace XamarinUniversity.Infrastructure 32 | { 33 | /// 34 | /// Provides a Behavior(Of T) which forwards the associated object's binding 35 | /// context to the behavior. This is NOT done by default because behaviors can 36 | /// be shared if they are applied using a Style. In that case, there is not 37 | /// a 1:1 relationship. This enforces the 1:1 relationship but disallows the 38 | /// application via a shared resource. 39 | /// 40 | public class BindingContextBehavior : Behavior where T : BindableObject 41 | { 42 | /// 43 | /// True if the binding context is being forwarded. 44 | /// 45 | bool bindingContextForwarded; 46 | 47 | /// 48 | /// The single object this behavior is bound to. 49 | /// 50 | /// The associated object. 51 | protected T AssociatedObject { get; set; } 52 | 53 | /// 54 | /// Called when the behavior is attached to an object. 55 | /// 56 | /// Bindable. 57 | protected override void OnAttachedTo (T bindable) 58 | { 59 | // Disallow sharing of the behavior since we are associating 60 | // to a single object and it's binding context. 61 | if (AssociatedObject != null) { 62 | throw new Exception (GetType () + " behaviors cannot be shared or used in a Style setter."); 63 | } 64 | 65 | base.OnAttachedTo (bindable); 66 | AssociatedObject = bindable; 67 | 68 | if (BindingContext == null) { 69 | bindingContextForwarded = true; 70 | BindingContext = bindable.BindingContext; 71 | bindable.BindingContextChanged += OnAssociatedBindingContextChanged; 72 | } 73 | } 74 | 75 | /// 76 | /// Called when this behavior is being detached from a bindable object. 77 | /// 78 | /// Bindable. 79 | protected override void OnDetachingFrom (T bindable) 80 | { 81 | Debug.Assert (AssociatedObject == bindable); 82 | base.OnDetachingFrom (bindable); 83 | AssociatedObject = null; 84 | if (bindingContextForwarded) { 85 | bindable.BindingContextChanged -= OnAssociatedBindingContextChanged; 86 | BindingContext = null; 87 | } 88 | } 89 | 90 | /// 91 | /// Raised when our associated object's BindingContext changes. 92 | /// 93 | /// Sender. 94 | /// E. 95 | void OnAssociatedBindingContextChanged (object sender, EventArgs e) 96 | { 97 | Debug.Assert (AssociatedObject == sender); 98 | Debug.Assert (bindingContextForwarded == true); 99 | this.BindingContext = ((BindableObject)sender).BindingContext; 100 | } 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Behaviors/EffectBehavior.cs: -------------------------------------------------------------------------------- 1 | // 2 | // EffectBehavior.cs 3 | // 4 | // Author: 5 | // David Britch 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using Xamarin.Forms; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// This behavior adds an Effect instance to a control when the behavior is attached to the control, 33 | /// and removes the Effect instance when the behavior is detached from the control. 34 | /// 35 | /// 36 | /// 43 | /// 44 | public class EffectBehavior : Behavior 45 | { 46 | /// 47 | /// Bindable property for the ResolutionGroupName attribute of the Effect. 48 | /// 49 | public static readonly BindableProperty GroupProperty = BindableProperty.Create("Group", typeof(string), typeof(EffectBehavior), null); 50 | 51 | /// 52 | /// Bindable property for the ExportEffect attribute of the Effect. 53 | /// 54 | public static readonly BindableProperty NameProperty = BindableProperty.Create("Name", typeof(string), typeof(EffectBehavior), null); 55 | 56 | /// 57 | /// The group name of the Effect 58 | /// 59 | /// The ResolutionGroupName value of the Effect. 60 | public string Group 61 | { 62 | get { return (string)GetValue(GroupProperty); } 63 | set { SetValue(GroupProperty, value); } 64 | } 65 | 66 | /// 67 | /// The name of the Effect. 68 | /// 69 | /// The ExportEffect value of the Effect. 70 | public string Name 71 | { 72 | get { return (string)GetValue(NameProperty); } 73 | set { SetValue(NameProperty, value); } 74 | } 75 | 76 | /// 77 | /// Called when the behavior is attached to an element. 78 | /// 79 | /// The attached object. 80 | protected override void OnAttachedTo(BindableObject bindable) 81 | { 82 | base.OnAttachedTo(bindable); 83 | AddEffect(bindable as View); 84 | } 85 | 86 | /// 87 | /// Called when the behavior is being removed from an element. 88 | /// 89 | /// The object being detached from. 90 | protected override void OnDetachingFrom(BindableObject bindable) 91 | { 92 | RemoveEffect(bindable as View); 93 | base.OnDetachingFrom(bindable); 94 | } 95 | 96 | /// 97 | /// Adds the Effect to the element's Effects collection. 98 | /// 99 | /// The View to add the Effect to. 100 | void AddEffect(View view) 101 | { 102 | var effect = GetEffect(); 103 | if (effect != null) 104 | { 105 | view.Effects.Add(GetEffect()); 106 | } 107 | } 108 | 109 | /// 110 | /// Removes the Effect from the element's Effects collection. 111 | /// 112 | /// The View to remove the Effect from. 113 | void RemoveEffect(View view) 114 | { 115 | var effect = GetEffect(); 116 | if (effect != null) 117 | { 118 | view.Effects.Remove(GetEffect()); 119 | } 120 | } 121 | 122 | /// 123 | /// Resolves the Effect to be added to an element. 124 | /// 125 | /// The resolved Effect. 126 | Effect GetEffect() 127 | { 128 | if (!string.IsNullOrWhiteSpace(Group) && !string.IsNullOrWhiteSpace(Name)) 129 | { 130 | return Effect.Resolve(string.Format("{0}.{1}", Group, Name)); 131 | } 132 | return null; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Behaviors/NumericValidationBehavior.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NumericValidationBehavior.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using Xamarin.Forms; 28 | 29 | namespace XamarinUniversity.Infrastructure 30 | { 31 | /// 32 | /// A custom behavior for the Xamarin.Forms Entry control to 33 | /// restrict the input to be numeric only in the form of a double or integer. 34 | /// 35 | public class NumericValidationBehavior : Behavior 36 | { 37 | #region AllowDecimalProperty 38 | /// 39 | /// Backing storage for the boolean flag which decides between 40 | /// integer vs. double validation. 41 | /// 42 | public static BindableProperty AllowDecimalProperty = BindableProperty.Create ( 43 | nameof(AllowDecimal), 44 | typeof (bool), typeof (NumericValidationBehavior), 45 | true, BindingMode.OneWay); 46 | 47 | /// 48 | /// Bindable property to hold the boolean flag which decides 49 | /// whether we test for integer vs. double values. 50 | /// 51 | /// The selected item. 52 | public bool AllowDecimal { 53 | get { return (bool)base.GetValue (AllowDecimalProperty); } 54 | set { base.SetValue (AllowDecimalProperty, value); } 55 | } 56 | #endregion 57 | 58 | 59 | #region InvalidColorProperty 60 | /// 61 | /// Backing storage for the color used when the 62 | /// Entry has invalid data (non-numeric). 63 | /// 64 | public static BindableProperty InvalidColorProperty = BindableProperty.Create ( 65 | nameof(InvalidColor), 66 | typeof (Color), typeof (NumericValidationBehavior), 67 | Color.Red, BindingMode.OneWay); 68 | 69 | /// 70 | /// Bindable property to hold the color used when the 71 | /// Entry has invalid data (non-numeric). 72 | /// 73 | /// The selected item. 74 | public Color InvalidColor { 75 | get { return (Color)GetValue(InvalidColorProperty); } 76 | set { base.SetValue (InvalidColorProperty, value); } 77 | } 78 | #endregion 79 | 80 | /// 81 | /// Called when this behavior is attached to a visual. 82 | /// 83 | /// Visual owner 84 | protected override void OnAttachedTo(Entry bindable) 85 | { 86 | base.OnAttachedTo(bindable); 87 | bindable.TextChanged += OnEntryTextChanged; 88 | } 89 | 90 | /// 91 | /// Called when this behavior is detached from a visual 92 | /// 93 | /// Visual owner 94 | protected override void OnDetachingFrom(Entry bindable) 95 | { 96 | base.OnDetachingFrom(bindable); 97 | bindable.TextChanged -= OnEntryTextChanged; 98 | } 99 | 100 | /// 101 | /// Called when the associated Entry has new text. 102 | /// This changes the text color to reflect whether the data 103 | /// is valid. 104 | /// 105 | /// Entry control 106 | /// TextChanged event arguments 107 | void OnEntryTextChanged(object sender, TextChangedEventArgs args) 108 | { 109 | bool isValid = false; 110 | if (AllowDecimal) 111 | { 112 | isValid = double.TryParse(args.NewTextValue, out double result); 113 | } 114 | else 115 | { 116 | isValid = long.TryParse(args.NewTextValue, out long result); 117 | } 118 | 119 | ((Entry)sender).TextColor = isValid ? Color.Default : InvalidColor; 120 | } 121 | }} 122 | 123 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Commands/NavigateBackCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NavigateBackCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Windows.Input; 29 | using XamarinUniversity.Infrastructure; 30 | using XamarinUniversity.Services; 31 | 32 | namespace XamarinUniversity.Commands 33 | { 34 | /// 35 | /// This command uses the registered INavigationService to perform 36 | /// a backwards navigation. 37 | /// 38 | public class NavigateBackCommand : ICommand 39 | { 40 | bool monitorNavigationStack; 41 | 42 | /// 43 | /// Protected ctor - only allow library to create command 44 | /// unless you derive from it. Should alway use NavigationCommands. 45 | /// 46 | protected internal NavigateBackCommand () 47 | { 48 | } 49 | 50 | /// 51 | /// True/False to monitor the enavigation and raise our CanExecuteChanged 52 | /// in response. 53 | /// 54 | public bool MonitorNavigationStack 55 | { 56 | get => monitorNavigationStack; 57 | 58 | set 59 | { 60 | monitorNavigationStack = value; 61 | 62 | var ns = XamUInfrastructure.ServiceLocator.Get (); 63 | if (ns != null) { 64 | // Always unsubscribe to ensure we are never > 1. 65 | ns.Navigated -= OnUpdateCanExecuteChanged; 66 | ns.NavigatedBack -= OnUpdateCanExecuteChanged; 67 | 68 | if (monitorNavigationStack) { 69 | ns.Navigated += OnUpdateCanExecuteChanged; 70 | ns.NavigatedBack += OnUpdateCanExecuteChanged; 71 | } 72 | } 73 | } 74 | } 75 | 76 | /// 77 | /// Event raised when the state of the NavigateBackCommand has changed. 78 | /// 79 | public event EventHandler CanExecuteChanged; 80 | 81 | /// 82 | /// This is called when the navigation stack has changed. 83 | /// It refreshes the state of the command. 84 | /// 85 | /// this 86 | /// Empty EventArgs 87 | void OnUpdateCanExecuteChanged (object sender, EventArgs e) 88 | { 89 | CanExecuteChanged?.Invoke (this, EventArgs.Empty); 90 | } 91 | 92 | /// 93 | /// This is called to determine whether the command can be executed. 94 | /// We use the current navigation stack state. 95 | /// 96 | /// True if the command is valid 97 | /// Parameter. 98 | public bool CanExecute (object parameter) 99 | { 100 | var ns = XamUInfrastructure.ServiceLocator.Get (); 101 | return ns?.CanGoBack == true; 102 | } 103 | 104 | /// 105 | /// This is called to execute the command. 106 | /// 107 | /// Not used 108 | public async void Execute (object parameter) 109 | { 110 | var ns = XamUInfrastructure.ServiceLocator.Get (); 111 | if (ns != null) { 112 | await ns.GoBackAsync().ConfigureAwait(false); 113 | } 114 | } 115 | } 116 | } 117 | 118 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Commands/NavigateToCommand.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NavigateToCommand.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Windows.Input; 29 | using XamarinUniversity.Infrastructure; 30 | using XamarinUniversity.Services; 31 | 32 | namespace XamarinUniversity.Commands 33 | { 34 | /// 35 | /// This class implements an ICommand which will use the registered INavigationService 36 | /// to perform a NavigateAsync to a specific page 37 | /// 38 | public class NavigateToCommand : ICommand 39 | { 40 | /// 41 | /// Protected ctor - only allow library to create command 42 | /// unless you derive from it. Should alway use NavigationCommands. 43 | /// 44 | protected internal NavigateToCommand () 45 | { 46 | } 47 | 48 | /// 49 | /// Event raised when the state of the NavigateBackCommand has changed. 50 | /// 51 | #pragma warning disable 67 52 | public event EventHandler CanExecuteChanged; 53 | #pragma warning restore 67 54 | 55 | /// 56 | /// This is called to determine whether the command can be executed. 57 | /// 58 | /// True if the command is valid 59 | /// PageKey to navigate to 60 | public bool CanExecute (object parameter) 61 | { 62 | // Must have a page key. 63 | return parameter != null; 64 | } 65 | 66 | /// 67 | /// This is called to execute the command. 68 | /// 69 | /// Page Key to navigate to 70 | public async void Execute (object parameter) 71 | { 72 | if (parameter != null) 73 | { 74 | var ns = XamUInfrastructure.ServiceLocator.Get (); 75 | if (ns != null) { 76 | await ns.NavigateAsync (parameter).ConfigureAwait(false); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Commands/NavigationCommands.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationCommands.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | namespace XamarinUniversity.Commands 28 | { 29 | /// 30 | /// Commands which perform common navigation 31 | /// 32 | public static class NavigationCommands 33 | { 34 | /// 35 | /// Field to hold back nav command 36 | /// 37 | static NavigateBackCommand navBackCommand; 38 | 39 | /// 40 | /// A command which performs a NavigationService.GoBack 41 | /// 42 | public static NavigateBackCommand GoBack => (navBackCommand != null) 43 | ? navBackCommand 44 | : (navBackCommand = new NavigateBackCommand ()); 45 | 46 | /// 47 | /// Field to hold fwd nav command 48 | /// 49 | static NavigateToCommand navToCommand; 50 | 51 | /// 52 | /// A command which performs a NavigationService.Navigate 53 | /// 54 | public static NavigateToCommand NavigateTo => (navToCommand != null) 55 | ? navToCommand 56 | : (navToCommand = new NavigateToCommand ()); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/BooleanToColorConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BooleanToColorConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Globalization; 30 | using System.Text; 31 | using Xamarin.Forms; 32 | using Xamarin.Forms.Xaml; 33 | 34 | namespace XamarinUniversity.Converters 35 | { 36 | /// 37 | /// This converter converts a boolean (true/false) value into a specific 38 | /// color. 39 | /// 40 | public class BooleanToColorConverter : IValueConverter, IMarkupExtension 41 | { 42 | /// 43 | /// The color to use for TRUE 44 | /// 45 | public Color TrueColor { get; set; } 46 | 47 | /// 48 | /// The color to use for FALSE 49 | /// 50 | public Color FalseColor { get; set; } 51 | 52 | /// 53 | /// Constructor - sets the initial colors. 54 | /// 55 | public BooleanToColorConverter() 56 | { 57 | TrueColor = Color.Black; 58 | FalseColor = Color.LightGray; 59 | } 60 | 61 | /// 62 | /// Convert a boolean into a Color value 63 | /// 64 | /// Boolean value 65 | /// Returning color 66 | /// Parameter (not used) 67 | /// Culture (not used) 68 | /// 69 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 70 | { 71 | if (targetType != typeof(Color)) 72 | throw new Exception($"{nameof(BooleanToColorConverter)} can only be used with a Color target."); 73 | 74 | return (value as bool? ?? false) ? TrueColor : FalseColor; 75 | } 76 | 77 | /// 78 | /// ConvertBack (not supported) 79 | /// 80 | /// Color 81 | /// Boolean 82 | /// Optional parameter (not used) 83 | /// Culture (not used) 84 | /// 85 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 86 | { 87 | Color color = (Color)value; 88 | return (color == TrueColor) ? true : false; 89 | } 90 | 91 | /// 92 | /// Returns an instance of the ValueConverter as an inline element. 93 | /// 94 | /// Service Provider for XAML services 95 | /// Value Converter 96 | public object ProvideValue(IServiceProvider serviceProvider) 97 | { 98 | return this; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/BooleanToImageSourceConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // BooleanToImageSourceConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Globalization; 30 | using System.Reflection; 31 | using System.Text; 32 | using Xamarin.Forms; 33 | 34 | namespace XamarinUniversity.Converters 35 | { 36 | /// 37 | /// Image source type (file, URL, or resource) 38 | /// 39 | public enum ImageSourceType 40 | { 41 | /// 42 | /// Image is a Filename 43 | /// 44 | File, 45 | /// 46 | /// Image is stored as an EmbeddedResource 47 | /// 48 | Resource, 49 | /// 50 | /// Image is a URL 51 | /// 52 | Uri 53 | } 54 | 55 | /// 56 | /// Converter to take a Boolean (true/false) value and turn it into an ImageSource 57 | /// 58 | public class BooleanToImageSourceConverter : IValueConverter 59 | { 60 | /// 61 | /// Source type (file, URL, or resource); defaults to FILE 62 | /// 63 | public ImageSourceType SourceType { get; set; } 64 | 65 | /// 66 | /// Image to use when value is TRUE 67 | /// 68 | public string TrueImageSource { get; set; } 69 | 70 | /// 71 | /// Image to use when value if FALSE 72 | /// 73 | public string FalseImageSource { get; set; } 74 | 75 | /// 76 | /// Prefix to prepend to the ImageSource id (e.g. assembly + namespace + folder) 77 | /// Leave empty if the bound property specifies the full resource ID/URL/filename 78 | /// 79 | public string Prefix { get; set; } 80 | 81 | /// 82 | /// A type in the same assembly as the image. This 83 | /// is a required property if the type is a resource and 84 | /// you are in a UWP application and using .NET Native 85 | /// 86 | /// The assembly. 87 | public Type ResolvingType { get; set; } 88 | 89 | /// 90 | /// Constructor 91 | /// 92 | public BooleanToImageSourceConverter() 93 | { 94 | SourceType = ImageSourceType.File; 95 | } 96 | 97 | /// 98 | /// Convert a boolean into an ImageSource 99 | /// 100 | /// Boolean value 101 | /// Returning image source 102 | /// Parameter (not used) 103 | /// Culture (not used) 104 | /// 105 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 106 | { 107 | if (targetType != typeof(ImageSource)) 108 | throw new Exception($"{nameof(BooleanToImageSourceConverter)} can only be used with an ImageSource target."); 109 | 110 | string id = (value as bool? ?? false) ? TrueImageSource : FalseImageSource; 111 | if (!string.IsNullOrEmpty(id)) 112 | { 113 | if (!string.IsNullOrWhiteSpace(Prefix)) 114 | { 115 | id = Prefix + id; 116 | } 117 | 118 | if (SourceType == ImageSourceType.Uri) 119 | { 120 | return ImageSource.FromUri(new Uri(id)); 121 | } 122 | else if (SourceType == ImageSourceType.File) 123 | { 124 | return ImageSource.FromFile(id); 125 | } 126 | else 127 | { 128 | if (ResolvingType != null) 129 | { 130 | return ImageSource.FromResource(id, ResolvingType); 131 | } 132 | else 133 | { 134 | // Use the MainPage assembly. 135 | return ImageSource.FromResource(id, Application.Current.MainPage?.GetType().GetTypeInfo().Assembly); 136 | } 137 | } 138 | } 139 | 140 | return null; 141 | } 142 | 143 | /// 144 | /// ConvertBack (not supported) 145 | /// 146 | /// ImageSource 147 | /// Boolean 148 | /// Optional parameter (not used) 149 | /// Culture (not used) 150 | /// 151 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 152 | { 153 | throw new NotImplementedException(); 154 | } 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/DebugConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DebugConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #define DEBUG 28 | using System; 29 | using System.Diagnostics; 30 | using Xamarin.Forms; 31 | using Xamarin.Forms.Xaml; 32 | 33 | namespace XamarinUniversity.Converters 34 | { 35 | /// 36 | /// This provides a debugging output for a binding converter 37 | /// 38 | public class DebugConverter : IValueConverter, IMarkupExtension 39 | { 40 | /// 41 | /// Outputs all parameters to the debug console. 42 | /// 43 | /// 44 | /// A converted value. If the method returns null, the valid null value is used. 45 | /// 46 | /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. 47 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 48 | { 49 | Debug.WriteLine(string.Format(culture, "Convert: Value={0}, TargetType={1}, Parameter={2}, Culture={3}", 50 | value, targetType, parameter, culture)); 51 | return value; 52 | } 53 | 54 | /// 55 | /// Converts a value. 56 | /// 57 | /// 58 | /// A converted value. If the method returns null, the valid null value is used. 59 | /// 60 | /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. 61 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 62 | { 63 | Debug.WriteLine(string.Format(culture, "ConvertBack: Value={0}, TargetType={1}, Parameter={2}, Culture={3}", 64 | value, targetType, parameter, culture)); 65 | return value; 66 | } 67 | 68 | /// 69 | /// Returns the converter 70 | /// 71 | /// 72 | /// 73 | public object ProvideValue(IServiceProvider serviceProvider) 74 | { 75 | Debug.WriteLine("Creating DebugConverter()"); 76 | return this; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/EventArgsConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // EventArgsConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Globalization; 29 | using System.Reflection; 30 | using Xamarin.Forms; 31 | 32 | namespace XamarinUniversity.Converters 33 | { 34 | /// 35 | /// This is a converter which can be used with the EventToCommandBehavior to 36 | /// retrieve a single property or field from an EventArgs class coming from 37 | /// an event to then pass into an ICommand as the parameter. 38 | /// 39 | /// 40 | /// 51 | /// 52 | public class EventArgsConverter : IValueConverter 53 | { 54 | /// 55 | /// The property (or field) to retrieve; must be public and 56 | /// use exact casing. 57 | /// 58 | /// The name of the property. 59 | public string PropertyName { get; set; } 60 | 61 | /// 62 | /// Takes the EventArgs passed in the 'parameter' and pulls a single 63 | /// property or field value from it as the return value. 64 | /// 65 | /// Property or field value 66 | /// Event sender 67 | /// Expected target type 68 | /// EventArgs from event 69 | /// UI culture 70 | public object Convert (object value, Type targetType, object parameter, CultureInfo culture) 71 | { 72 | // Do some validation checks up front. 73 | if (parameter == null) 74 | return null; 75 | if (string.IsNullOrEmpty (PropertyName)) 76 | throw new ArgumentNullException (nameof (PropertyName), $"{nameof (PropertyName)} must be set"); 77 | 78 | var theType = parameter.GetType ().GetTypeInfo (); 79 | 80 | // Look for a public property first. 81 | var pi = theType.GetDeclaredProperty (PropertyName); 82 | if (pi != null) 83 | return pi.GetValue (parameter); 84 | 85 | // Not found - see if it's a public field. This is unusual, but 86 | // sometimes done on EventArgs types. 87 | var fi = theType.GetDeclaredField (PropertyName); 88 | if (fi == null) 89 | throw new ArgumentException ($"{nameof (PropertyName)} not found on {value.GetType ()}"); 90 | 91 | return fi.GetValue (parameter); 92 | } 93 | 94 | /// 95 | /// Used to convert the value back from source > tatget. Not used with this converter 96 | /// 97 | /// Exceptiopn 98 | /// sender of the event 99 | /// Expected target type 100 | /// Event Args value 101 | /// UI culture 102 | public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture) 103 | { 104 | throw new NotImplementedException (); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/ImageResourceConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ImageResourceConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | using Xamarin.Forms.Xaml; 30 | 31 | namespace XamarinUniversity.Converters 32 | { 33 | /// 34 | /// A custom IValueConverter which can be used with a {Binding} to convert 35 | /// a View Model string-based property into an ImageSource when the image 36 | /// is stored as an embedded resource. If you are not using a binding, then 37 | /// you can use the ImageResourceExtension to load an embedded resource. 38 | /// 39 | public class ImageResourceConverter : IValueConverter, IMarkupExtension 40 | { 41 | /// 42 | /// Prefix to prepend to the Resource ID (e.g. assembly + namespace + folder) 43 | /// Leave empty if the bound property specifies the full resource ID. 44 | /// 45 | public string Prefix { get; set; } 46 | 47 | /// 48 | /// A type in the same assembly as the image. This 49 | /// is a required property set if you are in a UWP application 50 | /// and using .NET Native 51 | /// 52 | /// The assembly. 53 | public Type ResolvingType { get; set; } 54 | 55 | /// 56 | /// Convert a string-based value into an embedded resource 57 | /// 58 | /// Resource ID 59 | /// ImageSource 60 | /// Optional prefix 61 | /// Culture 62 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 63 | { 64 | if (targetType != typeof (ImageSource)) 65 | throw new ArgumentException ("ImageResourceConverter should only be used with Image.Source"); 66 | 67 | string resourceId = (value ?? "").ToString (); 68 | if (string.IsNullOrEmpty (resourceId)) 69 | return null; 70 | 71 | string prefix; 72 | prefix = parameter != null 73 | ? parameter.ToString () 74 | : Prefix != null 75 | ? Prefix : ""; 76 | if (!string.IsNullOrEmpty (prefix) 77 | && !prefix.EndsWith (".", StringComparison.Ordinal)) 78 | prefix += "."; 79 | 80 | return ResolvingType != null 81 | ? ImageSource.FromResource (prefix + resourceId, ResolvingType) 82 | : ImageSource.FromResource (prefix + resourceId); 83 | } 84 | 85 | /// 86 | /// Used to convert a value from target > source; not used for this converter. 87 | /// 88 | /// Converted value 89 | /// Value. 90 | /// Target type. 91 | /// Optional parameter 92 | /// Culture. 93 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 94 | { 95 | throw new NotSupportedException(); 96 | } 97 | 98 | /// 99 | /// Allows the value converter to be created inline; note that it is not 100 | /// shared if you use this approach. 101 | /// 102 | /// The Value Converter 103 | /// Service provider. 104 | public object ProvideValue (IServiceProvider serviceProvider) 105 | { 106 | return this; 107 | } 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/IntegerToBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // IntegerToBooleanConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | using Xamarin.Forms.Xaml; 30 | 31 | namespace XamarinUniversity.Converters 32 | { 33 | /// 34 | /// Converts an integer value into a boolean true/false 35 | /// 36 | public class IntegerToBooleanConverter : IMarkupExtension, IValueConverter 37 | { 38 | /// 39 | /// Boolean value for zero; defaults to false. 40 | /// 41 | public bool ZeroOrNull { get; set; } 42 | 43 | /// 44 | /// Boolean value for one; defaults to true. 45 | /// 46 | public bool One { get; set; } 47 | 48 | /// 49 | /// Boolean value for non-zero; defaults to true. 50 | /// 51 | public bool Positive { get; set; } 52 | 53 | /// 54 | /// Boolean value for negative treqtment; defaults to false. 55 | /// 56 | /// true if negative treatment; otherwise, false. 57 | public bool Negative { get; set; } 58 | 59 | /// 60 | /// Constructor 61 | /// 62 | public IntegerToBooleanConverter() 63 | { 64 | Positive = true; 65 | One = true; 66 | ZeroOrNull = false; 67 | Negative = false; 68 | } 69 | 70 | #region IValueConverter Members 71 | 72 | /// 73 | /// Converts a value. 74 | /// 75 | /// 76 | /// A converted value. If the method returns null, the valid null value is used. 77 | /// 78 | /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. 79 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 80 | { 81 | if (value == null) 82 | return ZeroOrNull; 83 | 84 | int result = System.Convert.ToInt32 (value, culture); 85 | 86 | return result < 0 ? Negative 87 | : result == 0 ? ZeroOrNull 88 | : result == 1 ? One : Positive; 89 | } 90 | 91 | /// 92 | /// Converts a value. 93 | /// 94 | /// 95 | /// A converted value. If the method returns null, the valid null value is used. 96 | /// 97 | /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. 98 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 99 | { 100 | throw new NotImplementedException(); 101 | } 102 | 103 | #endregion 104 | 105 | /// 106 | /// Returns the converter 107 | /// 108 | /// 109 | /// 110 | public object ProvideValue(IServiceProvider serviceProvider) 111 | { 112 | return this; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/NotBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NotBooleanConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Globalization; 29 | using Xamarin.Forms; 30 | using Xamarin.Forms.Xaml; 31 | 32 | namespace XamarinUniversity.Converters 33 | { 34 | /// 35 | /// This converter reverses a Boolean value (True == False, False == True). 36 | /// 37 | public class NotBooleanConverter : IMarkupExtension, IValueConverter 38 | { 39 | /// 40 | /// Converts a value. 41 | /// 42 | /// 43 | /// A converted value. If the method returns null, the valid null value is used. 44 | /// 45 | /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. 46 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 47 | { 48 | if (targetType != typeof (bool)) 49 | throw new ArgumentException ("Bad type conversion for NotBooleanConverter"); 50 | 51 | bool flag = false; 52 | if (value != null && value is bool) 53 | { 54 | flag = (bool)value; 55 | } 56 | return !flag; 57 | } 58 | 59 | /// 60 | /// Converts a value. 61 | /// 62 | /// 63 | /// A converted value. If the method returns null, the valid null value is used. 64 | /// 65 | /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. 66 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 67 | { 68 | return Convert(value, targetType, parameter, culture); 69 | } 70 | 71 | /// 72 | /// Returns the converter 73 | /// 74 | /// 75 | /// 76 | public object ProvideValue(IServiceProvider serviceProvider) 77 | { 78 | return this; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/NullOrEmptyBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NullOrEmptyBooleanConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Globalization; 29 | using Xamarin.Forms; 30 | using Xamarin.Forms.Xaml; 31 | 32 | namespace XamarinUniversity.Converters 33 | { 34 | /// 35 | /// This converts an object value to a boolean 36 | /// 37 | public class NullOrEmptyBooleanConverter : IMarkupExtension, IValueConverter 38 | { 39 | /// 40 | /// Mapping value for null - defaults to false. 41 | /// 42 | public bool Null { get; set; } 43 | /// 44 | /// Mapping value for empty - defaults to false. 45 | /// 46 | public bool Empty { get; set; } 47 | /// 48 | /// Mapping value for non-null, defaults to true. 49 | /// 50 | public bool NotEmpty { get; set; } 51 | 52 | /// 53 | /// Constructor 54 | /// 55 | public NullOrEmptyBooleanConverter() 56 | { 57 | Empty = false; 58 | Null = false; 59 | NotEmpty = true; 60 | } 61 | 62 | /// 63 | /// Converts a value. 64 | /// 65 | /// 66 | /// A converted value. If the method returns null, the valid null value is used. 67 | /// 68 | /// The value produced by the binding source.The type of the binding target property.The converter parameter to use.The culture to use in the converter. 69 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 70 | { 71 | if (targetType != typeof(bool)) 72 | throw new ArgumentException("Bad type conversion for NullOrEmptyBooleanConverter"); 73 | 74 | return value == null ? Null 75 | : string.IsNullOrEmpty((value ?? "").ToString()) ? Empty : NotEmpty; 76 | } 77 | 78 | /// 79 | /// Converts a value. 80 | /// 81 | /// 82 | /// A converted value. If the method returns null, the valid null value is used. 83 | /// 84 | /// The value that is produced by the binding target.The type to convert to.The converter parameter to use.The culture to use in the converter. 85 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 86 | { 87 | throw new NotImplementedException(); 88 | } 89 | 90 | /// 91 | /// Returns the converter 92 | /// 93 | /// 94 | /// 95 | public object ProvideValue(IServiceProvider serviceProvider) 96 | { 97 | return this; 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Converters/StreamToImageSourceConverter.cs: -------------------------------------------------------------------------------- 1 | // 2 | // StreamToImageSourceConverter.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Globalization; 30 | using System.IO; 31 | using System.Text; 32 | using Xamarin.Forms; 33 | using Xamarin.Forms.Xaml; 34 | 35 | namespace XamarinUniversity.Converters 36 | { 37 | /// 38 | /// Converter that takes an IO.Stream and turns it into an ImageSource. 39 | /// 40 | public class StreamToImageSourceConverter : IValueConverter, IMarkupExtension 41 | { 42 | /// 43 | /// Convert Stream input to an ImageSource output 44 | /// 45 | /// Stream 46 | /// ImageSource type 47 | /// Optional parameter (not used) 48 | /// Culture (not used) 49 | /// ImageSource object wrapped around stream 50 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 51 | { 52 | var stm = value as Stream; 53 | return stm != null ? ImageSource.FromStream(() => stm) : null; 54 | } 55 | 56 | /// 57 | /// Convert ImageSource back to stream (not supported) 58 | /// 59 | /// ImageSource 60 | /// Stream type 61 | /// Optional parameter (not used) 62 | /// Culture (not used) 63 | /// ImageSource object wrapped around stream 64 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 65 | { 66 | throw new NotImplementedException(); 67 | } 68 | 69 | /// 70 | /// Allows value converter to be used inline. 71 | /// 72 | /// Service Provider interface 73 | /// Value Converter 74 | public object ProvideValue(IServiceProvider serviceProvider) 75 | { 76 | return this; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Extensions/ColorExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ColorExtensions.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2017 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using Xamarin.Forms; 28 | using System; 29 | using System.Linq; 30 | using System.Reflection; 31 | 32 | namespace XamarinUniversity.Infrastructure 33 | { 34 | /// 35 | /// Extension methods for the Xamarin.Forms Color type. 36 | /// 37 | public static class ColorExtensions 38 | { 39 | /// 40 | /// Get the name of a given color - either the property or Hex value. 41 | /// This is useful because the default ToString implementation reports 42 | /// the underlying field values. 43 | /// 44 | /// String name 45 | /// Color. 46 | public static string GetName(this Color color) 47 | { 48 | return typeof(Color).GetTypeInfo().DeclaredFields 49 | .FirstOrDefault(c => c.FieldType == typeof(Color) 50 | && ((Color)c.GetValue(null)).Equals(color))?.Name 51 | ?? ToHex(color); 52 | } 53 | 54 | /// 55 | /// Get the hex (#rrggbb) value for a color. 56 | /// 57 | /// String hex value 58 | /// Color. 59 | public static string ToHex(this Color color) 60 | { 61 | return $"#{(int)Math.Floor(color.R * 255):X2}{(int)Math.Floor(color.G * 255):X2}{(int)Math.Floor(color.B * 255):X2}"; 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Extensions/ElementExtensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ElementExtensions.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using Xamarin.Forms; 28 | using System; 29 | using System.Linq; 30 | using System.Reflection; 31 | using System.Collections; 32 | using System.Collections.Generic; 33 | 34 | namespace XamarinUniversity.Infrastructure 35 | { 36 | /// 37 | /// Extension methods for the Xamarin.Forms Element class. 38 | /// 39 | public static class ElementExtensions 40 | { 41 | /// 42 | /// Find a visual ancestor from a point in our tree. 43 | /// 44 | /// The owner. 45 | /// View. 46 | /// The 1st type parameter. 47 | public static T FindOwner (this Element view) where T : Element 48 | { 49 | do { 50 | 51 | if (view is T) 52 | return (T)view; 53 | view = view.Parent; 54 | 55 | } while (view != null); 56 | return default (T); 57 | } 58 | 59 | /// 60 | /// Find resource from a given visual element. 61 | /// Throws an exception if the named resource does not exist. 62 | /// 63 | /// The owner. 64 | /// View. 65 | /// Name of the resource to locate. 66 | /// Type of resource being retrieved 67 | public static T FindResource (this VisualElement view, string name) 68 | { 69 | T resource; 70 | if (!TryFindResource (view, name, out resource)) 71 | throw new Exception ("Resource '" + name + "' not found."); 72 | return resource; 73 | } 74 | 75 | /// 76 | /// Find resource from a given visual element. 77 | /// Returns true if the resource is found, false if not. 78 | /// 79 | /// The owner. 80 | /// View. 81 | /// Name of the resource we are looking for 82 | /// Returned resource 83 | /// The 1st type parameter. 84 | public static bool TryFindResource (this VisualElement view, string name, out T resource) 85 | { 86 | if (view == null) { 87 | var rd = Application.Current?.Resources; 88 | 89 | if (rd != null 90 | && rd.ContainsKey (name)) { 91 | resource = (T)rd [name]; 92 | return true; 93 | } 94 | resource = default (T); 95 | return false; 96 | } 97 | 98 | if (view.Resources != null 99 | && view.Resources.ContainsKey (name)) { 100 | resource = (T)view.Resources [name]; 101 | return true; 102 | } 103 | 104 | return TryFindResource (view.Parent as VisualElement, name, out resource); 105 | } 106 | 107 | /// 108 | /// This walks the Xamarin.Forms logical tree and enumerates an object and any content/children. 109 | /// 110 | /// Starting element 111 | /// Enumerated list of element + children/content 112 | public static IEnumerable EnumerateLogicalTree(this Element parentElement) 113 | { 114 | if (parentElement == null) 115 | yield break; 116 | 117 | // Return the current value. 118 | yield return parentElement; 119 | 120 | Type parentType = parentElement.GetType(); 121 | var props = parentType.GetRuntimeProperties(); 122 | 123 | string contentProperty; 124 | var cpa = parentType.GetTypeInfo().GetCustomAttribute(); 125 | if (cpa != null) 126 | contentProperty = cpa.Name; 127 | else 128 | contentProperty = nameof(ContentPage.Content); 129 | 130 | var contProp = props.SingleOrDefault(w => w.Name == contentProperty); 131 | if (contProp != null) 132 | { 133 | var result = contProp.GetValue(parentElement); 134 | var elementResult = result as Element; 135 | if (elementResult != null) 136 | { 137 | foreach (var vi in EnumerateLogicalTree(elementResult)) 138 | yield return vi; 139 | } 140 | else 141 | { 142 | var enumResult = result as IEnumerable; 143 | if (enumResult != null) 144 | { 145 | foreach (var item in enumResult) 146 | { 147 | if (item is Element) 148 | { 149 | foreach (var vi in EnumerateLogicalTree((Element)item)) 150 | yield return vi; 151 | } 152 | } 153 | } 154 | } 155 | } 156 | } 157 | 158 | } 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Interfaces/INavigationPageService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // INavigationPageService.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Threading.Tasks; 30 | using Xamarin.Forms; 31 | 32 | namespace XamarinUniversity.Infrastructure 33 | { 34 | /// 35 | /// Interface to manage navigation with Forms Pages in the application. 36 | /// 37 | public interface INavigationPageService : INavigationService 38 | { 39 | /// 40 | /// True to hide the master page in MD scenarios when you navigate 41 | /// to a child page. 42 | /// 43 | bool HideMasterPageOnNavigation { get; set; } 44 | 45 | /// 46 | /// Register a page with a navigation key 47 | /// 48 | /// Navigation key 49 | /// Delegate to create the Page 50 | void RegisterPage(object key, Func creator); 51 | 52 | /// 53 | /// Register a page with a navigation key 54 | /// 55 | /// Navigation key 56 | /// Delegate to create the Page 57 | void RegisterPage(object key, Func creator); 58 | } 59 | } -------------------------------------------------------------------------------- /src/XamU.Infrastructure/MarkupExtensions/DependencyServiceExtension.cs: -------------------------------------------------------------------------------- 1 | // 2 | // DependencyServiceExtension.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Linq; 29 | using System.Reflection; 30 | using Xamarin.Forms; 31 | using Xamarin.Forms.Xaml; 32 | using XamarinUniversity.Services; 33 | 34 | namespace XamarinUniversity.Infrastructure 35 | { 36 | /// 37 | /// This markup extension allows XAML to lookup dependencies 38 | /// using the . 39 | /// 40 | /// 41 | /// 42 | /// BindingContext="{DependencyService Type={x:Type someVMType}}" 43 | /// 44 | /// 45 | [ContentProperty("Type")] 46 | public class DependencyServiceExtension : IMarkupExtension 47 | { 48 | /// 49 | /// Fetch target type for 50 | /// 51 | /// The fetch target. 52 | public DependencyScope Scope { get; set; } 53 | 54 | /// 55 | /// Type to retrieve (interface or class) 56 | /// 57 | /// The type. 58 | public Type Type { get; set; } 59 | 60 | /// 61 | /// Initializes the markup extension 62 | /// 63 | public DependencyServiceExtension() 64 | { 65 | // Default is a global instance. 66 | Scope = DependencyScope.Global; 67 | } 68 | 69 | /// 70 | /// Looks up the specified type and returns it to the XAML parser. 71 | /// 72 | /// Retrieved object 73 | /// Service provider. 74 | public object ProvideValue(IServiceProvider serviceProvider) 75 | { 76 | if (Type == null) 77 | throw new InvalidOperationException("Type argument mandatory for DependencyService extension."); 78 | 79 | var ds = XamUInfrastructure.ServiceLocator; 80 | if (ds == null) 81 | throw new InvalidOperationException("DependencyService extension requires XamUInfrastructure.Init."); 82 | 83 | // ds.Get(Scope); 84 | var mi = ds.GetType().GetTypeInfo().GetDeclaredMethods("Get").First(m => m.GetParameters().Length == 1); 85 | var cmi = mi.MakeGenericMethod(Type); 86 | var result = cmi.Invoke(ds, new object[] { Scope }); 87 | 88 | return result; 89 | } 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/MarkupExtensions/ImageResourceExtension.cs: -------------------------------------------------------------------------------- 1 | // 2 | // ImageResourceExtension.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | using Xamarin.Forms.Xaml; 30 | using System.Reflection; 31 | 32 | namespace XamarinUniversity.Infrastructure 33 | { 34 | /// 35 | /// XAML markup extension to load an image from embedded resources. 36 | /// 37 | [ContentProperty ("Source")] 38 | public class ImageResourceExtension : IMarkupExtension 39 | { 40 | /// 41 | /// Optional System.Type used to identify the assembly where 42 | /// the resources are located 43 | /// 44 | /// The type of the assembly resolver. 45 | public Type AssemblyResolverType { get; set; } 46 | 47 | /// 48 | /// Resource ID which identifies the image 49 | /// 50 | /// The source. 51 | public string Source { get; set; } 52 | 53 | /// 54 | /// Returns the image 55 | /// 56 | /// The value. 57 | /// Service provider. 58 | object IMarkupExtension.ProvideValue (IServiceProvider serviceProvider) 59 | { 60 | return (this as IMarkupExtension).ProvideValue (serviceProvider); 61 | } 62 | 63 | /// 64 | /// Returns the image 65 | /// 66 | /// The value. 67 | /// Service provider. 68 | public ImageSource ProvideValue (IServiceProvider serviceProvider) 69 | { 70 | Assembly assembly = null; 71 | if (AssemblyResolverType != null) { 72 | assembly = AssemblyResolverType.GetTypeInfo ().Assembly; 73 | } 74 | else { 75 | var app = Application.Current; 76 | if (app != null) { 77 | assembly = app.GetType ().GetTypeInfo ().Assembly; 78 | } 79 | } 80 | 81 | return Source == null ? null : ImageSource.FromResource (Source, assembly); 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/MarkupExtensions/RelativeBindingContext.cs: -------------------------------------------------------------------------------- 1 | // 2 | // RelativeBindingContext.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | using Xamarin.Forms.Xaml; 30 | using System.Diagnostics; 31 | 32 | namespace XamarinUniversity.Infrastructure 33 | { 34 | /// 35 | /// This markup extension will locate the given element by name, grab the 36 | /// associated BindingContext and return it. This allows you to forward a 37 | /// BindingContext from some other element with a simpler syntax. 38 | /// 39 | [ContentProperty ("Name")] 40 | public class RelativeBindingContext : IMarkupExtension 41 | { 42 | BindableObject associatedObject; 43 | 44 | /// 45 | /// The name of the Element in the XAML file to grab the 46 | /// BindingContext from. 47 | /// 48 | /// The name. 49 | public string Name { get; set; } 50 | 51 | /// 52 | /// True to track binding changes and apply them; this is the 53 | /// default. Set this property to FALSE if you are not applying 54 | /// the value to the BindingContext. 55 | /// 56 | /// true if track binding changes; otherwise, false. 57 | public bool TrackBindingChanges { get; set; } 58 | 59 | /// 60 | /// Construct a new RelativeBindinContext. 61 | /// 62 | public RelativeBindingContext () 63 | { 64 | TrackBindingChanges = true; 65 | } 66 | 67 | /// 68 | /// Retrieves the BindingContext from the named element. 69 | /// 70 | /// BindingContext value or null 71 | /// Service provider. 72 | public object ProvideValue (IServiceProvider serviceProvider) 73 | { 74 | Debug.Assert (serviceProvider != null); 75 | if (string.IsNullOrEmpty (Name)) 76 | throw new ArgumentNullException ("RelativeBindingContext: Name must be provided."); 77 | 78 | var pvt = serviceProvider.GetService (typeof (IProvideValueTarget)) as IProvideValueTarget; 79 | var rootProvider = serviceProvider.GetService (typeof(IRootObjectProvider)) as IRootObjectProvider; 80 | Debug.Assert (pvt != null && rootProvider != null); 81 | 82 | // BUGBUG: unfortunately, Forms currently does not implement the 'TargetProperty' 83 | // value from IProvideValueTarget. That means we cannot tell what property is 84 | // being assigned here; so we assume BindingContext but allow you to manually 85 | // switch that off through the TrackBindingChanges property for this extension. 86 | 87 | var root = rootProvider.RootObject as Element; 88 | if (root != null) { 89 | var namedElement = root.FindByName (Name); 90 | if (namedElement != null) { 91 | if (TrackBindingChanges) { 92 | associatedObject = pvt.TargetObject as BindableObject; 93 | if (associatedObject != null) { 94 | associatedObject.BindingContext = namedElement.BindingContext; 95 | namedElement.BindingContextChanged += OnBindingContextChanged; 96 | } 97 | } 98 | return namedElement.BindingContext; 99 | } 100 | } 101 | 102 | return null; 103 | } 104 | 105 | /// 106 | /// This is called when the named element's binding context has changed. 107 | /// We forward this back to our associated object. 108 | /// 109 | /// Sender. 110 | /// E. 111 | void OnBindingContextChanged (object sender, EventArgs e) 112 | { 113 | associatedObject.BindingContext = ((BindableObject)sender).BindingContext; 114 | } 115 | } 116 | } 117 | 118 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/NamedDataTemplateSelector.cs: -------------------------------------------------------------------------------- 1 | // 2 | // NamedDataTemplateSelector.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using Xamarin.Forms; 29 | 30 | namespace XamarinUniversity.Infrastructure 31 | { 32 | /// 33 | /// This is a simple DataTemplateSelector that matches resources by the typename of the 34 | /// object being data bound to the ListView. 35 | /// 36 | /// 37 | /// To use it, add a copy into your resources and then assign it as the value for a 38 | /// ItemTemplate. This will evaluate the bound object and, based 39 | /// on the typename, retrieve a resource (starting at that object and working up to App) 40 | /// by the name. 41 | /// 42 | public class NamedDataTemplateSelector : DataTemplateSelector 43 | { 44 | /// 45 | /// True to strip off the namespace and only look for the base typename. 46 | /// 47 | /// true if strip namespace; otherwise, false. 48 | public bool StripNamespace { get; set; } 49 | 50 | /// 51 | /// Retrieves the DataTemplate for a given object using the typename of the 52 | /// object as the resource key. Throws an exception if the resource is not found. 53 | /// 54 | /// The select template. 55 | /// Item. 56 | /// Container. 57 | protected override DataTemplate OnSelectTemplate (object item, BindableObject container) 58 | { 59 | if (item == null) 60 | throw new Exception ("Cannot create template for null object."); 61 | 62 | Type itemType = item.GetType (); 63 | string typeName = (StripNamespace) ? itemType.Name : itemType.FullName; 64 | 65 | VisualElement ve = container as VisualElement; 66 | return ve.FindResource (typeName); 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Services/DependencyServiceWrapper.cs: -------------------------------------------------------------------------------- 1 | #define DEBUG // so we can use Debug.WriteLine 2 | // 3 | // DependencyServiceWrapper.cs 4 | // 5 | // Author: 6 | // Mark Smith 7 | // 8 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in 18 | // all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | // THE SOFTWARE. 27 | 28 | using Xamarin.Forms; 29 | using System; 30 | using System.Collections.Generic; 31 | using System.Reflection; 32 | using System.Linq; 33 | using System.Diagnostics; 34 | using XamarinUniversity.Infrastructure; 35 | 36 | namespace XamarinUniversity.Services 37 | { 38 | /// 39 | /// Wrapper around static Xamarin.Forms DependencyService to allow it to 40 | /// be turned into a mockable interface for unit testing. 41 | /// 42 | public class DependencyServiceWrapper : IDependencyService 43 | { 44 | readonly MethodInfo genericGetMethod; 45 | static readonly Dictionary DependencyInstances = new Dictionary(); 46 | 47 | /// 48 | /// Constructor for the DS wrapper. 49 | /// 50 | public DependencyServiceWrapper() 51 | { 52 | genericGetMethod = GetType().GetTypeInfo().GetDeclaredMethods("Get").Single(m => m.GetParameters().Length == 1); 53 | } 54 | 55 | /// 56 | /// Retrieve a dependency based on the abstraction . 57 | /// This extends the default DependencyService capability by allowing this method 58 | /// to create types which are not registered but have a public constructor. 59 | /// 60 | /// The 1st type parameter. 61 | public T Get() where T : class 62 | { 63 | return Get(DependencyScope.Global); 64 | } 65 | 66 | /// 67 | /// Retrieve a dependency based on the abstraction . 68 | /// This extends the default DependencyService capability by allowing this method 69 | /// to create types which are not registered but have a public constructor. 70 | /// 71 | /// The 1st type parameter. 72 | /// Scope of the returning object (global or new) 73 | public T Get(DependencyScope scope) where T : class 74 | { 75 | Type targetType = typeof(T); 76 | if (DependencyInstances.ContainsKey(targetType)) 77 | return DependencyInstances[targetType] as T; 78 | 79 | // Try the underlying DependencyService. 80 | T value = DependencyService.Get(scope == DependencyScope.Global 81 | ? DependencyFetchTarget.GlobalInstance : DependencyFetchTarget.NewInstance); 82 | if (value != null) 83 | return value; 84 | 85 | try 86 | { 87 | // Try to create it ourselves. 88 | TypeInfo typeInfo = targetType.GetTypeInfo(); 89 | if (typeInfo.IsInterface || typeInfo.IsAbstract) 90 | return null; 91 | 92 | // Look for a public, default constructor first. 93 | var ctors = typeInfo.DeclaredConstructors.Where(c => c.IsPublic).ToArray(); 94 | if (ctors.Length == 0) 95 | return null; 96 | 97 | var ctor = Array.Find(ctors, c => c.GetParameters().Length == 0); 98 | if (ctor != null) 99 | return Activator.CreateInstance(targetType) as T; 100 | 101 | // Pick the first public constructor found and create any parameters. 102 | // Note we use the same scope as passed to create all the parameters. 103 | return Activator.CreateInstance(targetType, ctors[0].GetParameters() 104 | .Select(p => genericGetMethod.MakeGenericMethod(p.ParameterType) 105 | .Invoke(this, new object[] { scope })) 106 | .ToArray()) as T; 107 | } 108 | catch (Exception ex) 109 | { 110 | Debug.WriteLine($"DependencyServiceWrapper failed to create {targetType.Name}: {ex.Message}"); 111 | } 112 | 113 | return null; 114 | } 115 | 116 | /// 117 | /// Register a specific type as an abstraction 118 | /// 119 | /// The type to register. 120 | public void Register () where T : class, new() 121 | { 122 | DependencyService.Register (); 123 | } 124 | 125 | /// 126 | /// Register a type along with an abstraction type. 127 | /// 128 | /// Abstraction type 129 | /// Type to create 130 | public void Register () 131 | where T : class 132 | where TImpl : class, T, new() 133 | { 134 | DependencyService.Register (); 135 | } 136 | 137 | /// 138 | /// Register a specific instance with a type. This extends the 139 | /// built-in DependencyService by allowing a specific instance to be registered. 140 | /// 141 | /// Type to register 142 | /// Implementation 143 | public void Register(T impl) where T : class 144 | { 145 | DependencyInstances.Add(typeof(T), impl); 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Services/FormsMessageVisualizerService.cs: -------------------------------------------------------------------------------- 1 | // 2 | // FormsMessageVisualizerService.cs 3 | // 4 | // Author: 5 | // Mark Smith 6 | // 7 | // Copyright (c) 2016-2018 Xamarin, Microsoft. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System.Threading.Tasks; 28 | using Xamarin.Forms; 29 | using XamarinUniversity.Infrastructure; 30 | 31 | namespace XamarinUniversity.Services 32 | { 33 | /// 34 | /// Wrapper around Page.DisplayAlert to turn it into a Message Visualizer 35 | /// service for Xamarin.Forms which can be used from a ViewModel and mocked 36 | /// for Unit Testing. 37 | /// 38 | public class FormsMessageVisualizerService : IMessageVisualizerService 39 | { 40 | /// 41 | /// Show a message using the Forms DisplayAlert method. 42 | /// 43 | /// The message. 44 | /// Title. 45 | /// Message. 46 | /// Ok. 47 | /// Cancel. 48 | public async Task ShowMessage( 49 | string title, string message, string ok, string cancel=null) 50 | { 51 | if (cancel == null) { 52 | await Application.Current.MainPage.DisplayAlert(title, message, ok).ConfigureAwait(false); 53 | return true; 54 | } 55 | 56 | return await Application.Current.MainPage.DisplayAlert( 57 | title, message, ok, cancel).ConfigureAwait(false); 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/Services/XamUInfrastructure.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.CompilerServices; 4 | using XamarinUniversity.Infrastructure; 5 | 6 | [assembly:InternalsVisibleTo("XamU.Infrastructure.Tests")] 7 | 8 | namespace XamarinUniversity.Services 9 | { 10 | /// 11 | /// Identifies which services you want to register during the Init call. 12 | /// 13 | [Flags] 14 | public enum RegisterBehavior 15 | { 16 | /// 17 | /// Register the default (Forms) navigation service 18 | /// 19 | Navigation = 1, 20 | /// 21 | /// Register the default (Forms) message visualizer 22 | /// 23 | MessageVisualizer = 2 24 | } 25 | 26 | /// 27 | /// Static class to initialize the library 28 | /// 29 | public static class XamUInfrastructure 30 | { 31 | private static bool initialized; 32 | private static IDependencyService serviceLocator; 33 | 34 | /// 35 | /// Used to reset for unit tests. 36 | /// 37 | internal static void Reset() 38 | { 39 | initialized = false; 40 | serviceLocator = null; 41 | } 42 | 43 | /// 44 | /// This allows you to retrieve and customize the global dependency service 45 | /// used by the library (and app). 46 | /// 47 | /// The service locator. 48 | public static IDependencyService ServiceLocator => serviceLocator ?? (serviceLocator = new DependencyServiceWrapper ()); 49 | 50 | /// 51 | /// Registers the known services with the ServiceLocator type. 52 | /// 53 | /// IDependencyService 54 | public static IDependencyService Init () 55 | { 56 | return Init(null, RegisterBehavior.MessageVisualizer | RegisterBehavior.Navigation); 57 | } 58 | 59 | /// 60 | /// Register the known services with the ServiceLocator type. 61 | /// 62 | /// Service locator 63 | /// IDependencyService 64 | public static IDependencyService Init(IDependencyService defaultLocator) 65 | { 66 | return Init(defaultLocator, 67 | RegisterBehavior.MessageVisualizer | RegisterBehavior.Navigation); 68 | } 69 | 70 | /// 71 | /// Register the known services with the ServiceLocator type. 72 | /// 73 | /// Services to register 74 | /// IDependencyService 75 | public static IDependencyService Init(RegisterBehavior registerBehavior) 76 | { 77 | return Init(null, registerBehavior); 78 | } 79 | 80 | /// 81 | /// Registers the known services with the ServiceLocator type. 82 | /// 83 | /// ServiceLocator, if null, DependencyService is used. 84 | /// Registration behavior 85 | /// IDependencyService 86 | public static IDependencyService Init(IDependencyService defaultLocator, RegisterBehavior registerBehavior) 87 | { 88 | // If the ServiceLocator has already been set, then something used it before 89 | // Init was called. This is not allowed if they are going to change the locator. 90 | if (defaultLocator != null 91 | && serviceLocator != null) 92 | { 93 | throw new InvalidOperationException( 94 | $"Must call {nameof(XamUInfrastructure.Init)} before using any library features; " + 95 | "ServiceLocator has already been set."); 96 | } 97 | 98 | // Can call Init multiple times as long as you don't change the locator. 99 | if (initialized) 100 | { 101 | Debug.Assert(serviceLocator != null); 102 | return ServiceLocator; 103 | } 104 | 105 | // Only do the remaining logic once or we get duplicate key exceptions. 106 | initialized = true; 107 | 108 | // Assign the locator; either use the supplied one, or the default 109 | // DependencyService version if not supplied. 110 | if (defaultLocator == null) 111 | { 112 | defaultLocator = ServiceLocator; 113 | } 114 | else 115 | { 116 | Debug.Assert (serviceLocator == null); 117 | serviceLocator = defaultLocator; 118 | } 119 | 120 | // Register the services 121 | if ((registerBehavior & RegisterBehavior.MessageVisualizer) == RegisterBehavior.MessageVisualizer) 122 | { 123 | try 124 | { 125 | defaultLocator.Register(); 126 | } 127 | catch (ArgumentException) 128 | { 129 | } 130 | } 131 | 132 | if ((registerBehavior & RegisterBehavior.Navigation) == RegisterBehavior.Navigation) 133 | { 134 | // Use a single instance for the navigation service and 135 | // register both interfaces against it. 136 | var navService = new FormsNavigationPageService(); 137 | 138 | try 139 | { 140 | defaultLocator.Register(navService); 141 | defaultLocator.Register(navService); 142 | } 143 | catch (ArgumentException) 144 | { 145 | } 146 | } 147 | 148 | try 149 | { 150 | defaultLocator.Register(defaultLocator); 151 | } 152 | catch (ArgumentException) 153 | { 154 | } 155 | 156 | return defaultLocator; 157 | } 158 | } 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/XamU.Infrastructure-old.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 10.0 6 | Debug 7 | AnyCPU 8 | {67F9D3A8-F71E-4428-913F-C37AE82CDB24} 9 | Library 10 | Properties 11 | XamarinUniversity 12 | XamU.Infrastructure 13 | v4.5 14 | Profile259 15 | 512 16 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 18 | 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | bin\Debug\XamU.Infrastructure.xml 29 | 30 | 31 | 32 | 33 | true 34 | bin\Release\ 35 | TRACE 36 | prompt 37 | 4 38 | bin\Release\XamU.Infrastructure.xml 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {8F2F8275-08CE-4884-8BFA-F059EEE2BB1C} 71 | XamU.Core 72 | 73 | 74 | 75 | 76 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll 77 | 78 | 79 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll 80 | 81 | 82 | ..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /src/XamU.Infrastructure/XamU.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;uap10.0.16299 6 | netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71; 7 | 2.2.0 8 | XamarinUniversity.Infrastructure 9 | Xamarin University Infrastructure Library 10 | Microsoft, Xamarin University 11 | Xamarin University Infrastructure Library 12 | XamarinUniversity.Infrastructure 13 | https://github.com/xamarinhq/xamu-infrastructure/blob/master/LICENSE 14 | https://github.com/xamarinhq/xamu-infrastructure 15 | https://raw.githubusercontent.com/xamarinhq/xamu-infrastructure/master/logo.png 16 | true 17 | This library provides a set of Xamarin.Forms classes for enterprise and MVVM development; includes markup extensions, behaviors, custom controls and abstractions for MVVM. 18 | Set of Xamarin.Forms classes for enterprise and MVVM development. 19 | https://github.com/xamarinhq/xamu-infrastructure/blob/master/CHANGELOG.md 20 | https://github.com/xamarinhq/xamu-infrastructure 21 | mvvm;ios;xamarin;android;winphone;uwp;windows;wpf;macos 22 | XamarinUniversity 23 | Microsoft, Xamarin University 24 | true 25 | Copyright (C) 2017-2018 Microsoft, Xamarin University 26 | 2.2.0.0 27 | 2.2.0.0 28 | 29 | 30 | 31 | full 32 | true 33 | 34 | 35 | 36 | pdbonly 37 | true 38 | 39 | 40 | 41 | $(DefineConstants);PLATFORM_ANDROID 42 | 43 | 44 | 45 | $(DefineConstants);PLATFORM_MAC 46 | 47 | 48 | 49 | $(DefineConstants);PLATFORM_IOS 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Windows Mobile Extensions for the UWP 74 | 75 | 76 | 77 | 78 | 79 | --------------------------------------------------------------------------------