├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── art ├── connected-dots-01.svg ├── connected-dots.pdf └── connected-dots.png ├── build └── GetBuildVersion.psm1 └── src ├── TinyPubSub.Forms ├── TinyPubSub.Forms.csproj └── TinyPubSubForms.cs ├── TinyPubSub.Tests ├── AttributeTests.cs ├── PubSubTests.cs └── TinyPubSub.Tests.csproj ├── TinyPubSub.sln ├── TinyPubSub ├── ISubscription.cs ├── Subscription.cs ├── TinyEventArgs.cs ├── TinyException.cs ├── TinyPubSub.cs ├── TinyPubSub.csproj └── TinySubscribeAttribute.cs └── samples └── Forms ├── Droid ├── Assets │ └── AboutAssets.txt ├── Forms.Sample.Droid.csproj ├── MainActivity.cs ├── Properties │ ├── AndroidManifest.xml │ └── AssemblyInfo.cs ├── Resources │ ├── AboutResources.txt │ ├── Resource.designer.cs │ ├── drawable-hdpi │ │ └── icon.png │ ├── drawable-xhdpi │ │ └── icon.png │ ├── drawable-xxhdpi │ │ └── icon.png │ └── drawable │ │ └── icon.png └── packages.config ├── Forms.Sample ├── Forms.Sample.csproj ├── Properties │ └── AssemblyInfo.cs ├── TinyPubSub.Sample.cs ├── ViewModels │ ├── DuckViewModel.cs │ ├── MainViewModel.cs │ └── ViewModelBase.cs ├── Views │ ├── DuckView.xaml │ ├── DuckView.xaml.cs │ ├── MainView.xaml │ └── MainView.xaml.cs └── packages.config └── iOS ├── AppDelegate.cs ├── Entitlements.plist ├── Forms.Sample.iOS.csproj ├── Info.plist ├── Main.cs ├── Resources ├── Images.xcassets │ └── AppIcons.appiconset │ │ └── Contents.json └── LaunchScreen.xib └── packages.config /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | create: 5 | branches: 6 | - release/** 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | build: 16 | env: 17 | BUILD_CONFIG: "Release" 18 | 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | 24 | - name: Get Build Version 25 | run: | 26 | Import-Module .\build\GetBuildVersion.psm1 27 | Write-Host $Env:GITHUB_REF 28 | $version = GetBuildVersion -VersionString $Env:GITHUB_REF 29 | echo "BUILD_VERSION=$version" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append 30 | shell: pwsh 31 | 32 | - name: Setup NuGet 33 | uses: NuGet/setup-nuget@v1.0.5 34 | with: 35 | nuget-version: latest 36 | 37 | - name: Setup .NET 38 | uses: actions/setup-dotnet@v1 39 | with: 40 | dotnet-version: 6.0.x 41 | 42 | - name: Restore dependencies 43 | run: nuget restore ./src/TinyPubSub.sln 44 | 45 | - name: Restore dependencies 46 | run: dotnet restore ./src/TinyPubSub/TinyPubSub.csproj 47 | 48 | - name: Build 49 | run: dotnet build ./src/TinyPubSub --no-restore --configuration $BUILD_CONFIG -p:Version=$BUILD_VERSION --no-restore 50 | 51 | - name: Run tests 52 | run: dotnet test ./src/TinyPubSub.Tests /p:Configuration=$BUILD_CONFIG /p:Version=$BUILD_VERSION --verbosity normal 53 | 54 | - name: Publish 55 | if: startsWith(github.ref, 'refs/heads/release') 56 | run: nuget push ./src/TinyPubSub/**/*.nupkg -Source 'https://api.nuget.org/v3/index.json' -ApiKey ${{secrets.NUGET_API_KEY}} 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Autosave files 2 | *~ 3 | .vs/ 4 | .idea/ 5 | 6 | #build 7 | [Oo]bj/ 8 | [Bb]in/ 9 | packages/ 10 | TestResults/ 11 | 12 | # globs 13 | Makefile.in 14 | *.DS_Store 15 | *.sln.cache 16 | *.suo 17 | *.cache 18 | *.pidb 19 | *.userprefs 20 | *.usertasks 21 | config.log 22 | config.make 23 | config.status 24 | aclocal.m4 25 | install-sh 26 | autom4te.cache/ 27 | *.user 28 | *.tar.gz 29 | tarballs/ 30 | test-results/ 31 | Thumbs.db 32 | 33 | #Mac bundle stuff 34 | *.dmg 35 | *.app 36 | 37 | #resharper 38 | *_Resharper.* 39 | *.Resharper 40 | 41 | #dotCover 42 | *.dotCover 43 | *.nupkg 44 | *.bak 45 | 46 | #cake 47 | tools/ 48 | 49 | #vscode 50 | .vscode/ 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Johan Karlsson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyPubSub 2 | 3 | A really small pub/sub thingy created for .net! 4 | In memory, in-process, tiny and shiny. Sync publish, fire-and-forget publish, async publish, non-generic and generic publish/subscribe. 5 | 6 | ## Roadmap 7 | 8 | - V2 is under development - the aim is to modernize the lib to make use of new C# language features and runtimes. 9 | - TinyPubSub 2.0.0-preview4 is available as a nuget () 10 | 11 | ## Build status 12 | 13 | [![CI](https://github.com/TinyStuff/TinyPubSub/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/TinyStuff/TinyPubSub/actions/workflows/main.yml) 14 | 15 | ## TLDR 16 | 17 | What does it do? TinyPubSub lets you run code when an event happens. 18 | 19 | Init - if you are using forms, install the TinyPubSub.Forms package 20 | 21 | ```csharp 22 | 23 | // If you are using Xamarin 24 | public App () 25 | { 26 | // If you are using forms 27 | TinyPubSubLib.TinyPubSubForms.Init(this); 28 | 29 | // The root page of your application 30 | var navPage = new NavigationPage(new MainView()); 31 | 32 | // If you don't use the TinyPubSubForms.Init(..) method you can register the events yourself like this 33 | // navPage.Popped += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext); 34 | // navpage.PoppedToRoot += (s, args) => 35 | // { 36 | // var poppedToRootEventArgs = args as PoppedToRootEventArgs; 37 | // foreach (var poppedPage in poppedToRootEventArgs.PoppedPages) 38 | // { 39 | // TinyPubSub.Unsubscribe(poppedPage.BindingContext); 40 | // } 41 | // }; 42 | MainPage = navPage; 43 | } 44 | 45 | ``` 46 | 47 | Subscribe 48 | 49 | ```csharp 50 | // The forms way (from ViewModel) 51 | TinyPubSub.Subscribe(this, "new-duck-added", () => RebindDuckGui()); 52 | 53 | // Non-forms way 54 | TinyPubSub.Subscribe("new-duck-added", () => RebindDuckGui()); 55 | 56 | // The forms way (from ViewModel) with an argument 57 | TinyPubSub.Subscribe(this, "new-duck-added", (x) => RebindDuckGui(nameofduck: x)); 58 | 59 | // Non-forms way 60 | TinyPubSub.Subscribe("new-duck-added", (x) => RebindDuckGui(nameofduck: x)); 61 | 62 | // The forms way with a typed argument, where MessageModel can be any class you'd like 63 | TinyPubSub.Subscribe(this, "new-duck-added", (model) => RebindDuckGui(nameofduck: model.Name)); 64 | 65 | // Subscription by attribute 66 | public class MyClass 67 | { 68 | public MyClass() 69 | { 70 | // Register it directly in the class or somewhere else 71 | TinyPubSub.Register(this); 72 | } 73 | 74 | [TinySubscribe("new-duck-added")] 75 | public void DuckAdded(MessageModel duck) 76 | { 77 | // Do something with the duck 78 | } 79 | } 80 | 81 | // Subscription with control to determine if we should prevent the next subscriber on the same channel to handle the event 82 | // NOTE: Must be triggered by any PublishControlled* method to work. The _ argument is because we need an argument even if it's null 83 | TinyPubSub.Subscribe("new-duck-added", (_, args) => 84 | { 85 | args.HaltExecution = true; 86 | }); 87 | 88 | ``` 89 | 90 | Publish 91 | 92 | ```csharp 93 | // Without argument 94 | TinyPubSub.Publish("new-duck-added"); 95 | 96 | // With argument 97 | TinyPubSub.Publish("new-duck-added", "Ducky McDuckface"); 98 | 99 | // As a task (that runs later on) 100 | TinyPubSub.PublishAsTask("new-duck-added"); 101 | 102 | // As a task (that runs later on) with argument 103 | TinyPubSub.PublishAsTask("new-duck-added", "Ducky McDuckface"); 104 | 105 | // Async 106 | await TinyPubSub.PublishAsync("new-duck-added"); 107 | 108 | // Async with argument 109 | await TinyPubSub.PublishAsync("new-duck-added", "Ducky McDuckface"); 110 | 111 | // Publish with a typed argument 112 | TinyPubSub.Publish("new-duck-added", new MessageModel() { Name = "Ducky" }); 113 | 114 | // Publish and wait for the result - can be used to make sure someone has handled it 115 | var result = TinyPubSub.PublishControlled("new-duck-added"); 116 | var successful = result.Handled; 117 | 118 | // Publish controlled with a typed argument 119 | var result = TinyPubSub.PublishControlled("new-duck-added", new MessageModel() { Name = "Ducky" }); 120 | var successful = result.Handled; 121 | 122 | ``` 123 | 124 | ## WHY SHOULD I USE IT? 125 | 126 | 127 | 128 | This lib should be used when you want to easily register to events within a small app. It's not meant for data transfer (at least not at this point), it's not thread safe and it's never going to be finished. :) 129 | 130 | ### EXAMPLE 131 | 132 | I have a view that shows ducks. This is my main view. When I edit ducks on another view and the main page is covered I still want the main view to get new ducks before I return to it. I don't want the MainPage to start loading when it gets displayed. 133 | 134 | The main view can listen for the "ducks-added" event and run an action when that happens. When I create a new function in the system I can trust that if I publish an event on the "ducks-added" channel, all my other views subscribing to that event will get notified. 135 | 136 | And by following some patterns regarding the NavigationPage(...) we can also make sure that the subscriptions are removed when the view go out of scope. 137 | 138 | It's designed with MVVM in mind. Subscription to new events should be done in the ViewModel and the Unsubscription should be made automatically when pages are popped (see usage). 139 | 140 | It's not meant to solve world problems so if you want a robust and mature pub/sub framework then there are plenty others out there to use. This is bare metal. 141 | 142 | ## STATE 143 | 144 | Release (1.2.x for TinyPubSub and 1.2.x for TinyPubSub.Forms) 145 | 146 | ## NUGET 147 | 148 | Package 1.0.x and 1.1.x are built for profile 259. Packaged 1.2.x are built using netstandard 1.0. 149 | 150 | ## EXCEPTION HANDLING 151 | 152 | Exceptions are sent back to you through TinyPubSub itself. 153 | 154 | ```csharp 155 | TinyPubSub.Subscribe(this, TinyExceptionDefaultChannel, (TinyException ex) => { HandleException(ex) }); 156 | ``` 157 | 158 | You can also send an error handler directly into the publish call. 159 | 160 | ```csharp 161 | TinyPubSub.Publish(this, "new-duck-added", () => HandleDuck(), onError: (ex, s) => 162 | { 163 | // ex is the Exception that was thrown 164 | // s is the subscription that failed 165 | }); 166 | ``` 167 | 168 | ### Forms 169 | 170 | If you are using TinyPubSub from Xamarin forms, install this package and call the init method as described at the top. You don't have to install any other package. 171 | 172 | [https://www.nuget.org/packages/tinypubsub.forms](https://www.nuget.org/packages/tinypubsub.forms) 173 | 174 | ### Vanilla 175 | 176 | [https://www.nuget.org/packages/tinypubsub](https://www.nuget.org/packages/tinypubsub) 177 | 178 | ## USAGE 179 | 180 | To subscribe, simply register what "channel" (we call them channels) you would like to subscribe to. 181 | 182 | ```csharp 183 | TinyPubSub.Subscribe("new-duck-added", () => { RebindDuckGui(); }); 184 | ``` 185 | 186 | And in another part of you application, publish events to execute the actions that are registered for that channel. 187 | 188 | ```csharp 189 | 190 | // Sync publish with or without argument 191 | TinyPubSub.Publish("new-duck-added", "optional argument"); 192 | 193 | // As a task (fire and forget) 194 | TinyPubSub.PublishAsTask("new-duck-added", "optional argument"); 195 | 196 | // As an async call 197 | await TinyPubSub.PublishAsync("new-duck-added", "optional argument"); 198 | ``` 199 | 200 | ### WHAT ABOUT MEMORY ISSUES? 201 | 202 | If you are using the Xamarin Forms version (TinyPubSub.Forms) and call the Init(..) method as described at the top of this page, then you have no worries. The lib will take care of deregistration just in time given that you take two things into consideration. 203 | 204 | - You register your subscriptions from the ViewModel (whatever object you bind to BindingContext) or the page it self 205 | - You pass in `this` into the subscription registration like `TinyPubSub.Subscribe(this, "new-duck-added", () => { RebindDuckGui(); });` 206 | 207 | If you use the vanilla version, continue reading. 208 | 209 | #### Plan A - tags 210 | 211 | When subscribing you get a tag. 212 | 213 | ```c# 214 | var tag = TinyPubSub.Subscribe("new-duck-added", () => { RebindDuckGui(); }); 215 | ``` 216 | 217 | And when you are done you unsubscribe with that tag. 218 | 219 | ```c# 220 | TinyPubSub.Unsubscribe(tag); 221 | ``` 222 | 223 | #### Plan B - object refs 224 | 225 | This is a more suitable option for Xamarin MVVM (which is really the reason for this projects existance). I don't like having to keep track of tags. So instead we pass a reference to an object that counts as the owner of the subscription. Usually this and most usually a ViewModel. This way we can subscribe to several channels. 226 | 227 | ```c# 228 | TinyPubSub.Subscribe(this, "new-duck-added", () => { RebindDuckGui(); }); 229 | TinyPubSub.Subscribe(this, "old-duck-removed", () => { RebindDuckGui(); }); 230 | ``` 231 | 232 | And when the view is done (if we're talking MVVM) then the unsubscription could look like this. 233 | 234 | ```c# 235 | TinyPubSub.Unsubscribe(this); 236 | ``` 237 | 238 | Or specifically in Xamarin Forms 239 | 240 | ```c# 241 | TinyPubSub.Unsubscribe(this.BindingContext); // if this is a View and the Binding context the view model 242 | ``` 243 | 244 | The tricky part is still knowing when the view is done. One way is to hook up to the navigation page Popped and PoppedToRoot (if Forms, but then just use TinyPubSub.Forms package instead). 245 | 246 | ```c# 247 | // The root page of your application 248 | var navPage = new NavigationPage(new MainView()); 249 | navPage.Popped += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext); 250 | navpage.PoppedToRoot += (s, args) => 251 | { 252 | var poppedToRootEventArgs = args as PoppedToRootEventArgs; 253 | foreach (var poppedPage in poppedToRootEventArgs.PoppedPages) 254 | { 255 | TinyPubSub.Unsubscribe(poppedPage.BindingContext); 256 | } 257 | }; 258 | MainPage = navPage; 259 | ``` 260 | 261 | This works as long as PopToRoot isn't called and you are more than one level deep in the navigation stack. There is also a NavigationPage.PoppedToRoot event, but looking at the Xamarin Forms code it simply clears the children without calling popped for each page. I've started a thread about this at the xamarin forums. 262 | 263 | I got some new code into the Xamarin Forms Core Navigation stuff so now we can get information on what pages that are popped. 264 | 265 | # CI 266 | 267 | Pipeline was inspired by this post: https://www.jamescroft.co.uk/how-to-build-publish-nuget-packages-with-github-actions/ 268 | -------------------------------------------------------------------------------- /art/connected-dots.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/art/connected-dots.pdf -------------------------------------------------------------------------------- /art/connected-dots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/art/connected-dots.png -------------------------------------------------------------------------------- /build/GetBuildVersion.psm1: -------------------------------------------------------------------------------- 1 | Function GetBuildVersion { 2 | Param ( 3 | [string]$VersionString 4 | ) 5 | 6 | # Process through regex 7 | $VersionString -match "(?\d+)(\.(?\d+))?(\.(?\d+))?(\-(?
[0-9A-Za-z\-\.]+))?(\+(?\d+))?" | Out-Null
 8 | 
 9 |     if ($matches -eq $null) {
10 |         return "1.0.0-build"
11 |     }
12 | 
13 |     # Extract the build metadata
14 |     $BuildRevision = [uint64]$matches['build']
15 |     # Extract the pre-release tag
16 |     $PreReleaseTag = [string]$matches['pre']
17 |     # Extract the patch
18 |     $Patch = [uint64]$matches['patch']
19 |     # Extract the minor
20 |     $Minor = [uint64]$matches['minor']
21 |     # Extract the major
22 |     $Major = [uint64]$matches['major']
23 | 
24 |     $Version = [string]$Major + '.' + [string]$Minor + '.' + [string]$Patch;
25 |     if ($PreReleaseTag -ne [string]::Empty) {
26 |         $Version = $Version + '-' + $PreReleaseTag
27 |     }
28 | 
29 |     if ($BuildRevision -ne 0) {
30 |         $Version = $Version + '.' + [string]$BuildRevision
31 |     }
32 | 
33 |     return $Version
34 | }


--------------------------------------------------------------------------------
/src/TinyPubSub.Forms/TinyPubSub.Forms.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     netstandard1.1
 5 |     Release-CI;Debug;Release
 6 |   
 7 | 
 8 |   
 9 | 
10 |   
11 |     
12 |   
13 | 
14 |   
15 |     
16 |   
17 | 
18 |   
19 |     
20 |   
21 |   
22 |     TinyPubSub.Forms
23 |     1.2.0
24 |     johankson and dhindrik
25 |     Forms initialization helper for TinyPubSub
26 |     false
27 |     Updated package to netstandard 1.0
28 |     Copyright 2017 - Johan Karlsson and Daniel Hindrikes
29 |     Xamarin pubsub
30 |     http://i.imgur.com/p0xJYYC.png
31 |     https://github.com/johankson/TinyPubSub
32 |     https://opensource.org/licenses/MIT
33 |   
34 |   
35 | 


--------------------------------------------------------------------------------
/src/TinyPubSub.Forms/TinyPubSubForms.cs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * The MIT License (MIT)
  3 |  * Copyright (c) 2016 Johan Karlsson
  4 |  *
  5 |  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  6 |  * of this software and associated documentation files (the "Software"), to deal 
  7 |  * in the Software without restriction, including without limitation the rights 
  8 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  9 |  * copies of the Software, and to permit persons to whom the Software is furnished 
 10 |  * to do so, subject to the following conditions:
 11 |  *
 12 |  * The above copyright notice and this permission notice shall be included in 
 13 |  * all copies or substantial portions of the Software.
 14 |  * 
 15 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 16 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 17 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 18 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 20 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 21 |  * DEALINGS IN THE SOFTWARE.
 22 |  *
 23 |  */
 24 | 
 25 | using System;
 26 | using Xamarin.Forms;
 27 | 
 28 | namespace TinyPubSubLib
 29 | {
 30 |     public static class TinyPubSubForms
 31 |     {
 32 |         public static void Init(Application app)
 33 |         {
 34 |             TinyPubSub.Clear();
 35 |             app.PropertyChanged += App_PropertyChanged;
 36 |         }
 37 | 
 38 |         static void App_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
 39 |         {
 40 |             if (sender is Application && e.PropertyName == "MainPage")
 41 |             {
 42 |                 var page = (sender as Application).MainPage;
 43 | 
 44 |                 if (page is NavigationPage)
 45 |                 {
 46 |                     BindEvents(page as NavigationPage);
 47 |                 }
 48 |             }
 49 |         }
 50 | 
 51 |         public static void SubscribeOnMainThread(object owner, string channel, Action action) 
 52 |         {
 53 |             TinyPubSub.Subscribe(owner,channel, (obj) => {
 54 |                 Device.BeginInvokeOnMainThread(() => action(obj));   
 55 |             });
 56 |         }
 57 | 
 58 |         public static void SubscribeOnMainThread(string channel, Action action)
 59 |         {
 60 |             SubscribeOnMainThread(null, channel, action);
 61 |         }
 62 | 
 63 |         public static void SubscribeOnMainThread(object owner, string channel, Action action)
 64 |         {
 65 |             SubscribeOnMainThread(owner, channel, action);
 66 |         }
 67 | 
 68 |         public static void SubscribeOnMainThread(string channel, Action action)
 69 |         {
 70 |             SubscribeOnMainThread(null, channel, action);
 71 |         }
 72 | 
 73 | 
 74 |         static void BindEvents(NavigationPage page)
 75 |         {
 76 |             page.Popped += (s, args) =>
 77 |             {
 78 |                 TinyPubSub.Unsubscribe(args.Page);
 79 |                 TinyPubSub.Unsubscribe(args.Page.BindingContext);
 80 | 
 81 |                 if (args.Page is MultiPage multipage)
 82 |                 {
 83 |                     foreach (var child in multipage.Children)
 84 |                     {
 85 |                         TinyPubSub.Unsubscribe(child);
 86 |                         TinyPubSub.Unsubscribe(child.BindingContext);
 87 |                     }
 88 |                 }
 89 |             };
 90 | 
 91 |             page.PoppedToRoot += (s, args) =>
 92 |             {
 93 |                 var poppedToRootEventArgs = args as PoppedToRootEventArgs;
 94 |                 foreach (var poppedPage in poppedToRootEventArgs.PoppedPages)
 95 |                 {
 96 |                     TinyPubSub.Unsubscribe(poppedPage);
 97 |                     TinyPubSub.Unsubscribe(poppedPage?.BindingContext);
 98 |                 }
 99 |             };
100 |         }
101 |     }
102 | }
103 | 


--------------------------------------------------------------------------------
/src/TinyPubSub.Tests/AttributeTests.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Threading.Tasks;
  3 | using TinyPubSubLib;
  4 | using Xunit;
  5 | 
  6 | namespace TinyPubSub.Tests
  7 | {
  8 |     public class AttributeTests
  9 |     {
 10 |         [Fact]
 11 |         public void SubscribeWithAttributeTest()
 12 |         {
 13 |             // Arrange
 14 |             var subject = new TestSubject();
 15 |             TinyPubSubLib.TinyPubSub.Register(subject);
 16 | 
 17 |             // Act
 18 |             TinyPubSubLib.TinyPubSub.Publish("test");
 19 | 
 20 |             // Assert
 21 |             Assert.True(subject.IsSuccessful);
 22 |         }
 23 | 
 24 |         [Fact]
 25 |         public async Task SubscribeAsyncWithAttributeTest()
 26 |         {
 27 |             // Arrange
 28 |             var subject = new TestSubject();
 29 |             TinyPubSubLib.TinyPubSub.Register(subject);
 30 | 
 31 |             // Act
 32 |             TinyPubSubLib.TinyPubSub.Publish("test-async");
 33 |             await Task.Delay(100);
 34 | 
 35 |             // Assert
 36 |             Assert.True(subject.IsSuccessful);
 37 |         }
 38 | 
 39 |         [Fact]
 40 |         public void SubscribeWithParameterTest()
 41 |         {
 42 |             // Arrange
 43 |             var subject = new TestSubject();
 44 |             TinyPubSubLib.TinyPubSub.Register(subject);
 45 | 
 46 |             // Act
 47 |             var data = new TestType() { DuckLength = 42 };
 48 |             TinyPubSubLib.TinyPubSub.Publish("test-with-arguments", data, onError: (Exception arg1, ISubscription arg2) => Console.WriteLine($"Exception occured: {arg1.ToString()}"));
 49 | 
 50 |             // Assert
 51 |             Assert.True(subject.IsSuccessful);
 52 |         }
 53 | 
 54 |         /// 
 55 |         /// Register subcriptions through attribute but the publish calls data doesn't match the 
 56 |         /// signature of the subscription method. At the moment, this results in an error.
 57 |         /// 
 58 |         [Fact]
 59 |         public void SubscribeWithWrongParameterTest()
 60 |         {
 61 |             // Arrange
 62 |             var subject = new TestSubject();
 63 |             TinyPubSubLib.TinyPubSub.Register(subject);
 64 | 
 65 |             // Act
 66 |             var data = new BadTestType();
 67 |             TinyPubSubLib.TinyPubSub.Publish("test-with-bad-arguments", data, onError: (Exception arg1, ISubscription arg2) => subject.IsSuccessful = true);
 68 | 
 69 |             // Assert
 70 |             Assert.True(subject.IsSuccessful);
 71 |         }
 72 |     }
 73 | 
 74 |     public class TestSubject
 75 |     {
 76 |         public bool IsSuccessful
 77 |         {
 78 |             get;
 79 |             set;
 80 |         }
 81 | 
 82 |         [TinySubscribe("test")]
 83 |         public void DoEpicStuff()
 84 |         {
 85 |             IsSuccessful = true;
 86 |         }
 87 | 
 88 |         [TinySubscribe("test-async")]
 89 |         public async Task DoEpicAsyncStuff()
 90 |         {
 91 |             await Task.Delay(1);
 92 |             IsSuccessful = true;
 93 |         }
 94 | 
 95 |         /// 
 96 |         /// This method will only be called if the Publish passes
 97 |         /// TestType as argument.
 98 |         /// 
 99 |         /// Data.
100 |         [TinySubscribe("test-with-arguments")]
101 |         public void DoEpicStuffWithArgument(TestType data)
102 |         {
103 |             if (data.DuckLength == 42)
104 |             {
105 |                 IsSuccessful = true;
106 |             }
107 |         }
108 | 
109 |         /// 
110 |         /// This method will only be called if the Publish passes
111 |         /// TestType as argument.
112 |         /// 
113 |         /// Data.
114 |         [TinySubscribe("test-with-bad-arguments")]
115 |         public void DoEpicStuffWithBadArgument(TestType data)
116 |         {
117 |             if (data.DuckLength == 42)
118 |             {
119 |                 IsSuccessful = true;
120 |             }
121 |         }
122 |     }
123 | 
124 |     public class TestType
125 |     {
126 |         public string DuckSize { get; set; }
127 |         public int DuckLength { get; set; }
128 |     }
129 | 
130 |     public class BadTestType
131 |     {
132 |     }
133 | }
134 | 


--------------------------------------------------------------------------------
/src/TinyPubSub.Tests/PubSubTests.cs:
--------------------------------------------------------------------------------
  1 | using System;
  2 | using System.Threading.Tasks;
  3 | using FluentAssertions;
  4 | using Xunit;
  5 | using TinyPubSubLib;
  6 | 
  7 | namespace TinyPubSub.Tests
  8 | {
  9 |     // Dummy class for instance sending
 10 |     public class TestEventType
 11 |     {
 12 |         public int Sklep { get; set; } = 5;
 13 |     }
 14 | 
 15 |     // Dummy class for instance sending with inheritance
 16 |     public class InheritedTestEventType : TestEventType
 17 |     {
 18 |         public int MyOtherInt { get; set; } = 2;
 19 |     }
 20 | 
 21 |     public class PubSubTests
 22 |     {
 23 |         [Fact]
 24 |         public void SubscribeWithArgumentTest()
 25 |         {
 26 |             // Arrange
 27 |             var actionCalled = false;
 28 |             var channel = Guid.NewGuid().ToString();
 29 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (x) => actionCalled = (x == "duck"));
 30 | 
 31 |             // Act
 32 |             TinyPubSubLib.TinyPubSub.Publish(channel, "duck");
 33 | 
 34 |             // Assert
 35 |             Assert.True(actionCalled);
 36 |         }
 37 | 
 38 |         [Fact]
 39 |         public void SubscribeWithTypeTest()
 40 |         {
 41 |             // Arrange
 42 |             var actionCalled = false;
 43 |             var tstType = new TestEventType();
 44 |             var channel = Guid.NewGuid().ToString();
 45 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (x) => actionCalled = (x.Sklep == 5));
 46 | 
 47 |             // Act
 48 |             TinyPubSubLib.TinyPubSub.Publish(channel, tstType);
 49 | 
 50 |             // Assert
 51 |             Assert.True(actionCalled);
 52 |         }
 53 | 
 54 |         [Fact]
 55 |         public void SubscribeWithEventArguments()
 56 |         {
 57 |             // Arrange
 58 |             var actionCalled = 0;
 59 |             var tstType = new TestEventType();
 60 |             var channel = Guid.NewGuid().ToString();
 61 | 
 62 |             TinyPubSubLib.TinyPubSub.Subscribe(null, channel, (TestEventType x) =>
 63 |             {
 64 |                 actionCalled = 3;
 65 |             });
 66 | 
 67 |             TinyPubSubLib.TinyPubSub.Subscribe(null, channel, (TestEventType x, TinyPubSubLib.TinyEventArgs evtargs) =>
 68 |             {
 69 |                 evtargs.HaltExecution = true;
 70 |             });
 71 | 
 72 |             TinyPubSubLib.TinyPubSub.Subscribe(null, channel, (TestEventType x) =>
 73 |             {
 74 |                 actionCalled = 4;
 75 |             });
 76 | 
 77 |             // Act
 78 |             var ret = TinyPubSubLib.TinyPubSub.PublishControlled(channel, tstType);
 79 | 
 80 |             // Assert
 81 |             Assert.True(actionCalled == 3 && ret.Handled == true);
 82 |         }
 83 | 
 84 |         [Fact]
 85 |         public void SubscribeWithTypeInheritanceTest()
 86 |         {
 87 |             // Arrange
 88 |             var actionCalled = false;
 89 |             var tstType = new InheritedTestEventType();
 90 |             var channel = Guid.NewGuid().ToString();
 91 | 
 92 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (x) => actionCalled = (x.Sklep == 5));
 93 | 
 94 |             // Act
 95 |             TinyPubSubLib.TinyPubSub.Publish(channel, tstType);
 96 | 
 97 |             // Assert
 98 |             Assert.True(actionCalled);
 99 |         }
100 | 
101 |         [Fact]
102 |         public void SubscribeWithArgumentMissingTest()
103 |         {
104 |             // Arrange
105 |             var actionCalled = false;
106 |             var channel = Guid.NewGuid().ToString();
107 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => actionCalled = true);
108 | 
109 |             // Act
110 |             TinyPubSubLib.TinyPubSub.Publish(channel, "dumbargument");
111 | 
112 |             // Assert
113 |             Assert.True(actionCalled);
114 |         }
115 | 
116 |         [Fact]
117 |         public void SubscribeWithArgumentMissingButArgumentedSubscriptionTest()
118 |         {
119 |             // Arrange
120 |             var actionCalled = false;
121 |             var channel = Guid.NewGuid().ToString();
122 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (x) => actionCalled = (x == null));
123 | 
124 |             // Act
125 |             TinyPubSubLib.TinyPubSub.Publish(channel);
126 | 
127 |             // Assert
128 |             Assert.True(actionCalled);
129 |         }
130 | 
131 |         [Fact]
132 |         public void SubscribePublishTheMostCommonWayTest()
133 |         {
134 |             // Arrange
135 |             var actionCalled = false;
136 |             var channel = Guid.NewGuid().ToString();
137 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => actionCalled = true);
138 | 
139 |             // Act
140 |             TinyPubSubLib.TinyPubSub.Publish(channel);
141 | 
142 |             // Assert
143 |             Assert.True(actionCalled);
144 |         }
145 | 
146 |         [Fact]
147 |         public void SubscribePublishExceptionHandling()
148 |         {
149 |             // Arrange
150 |             var wasSuccessful = false;
151 |             var channel = Guid.NewGuid().ToString();
152 |             var subId = TinyPubSubLib.TinyPubSub.Subscribe(channel, () => throw new Exception("Error in handling"));
153 |             TinyPubSubLib.TinyPubSub.Subscribe(TinyException.DefaultChannel, (msg) => wasSuccessful = msg.SubscriptionTag == subId);
154 | 
155 |             // Act
156 |             TinyPubSubLib.TinyPubSub.Publish(channel);
157 | 
158 |             // Assert
159 |             Assert.True(wasSuccessful);
160 |         }
161 | 
162 |         [Fact]
163 |         public async Task DelayedSubscribePublishTest()
164 |         {
165 |             // Arrange
166 |             var actionCalled = false;
167 |             var channel = Guid.NewGuid().ToString();
168 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => actionCalled = true);
169 | 
170 |             // Act
171 |             TinyPubSubLib.TinyPubSub.PublishAsFireAndForgetTask(channel);
172 |             await Task.Delay(100);
173 | 
174 |             // Assert
175 |             Assert.True(actionCalled);
176 |         }
177 | 
178 |         [Fact]
179 |         public async Task DelayedSubscribePublishWithArgumentsTest()
180 |         {
181 |             // Arrange
182 |             var actionCalled = false;
183 |             var channel = Guid.NewGuid().ToString();
184 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (x) => actionCalled = x == "duck");
185 | 
186 |             // Act
187 |             TinyPubSubLib.TinyPubSub.PublishAsFireAndForgetTask(channel, "duck");
188 |             await Task.Delay(100);
189 | 
190 |             // Assert
191 |             Assert.True(actionCalled);
192 |         }
193 | 
194 |         [Fact]
195 |         public async Task PublishAsyncTest()
196 |         {
197 |             // Arrange
198 |             var actionCalled = false;
199 |             var channel = Guid.NewGuid().ToString();
200 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => actionCalled = true);
201 | 
202 |             // Act
203 |             await TinyPubSubLib.TinyPubSub.PublishAsync(channel);
204 | 
205 |             // Assert
206 |             Assert.True(actionCalled);
207 |         }
208 |         
209 |         [Fact]
210 |         public void ShouldThrowExceptionIfNoChannelWasProvidedWhenSubscribing()
211 |         {
212 |             // Arrange
213 |             Func act = () => TinyPubSubLib.TinyPubSub.Subscribe(null, () => { });
214 | 
215 |             // Act
216 |             act.Should().ThrowExactly();
217 |         }
218 |         
219 |         [Fact]
220 |         public void ShouldThrowExceptionIfNoChannelWasProvidedWhenPublishing()
221 |         {
222 |             // Arrange
223 |             var actionCalled = false;
224 |             var channel = Guid.NewGuid().ToString();
225 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => actionCalled = true);
226 |             Func act = () => TinyPubSubLib.TinyPubSub.PublishControlled(null);
227 |             
228 |             // Act
229 |             act.Should().ThrowExactly();
230 |             actionCalled.Should().BeFalse();
231 |         }
232 | 
233 |         [Fact]
234 |         public async Task PublishAsyncWithExceptionTest()
235 |         {
236 |             // Arrange
237 |             var wasSuccessful = true;
238 |             var channel = Guid.NewGuid().ToString();
239 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => throw new Exception());
240 | 
241 |             // Act
242 |             await TinyPubSubLib.TinyPubSub.PublishAsync(channel);
243 | 
244 |             // Assert
245 |             Assert.True(wasSuccessful);
246 |         }
247 | 
248 |         [Fact]
249 |         public async Task PublishWithOnErrorActionTest()
250 |         {
251 |             // Arrange
252 |             var wasSuccessful = true;
253 |             var channel = Guid.NewGuid().ToString();
254 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => throw new Exception("Boom"));
255 | 
256 |             // Act
257 |             await TinyPubSubLib.TinyPubSub.PublishAsync(channel, onError: (ex, s) => wasSuccessful = ex.Message == "Boom");
258 | 
259 |             // Assert
260 |             Assert.True(wasSuccessful);
261 |         }
262 | 
263 |         [Fact]
264 |         public void PublishWithEventArgsTest()
265 |         {
266 |             // Arrange
267 |             var wasSuccessful = true;
268 |             var channel = Guid.NewGuid().ToString();
269 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, (_, args) => args.HaltExecution = true);
270 |             TinyPubSubLib.TinyPubSub.Subscribe(channel, () => wasSuccessful = false); // This subscription should never be called
271 | 
272 |             // Act
273 |             TinyPubSubLib.TinyPubSub.PublishControlled(channel);
274 | 
275 |             // Assert
276 |             Assert.True(wasSuccessful);
277 |         }
278 | 
279 |         [Fact]
280 |         public void ShouldHandleSubscriptionWithOwner()
281 |         {
282 |             // Arrange
283 |             var actionCalled = false;
284 |             var channel = Guid.NewGuid().ToString();
285 |             var owner = new object();
286 |             var tag = TinyPubSubLib.TinyPubSub.Subscribe(owner, channel, x => actionCalled = x == "duck");
287 | 
288 |             // Act
289 |             TinyPubSubLib.TinyPubSub.Publish(channel, "duck");
290 | 
291 |             // Assert
292 |             actionCalled.Should().BeTrue();
293 |             tag.Should().NotBeNull();
294 |         }
295 |         
296 |         [Fact]
297 |         public void ShouldHandleSubscriptionForTypeWithReturningEventArgs()
298 |         {
299 |             // Arrange
300 |             var actionCalled = false;
301 |             var channel = Guid.NewGuid().ToString();
302 |             var tag = TinyPubSubLib.TinyPubSub.Subscribe(channel, (x, args) =>
303 |             {
304 |                 actionCalled = x.Sklep == 42;
305 |                 args.HaltExecution = true;
306 |             });
307 | 
308 |             // Act
309 |             TinyPubSubLib.TinyPubSub.Publish(channel, new TestEventType
310 |                 { Sklep = 42});
311 | 
312 |             // Assert
313 |             actionCalled.Should().BeTrue();
314 |             tag.Should().NotBeNull();
315 |         }
316 |         
317 |         [Fact]
318 |         public async Task ShouldPublishControlledAsyncWithoutExceptionHandlingAction()
319 |         {
320 |             // Arrange
321 |             var actionCalled = false;
322 |             var channel = Guid.NewGuid().ToString();
323 |             var tag = TinyPubSubLib.TinyPubSub.Subscribe(channel, x =>
324 |             {
325 |                 actionCalled = x == "Duck";
326 |             });
327 | 
328 |             // Act
329 |             await TinyPubSubLib.TinyPubSub.PublishControlledAsync(channel, "Duck");
330 |             await Task.Delay(100);
331 | 
332 |             // Assert
333 |             actionCalled.Should().BeTrue();
334 |             tag.Should().NotBeNull();
335 |         }
336 |         
337 |         [Fact]
338 |         public async Task ShouldPublishControlledAsyncWithExceptionHandlingAction()
339 |         {
340 |             // Arrange
341 |             var onErrorWasCalled = false;
342 |             var channel = Guid.NewGuid().ToString();
343 |             var tag = TinyPubSubLib.TinyPubSub.Subscribe(channel, x => throw new Exception("Something went bad"));
344 | 
345 |             // Act
346 |             await TinyPubSubLib.TinyPubSub.PublishControlledAsync(channel, "Duck", (exception, subscription) => onErrorWasCalled = true);
347 |             await Task.Delay(100);
348 | 
349 |             // Assert
350 |             onErrorWasCalled.Should().BeTrue();
351 |             tag.Should().NotBeNull();
352 |         }
353 |     }
354 | }
355 | 


--------------------------------------------------------------------------------
/src/TinyPubSub.Tests/TinyPubSub.Tests.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     net6.0
 5 | 
 6 |     false
 7 |   
 8 | 
 9 |   
10 |     
11 |     
12 |     
13 |     
14 |       all
15 |       runtime; build; native; contentfiles; analyzers; buildtransitive
16 |     
17 |   
18 | 
19 |   
20 |     
21 |   
22 | 
23 | 


--------------------------------------------------------------------------------
/src/TinyPubSub.sln:
--------------------------------------------------------------------------------
  1 | 
  2 | Microsoft Visual Studio Solution File, Format Version 12.00
  3 | # Visual Studio 15
  4 | VisualStudioVersion = 15.0.27130.2027
  5 | MinimumVisualStudioVersion = 10.0.40219.1
  6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{26E23983-3BE9-4A60-9A25-EB4CC67EFAAB}"
  7 | EndProject
  8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Forms.Sample", "samples\Forms\Forms.Sample\Forms.Sample.csproj", "{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}"
  9 | EndProject
 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Forms.Sample.Droid", "samples\Forms\Droid\Forms.Sample.Droid.csproj", "{66DD93B6-4755-419A-8CD6-B968196D5253}"
 11 | EndProject
 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Forms.Sample.iOS", "samples\Forms\iOS\Forms.Sample.iOS.csproj", "{2127250D-EC02-4077-A35A-ABACE46ABBFA}"
 13 | EndProject
 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TinyPubSub", "TinyPubSub\TinyPubSub.csproj", "{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}"
 15 | EndProject
 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TinyPubSub.Forms", "TinyPubSub.Forms\TinyPubSub.Forms.csproj", "{598F6C45-7597-4059-A9FD-6D440AAA4EA7}"
 17 | EndProject
 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TinyPubSub.Tests", "TinyPubSub.Tests\TinyPubSub.Tests.csproj", "{668BF359-30E9-4C60-8942-CA9C9558EAEE}"
 19 | EndProject
 20 | Global
 21 | 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 22 | 		Debug|Any CPU = Debug|Any CPU
 23 | 		Debug|iPhone = Debug|iPhone
 24 | 		Debug|iPhoneSimulator = Debug|iPhoneSimulator
 25 | 		Release|Any CPU = Release|Any CPU
 26 | 		Release|iPhone = Release|iPhone
 27 | 		Release|iPhoneSimulator = Release|iPhoneSimulator
 28 | 		Release-CI|Any CPU = Release-CI|Any CPU
 29 | 		Release-CI|iPhone = Release-CI|iPhone
 30 | 		Release-CI|iPhoneSimulator = Release-CI|iPhoneSimulator
 31 | 	EndGlobalSection
 32 | 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 33 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 34 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|Any CPU.Build.0 = Debug|Any CPU
 35 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|iPhone.ActiveCfg = Debug|Any CPU
 36 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|iPhone.Build.0 = Debug|Any CPU
 37 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
 38 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
 39 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|Any CPU.ActiveCfg = Release|Any CPU
 40 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|Any CPU.Build.0 = Release|Any CPU
 41 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|iPhone.ActiveCfg = Release|Any CPU
 42 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|iPhone.Build.0 = Release|Any CPU
 43 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 44 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 45 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release-CI|Any CPU.ActiveCfg = Release-CI|Any CPU
 46 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release-CI|Any CPU.Build.0 = Release-CI|Any CPU
 47 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release-CI|iPhone.ActiveCfg = Release-CI|Any CPU
 48 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release-CI|iPhone.Build.0 = Release-CI|Any CPU
 49 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436}.Release-CI|iPhoneSimulator.ActiveCfg = Release-CI|Any CPU
 50 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 51 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|Any CPU.Build.0 = Debug|Any CPU
 52 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|iPhone.ActiveCfg = Debug|Any CPU
 53 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|iPhone.Build.0 = Debug|Any CPU
 54 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
 55 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
 56 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|Any CPU.ActiveCfg = Release|Any CPU
 57 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|Any CPU.Build.0 = Release|Any CPU
 58 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|iPhone.ActiveCfg = Release|Any CPU
 59 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|iPhone.Build.0 = Release|Any CPU
 60 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 61 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 62 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|Any CPU.ActiveCfg = Release-CI|Any CPU
 63 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|Any CPU.Build.0 = Release-CI|Any CPU
 64 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|Any CPU.Deploy.0 = Release-CI|Any CPU
 65 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|iPhone.ActiveCfg = Release-CI|Any CPU
 66 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|iPhone.Build.0 = Release-CI|Any CPU
 67 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|iPhone.Deploy.0 = Release-CI|Any CPU
 68 | 		{66DD93B6-4755-419A-8CD6-B968196D5253}.Release-CI|iPhoneSimulator.ActiveCfg = Release-CI|Any CPU
 69 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
 70 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
 71 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|iPhone.ActiveCfg = Debug|iPhone
 72 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|iPhone.Build.0 = Debug|iPhone
 73 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
 74 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
 75 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|Any CPU.ActiveCfg = Release|iPhone
 76 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|Any CPU.Build.0 = Release|iPhone
 77 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|iPhone.ActiveCfg = Release|iPhone
 78 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|iPhone.Build.0 = Release|iPhone
 79 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
 80 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
 81 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release-CI|Any CPU.ActiveCfg = Release-CI|iPhone
 82 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release-CI|iPhone.ActiveCfg = Release-CI|iPhone
 83 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release-CI|iPhone.Build.0 = Release-CI|iPhone
 84 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA}.Release-CI|iPhoneSimulator.ActiveCfg = Release-CI|iPhoneSimulator
 85 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 86 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 87 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
 88 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|iPhone.Build.0 = Debug|Any CPU
 89 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
 90 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
 91 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 92 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|Any CPU.Build.0 = Release|Any CPU
 93 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|iPhone.ActiveCfg = Release|Any CPU
 94 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|iPhone.Build.0 = Release|Any CPU
 95 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
 96 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
 97 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|Any CPU.ActiveCfg = Release|Any CPU
 98 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|Any CPU.Build.0 = Release|Any CPU
 99 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|iPhone.ActiveCfg = Release|Any CPU
100 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|iPhone.Build.0 = Release|Any CPU
101 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|iPhoneSimulator.ActiveCfg = Release|Any CPU
102 | 		{3D0DEDB9-2407-46BB-983B-60AFE4EA909C}.Release-CI|iPhoneSimulator.Build.0 = Release|Any CPU
103 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
104 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
105 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
106 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|iPhone.Build.0 = Debug|Any CPU
107 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
108 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
109 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
110 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|Any CPU.Build.0 = Release|Any CPU
111 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|iPhone.ActiveCfg = Release|Any CPU
112 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|iPhone.Build.0 = Release|Any CPU
113 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
114 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
115 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|Any CPU.ActiveCfg = Release|Any CPU
116 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|Any CPU.Build.0 = Release|Any CPU
117 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|iPhone.ActiveCfg = Release|Any CPU
118 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|iPhone.Build.0 = Release|Any CPU
119 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|iPhoneSimulator.ActiveCfg = Release|Any CPU
120 | 		{598F6C45-7597-4059-A9FD-6D440AAA4EA7}.Release-CI|iPhoneSimulator.Build.0 = Release|Any CPU
121 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
122 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
123 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
124 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|iPhone.Build.0 = Debug|Any CPU
125 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
126 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
127 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
128 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|Any CPU.Build.0 = Release|Any CPU
129 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|iPhone.ActiveCfg = Release|Any CPU
130 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|iPhone.Build.0 = Release|Any CPU
131 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
132 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
133 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|Any CPU.ActiveCfg = Release|Any CPU
134 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|Any CPU.Build.0 = Release|Any CPU
135 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|iPhone.ActiveCfg = Release|Any CPU
136 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|iPhone.Build.0 = Release|Any CPU
137 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|iPhoneSimulator.ActiveCfg = Release|Any CPU
138 | 		{668BF359-30E9-4C60-8942-CA9C9558EAEE}.Release-CI|iPhoneSimulator.Build.0 = Release|Any CPU
139 | 	EndGlobalSection
140 | 	GlobalSection(SolutionProperties) = preSolution
141 | 		HideSolutionNode = FALSE
142 | 	EndGlobalSection
143 | 	GlobalSection(NestedProjects) = preSolution
144 | 		{A1258ABE-5D5F-46FA-AF37-00D37EF9D436} = {26E23983-3BE9-4A60-9A25-EB4CC67EFAAB}
145 | 		{66DD93B6-4755-419A-8CD6-B968196D5253} = {26E23983-3BE9-4A60-9A25-EB4CC67EFAAB}
146 | 		{2127250D-EC02-4077-A35A-ABACE46ABBFA} = {26E23983-3BE9-4A60-9A25-EB4CC67EFAAB}
147 | 	EndGlobalSection
148 | 	GlobalSection(ExtensibilityGlobals) = postSolution
149 | 		SolutionGuid = {BBAA39AC-E35A-4D5A-B894-A703F40E3FF3}
150 | 	EndGlobalSection
151 | EndGlobal
152 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/ISubscription.cs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * The MIT License (MIT)
 3 |  * Copyright (c) 2016 Johan Karlsson
 4 |  *
 5 |  * Permission is hereby granted, free of charge, to any person obtaining a copy 
 6 |  * of this software and associated documentation files (the "Software"), to deal 
 7 |  * in the Software without restriction, including without limitation the rights 
 8 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 9 |  * copies of the Software, and to permit persons to whom the Software is furnished 
10 |  * to do so, subject to the following conditions:
11 |  *
12 |  * The above copyright notice and this permission notice shall be included in 
13 |  * all copies or substantial portions of the Software.
14 |  * 
15 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
18 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
20 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
21 |  * DEALINGS IN THE SOFTWARE.
22 |  *
23 |  */
24 | 
25 | using System;
26 | 
27 | namespace TinyPubSubLib
28 | {
29 |     public interface ISubscription
30 |     {
31 |         Action Action { get; set; }
32 | 
33 |         Action ActionWithArgument { get; }
34 | 
35 |         string Tag { get; set; }
36 | 
37 |         Type SubscribeToType { get; set; }
38 | 
39 |         bool RemoveAfterUse { get; set; }
40 | 
41 |         WeakReference Owner { get; set; }
42 |     }
43 | 
44 | }
45 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/Subscription.cs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * The MIT License (MIT)
  3 |  * Copyright (c) 2016 Johan Karlsson
  4 |  *
  5 |  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  6 |  * of this software and associated documentation files (the "Software"), to deal 
  7 |  * in the Software without restriction, including without limitation the rights 
  8 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  9 |  * copies of the Software, and to permit persons to whom the Software is furnished 
 10 |  * to do so, subject to the following conditions:
 11 |  *
 12 |  * The above copyright notice and this permission notice shall be included in 
 13 |  * all copies or substantial portions of the Software.
 14 |  * 
 15 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 16 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 17 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 18 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 20 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 21 |  * DEALINGS IN THE SOFTWARE.
 22 |  *
 23 |  */
 24 | 
 25 | using System;
 26 | 
 27 | namespace TinyPubSubLib
 28 | {
 29 |     /// 
 30 |     /// Represents one subscription
 31 |     /// 
 32 |     internal class Subscription : ISubscription
 33 |     {
 34 |         /// 
 35 |         /// Order of executing subscriptions.
 36 |         /// 
 37 |         /// Since a user can halt execution of subscriptions, the order in which they
 38 |         /// are added matters. It was a List<T> earlier, now i't a Dictionary<T> which
 39 |         /// does not guarantee the order when enumerating. So we need to sort.
 40 |         public int Order { get; set; }
 41 |         
 42 |         public Action Action { get; set; }
 43 | 
 44 |         public Action ActionWithArgument { get; set; }
 45 | 
 46 |         public Action ActionWithArgumentAndArgs { get; set; }
 47 | 
 48 |         Action ISubscription.ActionWithArgument => ActionWithArgument as Action;
 49 | 
 50 |         public string Tag { get; set; }
 51 | 
 52 |         public Type SubscribeToType { get; set; }
 53 | 
 54 |         public WeakReference Owner { get; set; }
 55 | 
 56 |         public bool RemoveAfterUse { get; set; }
 57 | 
 58 |         internal Subscription()
 59 |         {
 60 |             Tag = Guid.NewGuid().ToString();
 61 |             SubscribeToType = typeof(T);
 62 |         }
 63 | 
 64 |         public Subscription(Action action, bool removeAfterUse = false, int order = 0) : this()
 65 |         {
 66 |             Action = action;
 67 |             RemoveAfterUse = removeAfterUse;
 68 |             Order = order;
 69 |         }
 70 | 
 71 |         public Subscription(Action action, bool removeAfterUse = false, int order = 0) : this()
 72 |         {
 73 |             ActionWithArgument = action;
 74 |             SubscribeToType = typeof(T);
 75 |             RemoveAfterUse = removeAfterUse;
 76 |             Order = order;
 77 |         }
 78 | 
 79 |         public Subscription(object owner, Action action, bool removeAfterUse = false, int order = 0) : this(action)
 80 |         {
 81 |             Owner = new WeakReference(owner);
 82 |             RemoveAfterUse = removeAfterUse;
 83 |             Order = order;
 84 |         }
 85 | 
 86 |         public Subscription(object owner, Action action, bool removeAfterUse = false, int order = 0) : this(action)
 87 |         {
 88 |             RemoveAfterUse = removeAfterUse;
 89 |             Owner = new WeakReference(owner);
 90 |             Order = order;
 91 |         }
 92 | 
 93 |         public Subscription(Action action, bool removeAfterUse = false, int order = 0) : this()
 94 |         {
 95 |             ActionWithArgumentAndArgs = action;
 96 |             RemoveAfterUse = removeAfterUse;
 97 |             Order = order;
 98 |         }
 99 | 
100 |         public Subscription(object owner, Action action, bool removeAfterUse = false, int order = 0) : this(action)
101 |         {
102 |             Owner = new WeakReference(owner);
103 |             RemoveAfterUse = removeAfterUse;
104 |             Order = order;
105 |         }
106 |     }
107 | }
108 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/TinyEventArgs.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | 
 3 | namespace TinyPubSubLib
 4 | {
 5 |     public class TinyEventArgs
 6 |     {
 7 |         public bool Handled { get; set; }
 8 |         public bool HaltExecution { get; set; }
 9 |         public object StateObject { get; set; }
10 |     }
11 | }
12 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/TinyException.cs:
--------------------------------------------------------------------------------
 1 | /*
 2 |  * The MIT License (MIT)
 3 |  * Copyright (c) 2016 Johan Karlsson
 4 |  *
 5 |  * Permission is hereby granted, free of charge, to any person obtaining a copy 
 6 |  * of this software and associated documentation files (the "Software"), to deal 
 7 |  * in the Software without restriction, including without limitation the rights 
 8 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 9 |  * copies of the Software, and to permit persons to whom the Software is furnished 
10 |  * to do so, subject to the following conditions:
11 |  *
12 |  * The above copyright notice and this permission notice shall be included in 
13 |  * all copies or substantial portions of the Software.
14 |  * 
15 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
16 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
17 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
18 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
20 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
21 |  * DEALINGS IN THE SOFTWARE.
22 |  *
23 |  */
24 | 
25 | using System;
26 | 
27 | namespace TinyPubSubLib
28 | {
29 |     public class TinyException
30 |     {
31 | 
32 |         public static readonly string DefaultChannel = "TinyException";
33 | 
34 |         public string Message
35 |         {
36 |             get;
37 |             set;
38 |         }
39 | 
40 |         public Exception InnerException
41 |         {
42 |             get;
43 |             set;
44 |         }
45 | 
46 |         public string SubscriptionTag { get; set; }
47 |     }
48 | }
49 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/TinyPubSub.cs:
--------------------------------------------------------------------------------
  1 | /*
  2 |  * The MIT License (MIT)
  3 |  * Copyright (c) 2016 Johan Karlsson
  4 |  *
  5 |  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  6 |  * of this software and associated documentation files (the "Software"), to deal 
  7 |  * in the Software without restriction, including without limitation the rights 
  8 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  9 |  * copies of the Software, and to permit persons to whom the Software is furnished 
 10 |  * to do so, subject to the following conditions:
 11 |  *
 12 |  * The above copyright notice and this permission notice shall be included in 
 13 |  * all copies or substantial portions of the Software.
 14 |  * 
 15 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 16 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 17 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 18 |  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 20 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 21 |  * DEALINGS IN THE SOFTWARE.
 22 |  *
 23 |  */
 24 | 
 25 | using System.Threading;
 26 | 
 27 | namespace TinyPubSubLib
 28 | {
 29 |     using System;
 30 |     using System.Collections.Concurrent;
 31 |     using System.Collections.Generic;
 32 |     using System.Linq;
 33 |     using System.Reflection;
 34 |     using System.Threading.Tasks;
 35 | 
 36 |     public static class TinyPubSub
 37 |     {
 38 |         private static readonly ConcurrentDictionary> Channels = new ConcurrentDictionary>();
 39 |         private static int order;
 40 |         
 41 |         private static ConcurrentDictionary GetOrCreateChannel(string channel)
 42 |         {
 43 |             if (string.IsNullOrWhiteSpace(channel))
 44 |             {
 45 |                 throw new ArgumentException("You have to provide a channel name");
 46 |             }
 47 |             
 48 |             return Channels.GetOrAdd(channel, key => new ConcurrentDictionary());
 49 |         }
 50 | 
 51 |         private static ISubscription CreateAndAdd(object owner, string channel, Action action, bool disableAfterFirstUse = false)
 52 |         {
 53 |             Interlocked.Increment(ref order);
 54 |             
 55 |             var current = GetOrCreateChannel(channel);
 56 |             var subscription = new Subscription(owner, action, disableAfterFirstUse, order);
 57 |             current.TryAdd(subscription, subscription);
 58 |             return subscription;
 59 |         }
 60 | 
 61 |         private static ISubscription CreateAndAdd(object owner, string channel, Action action, bool disableAfterFirstUse = false)
 62 |         {
 63 |             Interlocked.Increment(ref order);
 64 |             
 65 |             var current = GetOrCreateChannel(channel);
 66 |             var subscription = new Subscription(owner, action, disableAfterFirstUse, order);
 67 |             current.TryAdd(subscription, subscription);
 68 |             return subscription;
 69 |         }
 70 | 
 71 |         private static ISubscription CreateAndAdd(object owner, string channel, Action action, bool disableAfterFirstUse = false)
 72 |         {
 73 |             Interlocked.Increment(ref order);
 74 |             
 75 |             var current = GetOrCreateChannel(channel);
 76 |             var subscription = new Subscription(owner, action, disableAfterFirstUse, order);
 77 |             current.TryAdd(subscription, subscription);
 78 |             return subscription;
 79 |         }
 80 | 
 81 |         /// 
 82 |         /// Occurs when on subscription removed.
 83 |         /// 
 84 |         public static event EventHandler OnSubscriptionRemoved;
 85 | 
 86 |         /// 
 87 |         /// Subscribe to a channel.
 88 |         /// 
 89 |         /// The channel name.
 90 |         /// The action to run.
 91 |         /// A tag that can be used to unsubscribe.
 92 |         public static string Subscribe(string channel, Action action)
 93 |         {
 94 |             var subscription = CreateAndAdd(null, channel, action);
 95 |             return subscription.Tag;
 96 |         }
 97 | 
 98 |         /// 
 99 |         /// Subscribe to a channel that sends an argument.
100 |         /// 
101 |         /// The channel name.
102 |         /// The action to run.
103 |         /// A tag that can be used to unsubscribe.
104 |         public static string Subscribe(string channel, Action action)
105 |         {
106 |             var subscription = CreateAndAdd(null, channel, action);
107 |             return subscription.Tag;
108 |         }
109 | 
110 |         /// 
111 |         /// Subscribe to a channel.
112 |         /// 
113 |         /// The owner of the subscription. 
114 |         /// The channel name.
115 |         /// The action to run.
116 |         /// A tag that can be used to unsubscribe.
117 |         /// The owner can be used to make a mass-unsubscription by 
118 |         /// calling Unsubscribe and pass the same object.
119 |         public static string Subscribe(object owner, string channel, Action action)
120 |         {
121 |             var subscription = CreateAndAdd(owner, channel, action);
122 |             return subscription.Tag;
123 |         }
124 | 
125 |         /// 
126 |         /// Subscribe to a channel that sends an argument.
127 |         /// 
128 |         /// The owner of the subscription. 
129 |         /// The channel name.
130 |         /// The action to run.
131 |         /// A tag that can be used to unsubscribe.
132 |         /// The owner can be used to make a mass-unsubscription by 
133 |         /// calling Unsubscribe and pass the same object.
134 |         public static string Subscribe(object owner, string channel, Action action)
135 |         {
136 |             var subscription = CreateAndAdd(owner, channel, action);
137 |             return subscription.Tag;
138 |         }
139 | 
140 |         /// 
141 |         /// Subscribe to a channel that sends an argument.
142 |         /// 
143 |         /// The subscription tag.
144 |         /// The channel name.
145 |         /// The action to run.
146 |         /// The type to subscribe to.
147 |         public static string Subscribe(string channel, Action action)
148 |         {
149 |             var subscription = CreateAndAdd(null, channel, action);
150 |             return subscription.Tag;
151 |         }
152 | 
153 |         /// 
154 |         /// Subscribes to a channel with an argument and control flow event.
155 |         /// 
156 |         /// The subscription tag.
157 |         /// The channel to subscribe to.
158 |         /// The action to execute.
159 |         public static string Subscribe(string channel, Action action)
160 |         {
161 |             var subscription = CreateAndAdd(null, channel, action);
162 |             return subscription.Tag;
163 |         }
164 | 
165 |         /// 
166 |         /// Subscribe to a channel that sends an argument with specified owner.
167 |         /// 
168 |         /// The subscription tag
169 |         /// /// The owner of the subscription. 
170 |         /// The channel name.
171 |         /// The action to run.
172 |         /// The type to subscribe to.
173 |         public static string Subscribe(object owner, string channel, Action action)
174 |         {
175 |             var subscription = CreateAndAdd(owner, channel, action);
176 |             return subscription.Tag;
177 |         }
178 | 
179 |         /// 
180 |         /// Subscribe to a channel that sends an argument with specified owner and TinyEventArgs to be able to cancel execution and specify if the event has been handled.
181 |         /// 
182 |         /// The subscribe.
183 |         /// The owner of the subscription - used for automatic deregistration.
184 |         /// The channel to subscribe to.
185 |         /// Action with T and TinyEventArgs for execution handling and publish return.
186 |         /// The type to subscribe to.
187 |         public static string Subscribe(object owner, string channel, Action action)
188 |         {
189 |             var subscription = CreateAndAdd(owner, channel, action);
190 |             return subscription.Tag;
191 |         }
192 | 
193 |         /// 
194 |         /// Subscribe to a channel that sends an argument with specified owner and TinyEventArgs to be able to cancel execution and specify if the event has been handled.
195 |         /// 
196 |         /// The subscription tag
197 |         /// The channel to subscribe to
198 |         /// Action with T and TinyEventArgs for execution handling and publish return.
199 |         /// The type to subscribe to.
200 |         public static string Subscribe(string channel, Action action)
201 |         {
202 |             var subscription = CreateAndAdd(null, channel, action);
203 |             return subscription.Tag;
204 |         }
205 | 
206 |         /// 
207 |         /// Unsubscribes to a channel based on a tag
208 |         /// 
209 |         /// 
210 |         public static void Unsubscribe(string tag)
211 |         {
212 |             foreach (var channel in Channels.Values)
213 |             {
214 |                 foreach (var subscription in channel.Keys.Where(subscription => subscription.Tag == tag))
215 |                 {
216 |                     channel.TryRemove(subscription, out var _);
217 |                     OnSubscriptionRemoved?.Invoke(null, subscription);
218 |                 }
219 |             }
220 |         }
221 | 
222 |         /// 
223 |         /// Unsubscribes to a channel based on an object owner
224 |         /// 
225 |         /// The owner object
226 | 		public static void Unsubscribe(object owner)
227 |         {
228 |             if (owner == null)
229 |             {
230 |                 return;
231 |             }
232 | 
233 |             foreach (var channel in Channels.Values)
234 |             {
235 |                 var subscriptionsToRemove = new List();
236 | 
237 |                 foreach (var subscription in channel.Keys)
238 |                 {
239 |                     if(subscription.Owner.Target == null)
240 |                     {
241 |                         subscriptionsToRemove.Add(subscription);
242 |                     }
243 |                     else if (subscription.Owner.Target == owner)
244 |                     {
245 |                         channel.TryRemove(subscription, out var _);
246 |                         OnSubscriptionRemoved?.Invoke(owner, subscription);
247 |                     }
248 |                 }
249 | 
250 |                 foreach(var subscription in subscriptionsToRemove)
251 |                 {
252 |                     channel.TryRemove(subscription,out _);
253 |                 }
254 |             }
255 |         }
256 | 
257 |         /// 
258 |         /// Publish an event to the specified channel with instance argument.
259 |         /// 
260 |         /// The channel name
261 |         /// Instance of an object to pass to the receiver. Think argument.
262 |         /// Called if there is an error executing the subscription.
263 |         /// The 1st type parameter.
264 |         public static void Publish(string channel, T instance, Action onError = null)
265 |         {
266 |             PublishControlled(channel, instance, onError);
267 |         }
268 | 
269 |         /// 
270 |         /// Publish a controlled event to the specified channel with instance argument and returns when the event is handled.
271 |         /// 
272 |         /// The result of the call.
273 |         /// The channel name.
274 |         /// Instance of an object to pass to the receiver. Think argument.
275 |         /// Called if there is an error executing the subscription.
276 |         public static TinyEventArgs PublishControlled(string channel, string instance = default(string), Action onError = null)
277 |         {
278 |             return PublishControlled(channel, instance, onError);
279 |         }
280 | 
281 |         /// 
282 |         /// Publish a controlled event to the specified channel with instance argument and returns when the event is handled.
283 |         /// 
284 |         /// The result of the call.
285 |         /// The channel name.
286 |         /// The argument to pass.
287 |         /// Called if there is an error executing the subscription.
288 |         public static async Task PublishControlledAsync(string channel, string argument = default, Action onError = null)
289 |         {
290 |             return await Task.Run(() => PublishControlled(channel, argument, onError)).ConfigureAwait(false);
291 |         }
292 | 
293 |         /// 
294 |         /// Publish a controlled event to the specified channel with instance argument and returns when the event is handled.
295 |         /// 
296 |         /// The result of the call
297 |         /// The channel name
298 |         /// Instance of an object to pass to the receiver. Think argument.
299 |         /// Called if there is an error executing the subscription.
300 |         /// The 1st type parameter.
301 |         public static async Task PublishControlledAsync(string channel, T instance, Action onError = null)
302 |         {
303 |             return await Task.Run(() => PublishControlled(channel, instance, onError)).ConfigureAwait(false);
304 |         }
305 | 
306 |         /// 
307 |         /// Publish an event to the specified channel with instance argument and returns when the event is handled.
308 |         /// 
309 |         /// The result of the call
310 |         /// The channel name
311 |         /// Instance of an object to pass to the receiver. Think argument.
312 |         /// Called if there is an error executing the subscription.
313 |         /// The 1st type parameter.
314 |         public static TinyEventArgs PublishControlled(string channel, T instance, Action onError = null)
315 |         {
316 |             if (string.IsNullOrWhiteSpace(channel))
317 |             {
318 |                 throw new ArgumentException("You have to specify a channel to publish to");
319 |             }
320 | 
321 |             var returnEventArgs = new TinyEventArgs();
322 | 
323 |             if (!Channels.TryGetValue(channel, out var current))
324 |             {
325 |                 return returnEventArgs;
326 |             }
327 |             
328 |             var subscriptionsToRemove = new List();
329 | 
330 |             foreach (var subscription in current.Keys.OfType>().OrderBy(s => s.Order))
331 |             {
332 |                 try
333 |                 {
334 |                     if (subscription.Owner.Target == null)
335 |                     {
336 |                         subscriptionsToRemove.Add(subscription);
337 |                     }
338 |                         
339 |                     if (subscription.ActionWithArgumentAndArgs != null)
340 |                     {
341 |                         subscription.ActionWithArgumentAndArgs.Invoke(instance, returnEventArgs);
342 |                     }
343 |                     else
344 |                     {
345 |                         var hasBeenHandled = false;
346 | 
347 |                         if (subscription.Action != null)
348 |                         {
349 |                             subscription.Action.Invoke();
350 |                             hasBeenHandled = true;
351 |                         }
352 |                         else if (subscription.ActionWithArgument != null)
353 |                         {
354 |                             subscription.ActionWithArgument.Invoke(instance);
355 |                             hasBeenHandled = true;
356 |                         }
357 | 
358 |                         returnEventArgs.Handled = hasBeenHandled;
359 |                     }
360 |                 }
361 |                 catch (Exception ex)
362 |                 {
363 |                     onError?.Invoke(ex, subscription);
364 |                     SendException(ex, subscription.Tag);
365 |                 }
366 | 
367 |                 if (subscription.RemoveAfterUse)
368 |                 {
369 |                     Unsubscribe(subscription.Tag);
370 |                 }
371 | 
372 |                 if (returnEventArgs.HaltExecution)
373 |                 {
374 |                     return returnEventArgs;
375 |                 }
376 |             }
377 | 
378 |             foreach(var subscription in subscriptionsToRemove)
379 |             {
380 |                 current.TryRemove(subscription, out _);
381 |             }
382 | 
383 |             // Concept code - fall back to calling each with object
384 |             // this is the way we need to do it for allowing attribute
385 |             // subscription.
386 |             if (typeof(T) != typeof(object))
387 |             {
388 |                 PublishControlled(channel, instance, onError);
389 |             }
390 | 
391 |             return returnEventArgs;
392 |         }
393 | 
394 |         private static void SendException(Exception ex, string tag)
395 |         {
396 |             var message = new TinyException()
397 |             {
398 |                 Message = "Error sending event to receiver: " + ex.Message,
399 |                 InnerException = ex,
400 |                 SubscriptionTag = tag
401 |             };
402 |             
403 |             Publish(TinyException.DefaultChannel, message);
404 |         }
405 | 
406 |         /// 
407 |         /// Publish an event the specified channel.
408 |         /// 
409 |         /// The channel name
410 |         /// The argument to pass.
411 |         /// Called if there is an error executing the subscription.
412 |         public static void Publish(string channel, string argument = default, Action onError = null)
413 |         {
414 |             Publish(channel, argument, onError);
415 |         }
416 | 
417 |         /// 
418 |         /// Publish using Task.Run
419 |         /// 
420 |         /// The channel to publish to
421 |         /// An optional parameter
422 |         /// Called if there is an error executing the subscription.
423 |         /// This method is not blocking, it simply uses a Task.Run(() => Publish(...)) internally
424 |         /// to hand of the call to be handled by someone else.
425 |         public static void PublishAsFireAndForgetTask(string channel, string argument = default, Action onError = null)
426 |         {
427 |             // Add to delayed handle queue
428 |             Task.Run(() => Publish(channel, argument, onError));
429 |         }
430 | 
431 |         /// 
432 |         /// Publish using Task.Run
433 |         /// 
434 |         /// The channel to publish to
435 |         /// An instance of an object to pass to the handler of the event
436 |         /// Called if there is an error executing the subscription.
437 |         /// This method is not blocking, it simply uses a Task.Run(() => Publish(...)) internally
438 |         /// to hand of the call to be handled by someone else.
439 |         public static void PublishAsFireAndForgetTask(string channel, T instance, Action onError = null)
440 |         {
441 |             Task.Run(() => Publish(channel, instance, onError));
442 |         }
443 | 
444 |         /// 
445 |         /// Publish async
446 |         /// 
447 |         /// The channel to publish to
448 |         /// An optional parameter
449 |         /// Called if there is an error executing the subscription.
450 |         /// A task
451 |         public static Task PublishAsync(string channel, string argument = default(string), Action onError = null)
452 |         {
453 |             // EB: Not necessary to await the task.
454 |             ////await Task.Run(() => Publish(channel, argument, OnError));
455 |             return Task.Run(() => Publish(channel, argument, onError));
456 |         }
457 | 
458 |         /// 
459 |         /// Clears all channels
460 |         /// 
461 |         public static void Clear()
462 |         {
463 |             Channels.Clear();
464 |         }
465 | 
466 |         /// 
467 |         /// Scans an object after attributes to hook up to TinyPubSub
468 |         /// 
469 |         /// The object to scan
470 |         public static void Register(object obj)
471 |         {
472 |             //// TODO: EB: Move the reflection code to a separate type, for performance - add a cache (ConcurrentDictionary) to scanned objects and use expressions to invoke the subscriber methods instead of method.Invoke()..
473 | 
474 |             var typeInfo = obj.GetType().GetTypeInfo();
475 | 
476 |             foreach (var method in typeInfo.DeclaredMethods)
477 |             {
478 |                 var attributes = method.GetCustomAttributes(typeof(TinySubscribeAttribute)).OfType();
479 | 
480 |                 foreach (var attribute in attributes)
481 |                 {
482 |                     var channel = attribute.Channel;
483 | 
484 |                     var methodParameters = method.GetParameters();
485 | 
486 |                     if (methodParameters.Length > 0)
487 |                     {
488 |                         // Concept code for subscriptions
489 |                         Subscribe(obj, channel, (data) => method.Invoke(obj, new[] { data }));
490 |                     }
491 |                     else
492 |                     {
493 |                         // Register without parameters since the target method has none
494 |                         Subscribe(obj, channel, () => method.Invoke(obj, null));
495 |                     }
496 |                 }
497 |             }
498 |         }
499 | 
500 |         public static void Deregister(object obj)
501 |         {
502 |             TinyPubSub.Unsubscribe(obj);
503 |         }
504 |     }
505 | }
506 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/TinyPubSub.csproj:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     netstandard1.1;netstandard2.0;net6.0;
 5 |     TinyPubSubLib
 6 |     Release-CI;Debug;Release
 7 |     true
 8 |   
 9 | 
10 |   
11 | 
12 |   
13 |     TinyPubSub
14 |     johankson and dhindrik
15 |     A very simple pub/sub implementation for .net.
16 |     false
17 |     Formatted package name
18 |     Copyright 2017-2022 - Johan Karlsson and Daniel Hindrikes
19 |     PubSub .net
20 |     http://i.imgur.com/p0xJYYC.png
21 |     https://github.com/TinyStuff/TinyPubSub
22 |     https://opensource.org/licenses/MIT
23 |   
24 | 
25 |   
26 |     
27 |   
28 | 
29 | 


--------------------------------------------------------------------------------
/src/TinyPubSub/TinySubscribeAttribute.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | namespace TinyPubSubLib
 3 | {
 4 |     [AttributeUsage(AttributeTargets.Method, AllowMultiple=true)]
 5 |     public class TinySubscribeAttribute : Attribute
 6 |     {
 7 |         public string Channel
 8 |         {
 9 |             get;
10 |             set;
11 |         }
12 | 
13 |         public TinySubscribeAttribute(string channel)
14 |         {
15 |             Channel = channel;
16 |         }
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
 1 | Any raw assets you want to be deployed with your application can be placed in
 2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
 3 | 
 4 | These files will be deployed with your package and will be accessible using Android's
 5 | AssetManager, like this:
 6 | 
 7 | public class ReadAsset : Activity
 8 | {
 9 | 	protected override void OnCreate (Bundle bundle)
10 | 	{
11 | 		base.OnCreate (bundle);
12 | 
13 | 		InputStream input = Assets.Open ("my_asset.txt");
14 | 	}
15 | }
16 | 
17 | Additionally, some Android functions will automatically load asset files:
18 | 
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
20 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Forms.Sample.Droid.csproj:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |     Debug
  5 |     AnyCPU
  6 |     {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
  7 |     {66DD93B6-4755-419A-8CD6-B968196D5253}
  8 |     Library
  9 |     Forms.Sample.Droid
 10 |     Assets
 11 |     Resources
 12 |     Properties\AndroidManifest.xml
 13 |     Resource
 14 |     Resources\Resource.designer.cs
 15 |     True
 16 |     True
 17 |     TinyPubSub.Sample.Droid
 18 |     v8.0
 19 |     
 20 |     
 21 |   
 22 |   
 23 |     true
 24 |     full
 25 |     false
 26 |     bin\Debug
 27 |     DEBUG;
 28 |     prompt
 29 |     4
 30 |     None
 31 |     false
 32 |   
 33 |   
 34 |     full
 35 |     true
 36 |     bin\Release
 37 |     prompt
 38 |     4
 39 |     false
 40 |     false
 41 |   
 42 |   
 43 |     bin\Release-CI\
 44 |     true
 45 |     full
 46 |     AnyCPU
 47 |     Off
 48 |     prompt
 49 |     MinimumRecommendedRules.ruleset
 50 |   
 51 |   
 52 |     
 53 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll
 54 |     
 55 |     
 56 |     
 57 |     
 58 |     
 59 |     
 60 |       ..\..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll
 61 |     
 62 |     
 63 |       ..\..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll
 64 |     
 65 |     
 66 |       ..\..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll
 67 |     
 68 |     
 69 |       ..\..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll
 70 |     
 71 |     
 72 |       ..\..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll
 73 |     
 74 |     
 75 |       ..\..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll
 76 |     
 77 |     
 78 |       ..\..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll
 79 |     
 80 |     
 81 |       ..\..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll
 82 |     
 83 |     
 84 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll
 85 |     
 86 |     
 87 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll
 88 |     
 89 |     
 90 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll
 91 |     
 92 |     
 93 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll
 94 |     
 95 |   
 96 |   
 97 |     
 98 |       {A1258ABE-5D5F-46FA-AF37-00D37EF9D436}
 99 |       Forms.Sample
100 |     
101 |   
102 |   
103 |     
104 |     
105 |     
106 |   
107 |   
108 |     
109 |     
110 |     
111 |     
112 |   
113 |   
114 |     
115 |     
116 |   
117 |   
118 |     
119 |     
120 |     
121 |     
122 |   
123 |   
124 |   
125 |   
126 |   
127 |   
128 |   
129 |   
130 |     
131 |       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}.
132 |     
133 |     
134 |   
135 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/MainActivity.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using Android.App;
 3 | using Android.Content;
 4 | using Android.Content.PM;
 5 | using Android.Runtime;
 6 | using Android.Views;
 7 | using Android.Widget;
 8 | using Android.OS;
 9 | using TinyPubSubForms.Sample;
10 | 
11 | namespace TinyPubSub.Sample.Droid
12 | {
13 | 	[Activity (Label = "TinyPubSub.Sample.Droid", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
14 | 	public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
15 | 	{
16 | 		protected override void OnCreate (Bundle bundle)
17 | 		{
18 | 			base.OnCreate (bundle);
19 | 
20 | 			global::Xamarin.Forms.Forms.Init (this, bundle);
21 | 
22 | 			LoadApplication (new App ());
23 | 		}
24 | 	}
25 | }


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 	
4 | 	
5 | 	
6 | 
7 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.CompilerServices;
 3 | using Android.App;
 4 | 
 5 | // Information about this assembly is defined by the following attributes.
 6 | // Change them to the values specific to your project.
 7 | 
 8 | [assembly: AssemblyTitle ("TinyPubSub.Sample.Droid")]
 9 | [assembly: AssemblyDescription ("")]
10 | [assembly: AssemblyConfiguration ("")]
11 | [assembly: AssemblyCompany ("")]
12 | [assembly: AssemblyProduct ("")]
13 | [assembly: AssemblyCopyright ("johankarlsson")]
14 | [assembly: AssemblyTrademark ("")]
15 | [assembly: AssemblyCulture ("")]
16 | 
17 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
18 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
19 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
20 | 
21 | [assembly: AssemblyVersion ("1.0.0")]
22 | 
23 | // The following attributes are used to specify the signing key for the assembly,
24 | // if desired. See the Mono documentation for more information about signing.
25 | 
26 | //[assembly: AssemblyDelaySign(false)]
27 | //[assembly: AssemblyKeyFile("")]
28 | 
29 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
 1 | Images, layout descriptions, binary blobs and string dictionaries can be included 
 2 | in your application as resource files.  Various Android APIs are designed to 
 3 | operate on the resource IDs instead of dealing with images, strings or binary blobs 
 4 | directly.
 5 | 
 6 | For example, a sample Android app that contains a user interface layout (main.axml),
 7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png) 
 8 | would keep its resources in the "Resources" directory of the application:
 9 | 
10 | Resources/
11 |     drawable/
12 |         icon.png
13 | 
14 |     layout/
15 |         main.axml
16 | 
17 |     values/
18 |         strings.xml
19 | 
20 | In order to get the build system to recognize Android resources, set the build action to
21 | "AndroidResource".  The native Android APIs do not operate directly with filenames, but 
22 | instead operate on resource IDs.  When you compile an Android application that uses resources, 
23 | the build system will package the resources for distribution and generate a class called "R" 
24 | (this is an Android convention) that contains the tokens for each one of the resources 
25 | included. For example, for the above Resources layout, this is what the R class would expose:
26 | 
27 | public class R {
28 |     public class drawable {
29 |         public const int icon = 0x123;
30 |     }
31 | 
32 |     public class layout {
33 |         public const int main = 0x456;
34 |     }
35 | 
36 |     public class strings {
37 |         public const int first_string = 0xabc;
38 |         public const int second_string = 0xbcd;
39 |     }
40 | }
41 | 
42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main 
43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first 
44 | string in the dictionary file values/strings.xml.
45 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Resources/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/src/samples/Forms/Droid/Resources/drawable-hdpi/icon.png


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Resources/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/src/samples/Forms/Droid/Resources/drawable-xhdpi/icon.png


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Resources/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/src/samples/Forms/Droid/Resources/drawable-xxhdpi/icon.png


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/Resources/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TinyStuff/TinyPubSub/a28cf7f342e695d6aaaa73eef2bdc06a4deb5131/src/samples/Forms/Droid/Resources/drawable/icon.png


--------------------------------------------------------------------------------
/src/samples/Forms/Droid/packages.config:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |   
 5 |   
 6 |   
 7 |   
 8 |   
 9 |   
10 |   
11 |   
12 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/Forms.Sample.csproj:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 |   
  4 |     Debug
  5 |     AnyCPU
  6 |     {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
  7 |     {A1258ABE-5D5F-46FA-AF37-00D37EF9D436}
  8 |     Library
  9 |     Forms.Sample
 10 |     TinyPubSub.Sample
 11 |     v4.6
 12 |     Profile44
 13 |     
 14 |     
 15 |     10.0
 16 |   
 17 |   
 18 |     true
 19 |     full
 20 |     false
 21 |     bin\Debug
 22 |     DEBUG;
 23 |     prompt
 24 |     4
 25 |     false
 26 |   
 27 |   
 28 |     full
 29 |     true
 30 |     bin\Release
 31 |     prompt
 32 |     4
 33 |     false
 34 |   
 35 |   
 36 |     bin\Release-CI\
 37 |     true
 38 |     full
 39 |     AnyCPU
 40 |     prompt
 41 |     MinimumRecommendedRules.ruleset
 42 |   
 43 |   
 44 |     
 45 |     
 46 |     
 47 |       MainView.xaml
 48 |     
 49 |     
 50 |     
 51 |       DuckView.xaml
 52 |     
 53 |     
 54 |     
 55 |   
 56 |   
 57 |   
 58 |   
 59 |   
 60 |   
 61 |     
 62 |       {598f6c45-7597-4059-a9fd-6d440aaa4ea7}
 63 |       TinyPubSub.Forms
 64 |     
 65 |     
 66 |       {3d0dedb9-2407-46bb-983b-60afe4ea909c}
 67 |       TinyPubSub
 68 |     
 69 |   
 70 |   
 71 |     
 72 |       MSBuild:UpdateDesignTimeXaml
 73 |     
 74 |     
 75 |       MSBuild:UpdateDesignTimeXaml
 76 |     
 77 |   
 78 |   
 79 |     
 80 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll
 81 |       True
 82 |     
 83 |     
 84 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll
 85 |       True
 86 |     
 87 |     
 88 |       ..\..\..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll
 89 |       True
 90 |     
 91 |   
 92 |   
 93 |     
 94 |       Designer
 95 |     
 96 |   
 97 |   
 98 |   
 99 |     
100 |       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}.
101 |     
102 |     
103 |   
104 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
 1 | using System.Reflection;
 2 | using System.Runtime.CompilerServices;
 3 | 
 4 | // Information about this assembly is defined by the following attributes.
 5 | // Change them to the values specific to your project.
 6 | 
 7 | [assembly: AssemblyTitle ("TinyPubSub.Sample")]
 8 | [assembly: AssemblyDescription ("")]
 9 | [assembly: AssemblyConfiguration ("")]
10 | [assembly: AssemblyCompany ("")]
11 | [assembly: AssemblyProduct ("")]
12 | [assembly: AssemblyCopyright ("johankarlsson")]
13 | [assembly: AssemblyTrademark ("")]
14 | [assembly: AssemblyCulture ("")]
15 | 
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 | 
20 | [assembly: AssemblyVersion ("1.0.*")]
21 | 
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 | 
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 | 
28 | 


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/TinyPubSub.Sample.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using TinyPubSubLib;
 3 | 
 4 | using Xamarin.Forms;
 5 | using Views;
 6 | 
 7 | namespace TinyPubSubForms.Sample
 8 | {
 9 | 	public class App : Application
10 | 	{
11 | 		public App ()
12 | 		{
13 |             // If you are using forms, then Init before setting the main view to automate the
14 |             // unsubscription of events.
15 |             TinyPubSubLib.TinyPubSubForms.Init(this);
16 | 
17 | 			// The root page of your application
18 | 			var navPage = new NavigationPage(new MainView());
19 | 
20 |             // If you don't use the TinyPubSubForms.Init(..) method you can register the events yourself like this
21 | 			// navPage.Popped += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext);
22 | 			// navPage.PoppedToRoot += (object sender, NavigationEventArgs e) => TinyPubSub.Unsubscribe(e.Page.BindingContext);
23 | 			
24 | 			MainPage = navPage;
25 | 		}
26 | 
27 | 		protected override void OnStart ()
28 | 		{
29 | 			// Handle when your app starts
30 | 		}
31 | 
32 | 		protected override void OnSleep ()
33 | 		{
34 | 			// Handle when your app sleeps
35 | 		}
36 | 
37 | 		protected override void OnResume ()
38 | 		{
39 | 			// Handle when your app resumes
40 | 		}
41 | 	}
42 | }


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/ViewModels/DuckViewModel.cs:
--------------------------------------------------------------------------------
 1 | 
 2 | using Xamarin.Forms;
 3 | using TinyPubSubLib;
 4 | using System.Windows.Input;
 5 | using Views;
 6 | using System.ComponentModel;
 7 | 
 8 | namespace ViewModels
 9 | {
10 | 
11 |     public class DuckViewModel : ViewModelBase, INotifyPropertyChanged
12 | 	{
13 |         int duckCount = 1;
14 | 
15 |         public event PropertyChangedEventHandler PropertyChanged;
16 | 
17 |         public int DuckCount
18 |         {
19 |             get
20 |             {
21 |                 return duckCount;
22 |             }
23 | 
24 |             set
25 |             {
26 |                 duckCount = value;
27 |             }
28 |         }
29 | 
30 |         public DuckViewModel ()
31 | 		{
32 |             TinyPubSub.Subscribe (this, "fire", () => 
33 | 			{ 
34 | 				// This line should not be fired when the page is navigated away from
35 | 				int i = 10;
36 | 			});	
37 |             TinyPubSubLib.TinyPubSubForms.SubscribeOnMainThread("onmain",(obj) => {
38 |                 DuckCount++;
39 |                 PropertyChanged(this, new PropertyChangedEventArgs("DockCount"));
40 |             });
41 | 		}
42 | 
43 | 		public ICommand PopToRoot 
44 | 		{
45 | 			get {
46 | 				return new Command (async () => await Navigation.PopToRootAsync ());
47 | 			}
48 | 		}
49 | 
50 | 		public ICommand ViewAnotherDuck
51 | 		{
52 | 			get {
53 | 				return new Command (async () => await Navigation.PushAsync (new DuckView ()));
54 | 			}
55 | 		}
56 | 	}
57 | }


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using System.Windows.Input;
 3 | using Xamarin.Forms;
 4 | using TinyPubSubLib;
 5 | using Views;
 6 | using System.ComponentModel;
 7 | 
 8 | namespace ViewModels
 9 | {
10 |     public class MainViewModel : ViewModelBase, INotifyPropertyChanged
11 | 	{
12 |         int duckCount = 1;
13 | 
14 |         public event PropertyChangedEventHandler PropertyChanged;
15 | 
16 |         public int DuckCount
17 |         {
18 |             get
19 |             {
20 |                 return duckCount;
21 |             }
22 | 
23 |             set
24 |             {
25 |                 duckCount = value;
26 |             }
27 |         }
28 | 
29 | 		public MainViewModel ()
30 | 		{
31 | 			TinyPubSub.Subscribe ("fire", () => 
32 | 				{ 
33 |  					// Do something here, but nuget was down at the time of writing this code
34 | 				});	
35 | 
36 |             TinyPubSub.Subscribe("firebool",(obj) => {
37 |                 _toggleBool = obj;
38 |                 TheBool = _toggleBool;
39 |             });
40 | 
41 |             TinyPubSubLib.TinyPubSubForms.SubscribeOnMainThread("onmain", (obj) => {
42 |                 DuckCount++;
43 |                 PropertyChanged(this, new PropertyChangedEventArgs("DuckCount"));
44 |             });
45 | 		}
46 | 
47 |         public bool TheBool 
48 |         {
49 |             get 
50 |             {
51 |                 return _toggleBool;
52 |             }
53 |             set 
54 |             {
55 |                 _toggleBool = value;
56 |                 PropertyChanged(this, new PropertyChangedEventArgs("TheBool"));
57 |             }
58 |         }
59 | 
60 |         private bool _toggleBool = false;
61 | 
62 | 		public ICommand Fire {
63 | 			get {
64 | 				return new Command (() => {
65 | 					TinyPubSub.Publish("fire");
66 | 				});
67 | 			}
68 | 		}
69 | 
70 |         public ICommand Fire2
71 |         {
72 |             get
73 |             {
74 |                 return new Command(() => {
75 |                     TinyPubSub.Publish("firebool",!_toggleBool);
76 |                 });
77 |             }
78 |         }
79 |         
80 |         public ICommand Fire3
81 |         {
82 |             get
83 |             {
84 |                 return new Command(() => {
85 |                     TinyPubSub.Publish("onmain");
86 |                 });
87 |             }
88 |         }
89 | 
90 | 		public ICommand NavigateToDuck {
91 | 			get {
92 | 				return new Command (async () => {
93 | 					await Navigation.PushAsync(new DuckView());
94 | 				});
95 | 			}
96 | 		}
97 | 	}
98 | }


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
 1 | using System;
 2 | using Xamarin.Forms;
 3 | 
 4 | namespace ViewModels
 5 | {
 6 | 	public class ViewModelBase
 7 | 	{
 8 | 		public INavigation Navigation {
 9 | 			get;
10 | 			set;
11 | 		}
12 | 	}
13 | }


--------------------------------------------------------------------------------
/src/samples/Forms/Forms.Sample/Views/DuckView.xaml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 	
 4 | 		
 5 |