├── .gitattributes ├── .gitignore ├── CONTRIBUTING.md ├── DemoApps └── QuizGame │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── Logo.scale-100.png │ ├── SmallLogo.scale-100.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ ├── StoreLogo.scale-100.png │ ├── Wide310x150Logo.scale-200.png │ └── WideLogo.scale-100.png │ ├── Common │ ├── BindableBase.cs │ └── DelegateCommand.cs │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── Model │ ├── GameHost.cs │ ├── PlayerMessage.cs │ └── Question.cs │ ├── Package.appxmanifest │ ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml │ ├── QuizGame.csproj │ ├── View │ ├── GamePage.xaml │ ├── GamePage.xaml.cs │ ├── PlayerPage.xaml │ └── PlayerPage.xaml.cs │ └── ViewModel │ ├── GameViewModel.cs │ └── PlayerViewModel.cs ├── LICENSE ├── NetworkHelper.sln ├── NetworkHelper ├── DnssdManager.cs ├── DnssdParticipant.cs ├── ICommunicationChannel.cs ├── ISessionManager.cs ├── ISessionParticipant.cs ├── NetworkHelper.csproj ├── Properties │ ├── AssemblyInfo.cs │ └── NetworkHelper.rd.xml ├── SessionManager.cs ├── SessionParticipant.cs ├── TcpCommunicationChannel.cs ├── UdpManager.cs ├── UdpParticipant.cs └── project.json ├── README.md ├── SECURITY.md ├── Screenshots ├── QuizGame_CreateGame_Lobby_scaled.png ├── QuizGame_GameInProgress_scaled.png ├── QuizGame_JoinGame_scaled.png ├── QuizGame_QuestionAnswered_scaled.png └── StartUpProject_scaled.png └── architecture.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.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 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 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 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Microsoft Store app package directory 159 | AppPackages/ 160 | 161 | # Visual Studio cache files 162 | # files ending in .cache can be ignored 163 | *.[Cc]ache 164 | # but keep track of directories ending in .cache 165 | !*.[Cc]ache/ 166 | 167 | # Others 168 | ClientBin/ 169 | [Ss]tyle[Cc]op.* 170 | ~$* 171 | *~ 172 | *.dbmdl 173 | *.dbproj.schemaview 174 | *.pfx 175 | *.publishsettings 176 | node_modules/ 177 | orleans.codegen.cs 178 | 179 | # RIA/Silverlight projects 180 | Generated_Code/ 181 | 182 | # Backup & report files from converting an old project file 183 | # to a newer Visual Studio version. Backup files are not needed, 184 | # because we have git ;-) 185 | _UpgradeReport_Files/ 186 | Backup*/ 187 | UpgradeLog*.XML 188 | UpgradeLog*.htm 189 | 190 | # SQL Server files 191 | *.mdf 192 | *.ldf 193 | 194 | # Business Intelligence projects 195 | *.rdl.data 196 | *.bim.layout 197 | *.bim_*.settings 198 | 199 | # Microsoft Fakes 200 | FakesAssemblies/ 201 | 202 | # Node.js Tools for Visual Studio 203 | .ntvs_analysis.dat 204 | 205 | # Visual Studio 6 build log 206 | *.plg 207 | 208 | # Visual Studio 6 workspace options file 209 | *.opt 210 | 211 | # Visual Studio LightSwitch build output 212 | **/*.HTMLClient/GeneratedArtifacts 213 | **/*.DesktopClient/GeneratedArtifacts 214 | **/*.DesktopClient/ModelManifest.xml 215 | **/*.Server/GeneratedArtifacts 216 | **/*.Server/ModelManifest.xml 217 | _Pvt_Extensions 218 | 219 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 2 | -------------------------------------------------------------------------------- /DemoApps/QuizGame/App.xaml: -------------------------------------------------------------------------------- 1 |  24 | 25 | 31 | 32 | 33 | -25 34 | 37 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /DemoApps/QuizGame/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using Windows.ApplicationModel; 27 | using Windows.ApplicationModel.Activation; 28 | using Windows.UI.Xaml; 29 | using Windows.UI.Xaml.Controls; 30 | using Windows.UI.Xaml.Navigation; 31 | 32 | namespace QuizGameClient 33 | { 34 | /// 35 | /// Provides application-specific behavior to supplement the default Application class. 36 | /// 37 | sealed partial class App : Application 38 | { 39 | /// 40 | /// Initializes the singleton application object. This is the first line of authored code 41 | /// executed, and as such is the logical equivalent of main() or WinMain(). 42 | /// 43 | public App() 44 | { 45 | this.InitializeComponent(); 46 | this.Suspending += OnSuspending; 47 | } 48 | 49 | /// 50 | /// Invoked when the application is launched normally by the end user. Other entry points 51 | /// will be used such as when the application is launched to open a specific file. 52 | /// 53 | /// Details about the launch request and process. 54 | protected override void OnLaunched(LaunchActivatedEventArgs e) 55 | { 56 | //#if DEBUG 57 | // if (System.Diagnostics.Debugger.IsAttached) 58 | // { 59 | // this.DebugSettings.EnableFrameRateCounter = true; 60 | // } 61 | //#endif 62 | 63 | Frame rootFrame = Window.Current.Content as Frame; 64 | 65 | // Do not repeat app initialization when the Window already has content, 66 | // just ensure that the window is active 67 | if (rootFrame == null) 68 | { 69 | // Create a Frame to act as the navigation context and navigate to the first page 70 | rootFrame = new Frame(); 71 | // Set the default language 72 | rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0]; 73 | 74 | rootFrame.NavigationFailed += OnNavigationFailed; 75 | 76 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 77 | { 78 | //TODO: Load state from previously suspended application 79 | } 80 | 81 | // Place the frame in the current Window 82 | Window.Current.Content = rootFrame; 83 | } 84 | 85 | if (rootFrame.Content == null) 86 | { 87 | // When the navigation stack isn't restored navigate to the first page, 88 | // configuring the new page by passing required information as a navigation 89 | // parameter 90 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 91 | } 92 | 93 | // Enable back navigation. 94 | Windows.UI.Core.SystemNavigationManager.GetForCurrentView().BackRequested += (s, ea) => 95 | { 96 | Frame frame = Window.Current.Content as Frame; 97 | 98 | if (frame != null && frame.CanGoBack && ea.Handled == false) 99 | { 100 | ea.Handled = true; 101 | frame.GoBack(); 102 | } 103 | }; 104 | 105 | // Ensure the current window is active 106 | Window.Current.Activate(); 107 | } 108 | 109 | /// 110 | /// Invoked when Navigation to a certain page fails 111 | /// 112 | /// The Frame which failed navigation 113 | /// Details about the navigation failure 114 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 115 | { 116 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 117 | } 118 | 119 | /// 120 | /// Invoked when application execution is being suspended. Application state is saved 121 | /// without knowing whether the application will be terminated or resumed with the contents 122 | /// of memory still intact. 123 | /// 124 | /// The source of the suspend request. 125 | /// Details about the suspend request. 126 | private void OnSuspending(object sender, SuspendingEventArgs e) 127 | { 128 | var deferral = e.SuspendingOperation.GetDeferral(); 129 | //TODO: Save application state and stop any background activity 130 | deferral.Complete(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/Logo.scale-100.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/SmallLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/SmallLogo.scale-100.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/StoreLogo.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Assets/WideLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/Windows-appsample-networkhelper/03c096983370eda96ab6bd8695d0f8a0f2bd3996/DemoApps/QuizGame/Assets/WideLogo.scale-100.png -------------------------------------------------------------------------------- /DemoApps/QuizGame/Common/BindableBase.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.ComponentModel; 27 | using System.Linq.Expressions; 28 | using System.Runtime.CompilerServices; 29 | using Windows.UI.Xaml.Data; 30 | 31 | namespace QuizGame.Common 32 | { 33 | /// 34 | /// Implementation of to simplify models. 35 | /// 36 | [Windows.Foundation.Metadata.WebHostHidden] 37 | public abstract class BindableBase : INotifyPropertyChanged 38 | { 39 | /// 40 | /// Multicast event for property change notifications. 41 | /// 42 | public event PropertyChangedEventHandler PropertyChanged; 43 | 44 | /// 45 | /// Checks if a property already matches a desired value. Sets the property and 46 | /// notifies listeners only when necessary. 47 | /// 48 | /// Type of the property. 49 | /// Reference to a property with both getter and setter. 50 | /// Desired value for the property. 51 | /// Name of the property used to notify listeners. This 52 | /// value is optional and can be provided automatically when invoked from compilers that 53 | /// support CallerMemberName. 54 | /// True if the value was changed, false if the existing value matched the 55 | /// desired value. 56 | protected bool SetProperty(ref T storage, T value, [CallerMemberName] String propertyName = null) 57 | { 58 | if (object.Equals(storage, value)) return false; 59 | 60 | storage = value; 61 | OnPropertyChanged(propertyName); 62 | return true; 63 | } 64 | 65 | /// 66 | /// Notifies listeners that a property value has changed. 67 | /// 68 | /// Name of the property used to notify listeners. This 69 | /// value is optional and can be provided automatically when invoked from compilers 70 | /// that support . 71 | protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 72 | { 73 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /DemoApps/QuizGame/Common/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------------- 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | // The MIT License (MIT) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // --------------------------------------------------------------------------------- 24 | 25 | using System; 26 | using System.Threading.Tasks; 27 | using System.Windows.Input; 28 | 29 | namespace QuizGame.Common 30 | { 31 | /// 32 | /// An whose delegates can be attached for and . 33 | /// 34 | /// Parameter type. 35 | /// 36 | /// The constructor deliberately prevents the use of value types. 37 | /// Because ICommand takes an object, having a value type for T would cause unexpected behavior when CanExecute(null) is called during XAML initialization for command bindings. 38 | /// Using default(T) was considered and rejected as a solution because the implementor would not be able to distinguish between a valid and defaulted values. 39 | /// 40 | /// Instead, callers should support a value type by using a nullable value type and checking the HasValue property before using the Value property. 41 | /// 42 | /// 43 | /// public MyClass() 44 | /// { 45 | /// this.submitCommand = new DelegateCommand<int?>(this.Submit, this.CanSubmit); 46 | /// } 47 | /// 48 | /// private bool CanSubmit(int? customerId) 49 | /// { 50 | /// return (customerId.HasValue && customers.Contains(customerId.Value)); 51 | /// } 52 | /// 53 | /// 54 | /// 55 | public class DelegateCommand : DelegateCommandBase 56 | { 57 | /// 58 | /// Initializes a new instance of . 59 | /// 60 | /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. 61 | /// will always return true. 62 | public DelegateCommand(Action executeMethod) 63 | : this(executeMethod, (o) => true) 64 | { 65 | } 66 | 67 | /// 68 | /// Initializes a new instance of . 69 | /// 70 | /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. 71 | /// Delegate to execute when CanExecute is called on the command. This can be null. 72 | /// When both and ar . 73 | public DelegateCommand(Action executeMethod, Func canExecuteMethod) 74 | : base((o) => executeMethod((T)o), (o) => canExecuteMethod((T)o)) 75 | { 76 | if (executeMethod == null || canExecuteMethod == null) 77 | throw new ArgumentNullException("executeMethod"); 78 | } 79 | 80 | /// 81 | /// Factory method to create a new instance of from an awaitable handler method. 82 | /// 83 | /// Delegate to execute when Execute is called on the command. 84 | /// Constructed instance of 85 | public static DelegateCommand FromAsyncHandler(Func executeMethod) 86 | { 87 | return new DelegateCommand(executeMethod); 88 | } 89 | 90 | /// 91 | /// Factory method to create a new instance of from an awaitable handler method. 92 | /// 93 | /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. 94 | /// Delegate to execute when CanExecute is called on the command. This can be null. 95 | /// Constructed instance of 96 | public static DelegateCommand FromAsyncHandler(Func executeMethod, Func canExecuteMethod) 97 | { 98 | return new DelegateCommand(executeMethod, canExecuteMethod); 99 | } 100 | 101 | /// 102 | ///Determines if the command can execute by invoked the provided during construction. 103 | /// 104 | ///Data used by the command to determine if it can execute. 105 | /// 106 | /// if this command can be executed; otherwise, . 107 | /// 108 | public bool CanExecute(T parameter) 109 | { 110 | return base.CanExecute(parameter); 111 | } 112 | 113 | /// 114 | ///Executes the command and invokes the provided during construction. 115 | /// 116 | ///Data used by the command. 117 | public async Task Execute(T parameter) 118 | { 119 | await base.Execute(parameter); 120 | } 121 | 122 | 123 | private DelegateCommand(Func executeMethod) 124 | : this(executeMethod, (o) => true) 125 | { 126 | } 127 | 128 | private DelegateCommand(Func executeMethod, Func canExecuteMethod) 129 | : base((o) => executeMethod((T)o), (o) => canExecuteMethod((T)o)) 130 | { 131 | if (executeMethod == null || canExecuteMethod == null) 132 | throw new ArgumentNullException("executeMethod"); 133 | } 134 | 135 | } 136 | 137 | /// 138 | /// An whose delegates do not take any parameters for and . 139 | /// 140 | /// 141 | /// 142 | public class DelegateCommand : DelegateCommandBase 143 | { 144 | /// 145 | /// Creates a new instance of with the to invoke on execution. 146 | /// 147 | /// The to invoke when is called. 148 | public DelegateCommand(Action executeMethod) 149 | : this(executeMethod, () => true) 150 | { 151 | } 152 | 153 | /// 154 | /// Creates a new instance of with the to invoke on execution 155 | /// and a to query for determining if the command can execute. 156 | /// 157 | /// The to invoke when is called. 158 | /// The to invoke when is called 159 | public DelegateCommand(Action executeMethod, Func canExecuteMethod) 160 | : base((o) => executeMethod(), (o) => canExecuteMethod()) 161 | { 162 | if (executeMethod == null || canExecuteMethod == null) 163 | throw new ArgumentNullException("executeMethod"); 164 | } 165 | 166 | /// 167 | /// Factory method to create a new instance of from an awaitable handler method. 168 | /// 169 | /// Delegate to execute when Execute is called on the command. 170 | /// Constructed instance of 171 | public static DelegateCommand FromAsyncHandler(Func executeMethod) 172 | { 173 | return new DelegateCommand(executeMethod); 174 | } 175 | 176 | /// 177 | /// Factory method to create a new instance of from an awaitable handler method. 178 | /// 179 | /// Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate. 180 | /// Delegate to execute when CanExecute is called on the command. This can be null. 181 | /// Constructed instance of 182 | public static DelegateCommand FromAsyncHandler(Func executeMethod, Func canExecuteMethod) 183 | { 184 | return new DelegateCommand(executeMethod, canExecuteMethod); 185 | } 186 | 187 | /// 188 | /// Executes the command. 189 | /// 190 | public async Task Execute() 191 | { 192 | await Execute(null); 193 | } 194 | 195 | /// 196 | /// Determines if the command can be executed. 197 | /// 198 | /// Returns if the command can execute, otherwise returns . 199 | public bool CanExecute() 200 | { 201 | return CanExecute(null); 202 | } 203 | 204 | private DelegateCommand(Func executeMethod) 205 | : this(executeMethod, () => true) 206 | { 207 | } 208 | 209 | private DelegateCommand(Func executeMethod, Func canExecuteMethod) 210 | : base((o) => executeMethod(), (o) => canExecuteMethod()) 211 | { 212 | if (executeMethod == null || canExecuteMethod == null) 213 | throw new ArgumentNullException("executeMethod"); 214 | } 215 | } 216 | 217 | /// 218 | /// An whose delegates can be attached for and . 219 | /// 220 | public abstract class DelegateCommandBase : ICommand 221 | { 222 | private readonly Func _executeMethod; 223 | private readonly Func _canExecuteMethod; 224 | 225 | /// 226 | /// Creates a new instance of a , specifying both the execute action and the can execute function. 227 | /// 228 | /// The to execute when is invoked. 229 | /// The to invoked when is invoked. 230 | protected DelegateCommandBase(Action executeMethod, Func canExecuteMethod) 231 | { 232 | if (executeMethod == null || canExecuteMethod == null) 233 | throw new ArgumentNullException("executeMethod"); 234 | 235 | _executeMethod = (arg) => { executeMethod(arg); return Task.Delay(0); }; 236 | _canExecuteMethod = canExecuteMethod; 237 | } 238 | 239 | /// 240 | /// Creates a new instance of a , specifying both the Execute action as an awaitable Task and the CanExecute function. 241 | /// 242 | /// The to execute when is invoked. 243 | /// The to invoked when is invoked. 244 | protected DelegateCommandBase(Func executeMethod, Func canExecuteMethod) 245 | { 246 | if (executeMethod == null || canExecuteMethod == null) 247 | throw new ArgumentNullException("executeMethod"); 248 | 249 | _executeMethod = executeMethod; 250 | _canExecuteMethod = canExecuteMethod; 251 | } 252 | 253 | /// 254 | /// Raises on the UI thread so every 255 | /// command invoker can requery . 256 | /// 257 | protected virtual void OnCanExecuteChanged() 258 | { 259 | var handlers = CanExecuteChanged; 260 | if (handlers != null) 261 | { 262 | handlers(this, EventArgs.Empty); 263 | } 264 | } 265 | 266 | 267 | /// 268 | /// Raises on the UI thread so every command invoker 269 | /// can requery to check if the command can execute. 270 | /// Note that this will trigger the execution of once for each invoker. 271 | /// 272 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")] 273 | public void RaiseCanExecuteChanged() 274 | { 275 | OnCanExecuteChanged(); 276 | } 277 | 278 | async void ICommand.Execute(object parameter) 279 | { 280 | await Execute(parameter); 281 | } 282 | 283 | bool ICommand.CanExecute(object parameter) 284 | { 285 | return CanExecute(parameter); 286 | } 287 | 288 | /// 289 | /// Executes the command with the provided parameter by invoking the supplied during construction. 290 | /// 291 | /// 292 | protected async Task Execute(object parameter) 293 | { 294 | await _executeMethod(parameter); 295 | } 296 | 297 | /// 298 | /// Determines if the command can execute with the provided parameter by invoking the supplied during construction. 299 | /// 300 | /// The parameter to use when determining if this command can execute. 301 | /// Returns if the command can execute. otherwise. 302 | protected bool CanExecute(object parameter) 303 | { 304 | return _canExecuteMethod == null || _canExecuteMethod(parameter); 305 | } 306 | 307 | /// 308 | /// Occurs when changes happen that affect whether or not the command should execute. 309 | /// 310 | public event EventHandler CanExecuteChanged; 311 | 312 | } 313 | 314 | } -------------------------------------------------------------------------------- /DemoApps/QuizGame/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  24 | 25 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |