ReactiveUI: Turning MVVM up to 11
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Anzahl der Teile | 170 | |
Autor | ||
Lizenz | CC-Namensnennung - keine kommerzielle Nutzung - Weitergabe unter gleichen Bedingungen 3.0 Unported: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen und nicht-kommerziellen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen und das Werk bzw. diesen Inhalt auch in veränderter Form nur unter den Bedingungen dieser Lizenz weitergeben | |
Identifikatoren | 10.5446/50582 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
|
00:00
QuellcodeKontextbezogenes SystemHackerBildschirmfensterTwitter <Softwareplattform>SchaltwerkOpen SourceKünstliches LebenKartesische KoordinatenTermRichtungFormale SpracheSystemplattformComputeranimation
00:42
Coxeter-GruppeDatenmodellCodecWidgetVolumenvisualisierungTouchscreenCodeSynchronisierungSichtenkonzeptSchnelltasteGrenzschichtablösungCoxeter-GruppeDatenverwaltungProgrammierungBildschirmfensterSichtenkonzeptEin-AusgabeMusterspracheTouchscreenEndliche ModelltheorieApp <Programm>Framework <Informatik>BitInteraktives FernsehenMereologieWeb logProjektive EbeneTermGewicht <Ausgleichsrechnung>Graphische BenutzeroberflächeSchnelltasteUmwandlungsenthalpieCodeGraphfärbungRichtungFormale SpracheSystemplattformTextbausteinAvatar <Informatik>ComputerspielDivergente ReiheGüte der AnpassungEntscheidungstheorieSynchronisierungInterface <Schaltung>Intelligentes NetzAppletGamecontrollerZeichenketteEinschließungssatzSoundverarbeitungKartesische KoordinatenMomentenproblemWeb SiteProzess <Informatik>SkriptspracheMathematikGruppenoperationMultiplikationsoperatorTropfenComputeranimation
04:30
Gewicht <Ausgleichsrechnung>App <Programm>Humanoider RoboterFunktionalProgrammierungEreignishorizontMaßstabProzess <Informatik>MaßerweiterungInterface <Schaltung>Strom <Mathematik>AusnahmebehandlungLuenberger-BeobachterDualitätstheorieSpielkonsoleSummierbarkeitSichtenkonzeptBildschirmfensterSpannweite <Stochastik>StichprobeMomentenproblemGewicht <Ausgleichsrechnung>SpeicherabzugCodeQuick-SortProgrammierungNichtlinearer OperatorVersionsverwaltungErweiterungRechter WinkelApp <Programm>ImplementierungFunktionalGrundraumInhalt <Mathematik>SystemplattformMultiplikationsoperatorVollständigkeitGeradeProgrammfehlerÄhnlichkeitsgeometrieFolge <Mathematik>Mailing-ListeSchnittmengeDifferenteTreiber <Programm>ZahlenbereichSpannweite <Stochastik>CASE <Informatik>VerschlingungMereologieEreignishorizontObjekt <Kategorie>SystemaufrufAusnahmebehandlungSchreib-Lese-KopfPay-TVDatensatzFamilie <Mathematik>Weg <Topologie>LoopSynchronisierungBus <Informatik>DatenbankProzess <Informatik>ZweiVisualisierungBetafunktionKardinalzahlLambda-KalkülInterface <Schaltung>QuaderStrömungsrichtungDualitätstheorieGraphiktablettAbzählenProgrammierumgebungTransformation <Mathematik>ComputeranimationBesprechung/Interview
11:14
SpielkonsoleComputermusikSichtenkonzeptBildschirmfensterSummierbarkeitGleitendes MittelKonvexe HülleEin-AusgabeLuenberger-BeobachterKontrollstrukturSchedulingThreadElektronische UnterschriftSynchronisierungFehlermeldungTaskVirtuelle MaschineLokales MinimumGammafunktionHill-DifferentialgleichungAusnahmebehandlungPhysikalisches SystemSchnelltasteMathematische LogikEreignishorizontVakuumRohdatenKonfigurationsraumInstantiierungDatenmodellVerschlingungTermStreaming <Kommunikationstechnik>Fahne <Mathematik>SchaltnetzMultiplikationQuick-SortKartesische KoordinatenLeistungsbewertungKlassische PhysikFunktion <Mathematik>RuhmasseDienst <Informatik>TouchscreenEndliche ModelltheorieBAYESSichtenkonzeptBildschirmfensterDifferenteProgrammfehlerThreadHalbleiterspeicherGraphiktablettZahlenbereichServerSchreib-Lese-KopfReibungswärmeSchlüsselverwaltungMessage-PassingEreignishorizontPlastikkarteGruppenoperationCodeMailing-ListeAuflösung <Mathematik>PunktEinfach zusammenhängender RaumSoftwaretestSystemaufrufRechter WinkelDemo <Programm>Diskrete-Elemente-MethodeCursorMathematikSoftwareschwachstelleVollständigkeitWechselsprungQuaderEinsApp <Programm>ResultanteWurm <Informatik>UnrundheitLuenberger-BeobachterSpezielle unitäre GruppeCodecTaskAusnahmebehandlungNichtlinearer OperatorDatensichtgerätSchedulingEigentliche AbbildungTypentheorieRepository <Informatik>Kollaboration <Informatik>StörungstheorieDemoszene <Programmierung>Computeranimation
17:46
Weg <Topologie>SpeicherabzugDean-ZahlVerzeichnisdienstBildschirmfensterSichtenkonzeptInterface <Schaltung>StatistikPhysikalisches SystemKonfigurationsraumGebäude <Mathematik>InstantiierungHilfesystemBetafunktionVersionsverwaltungFramework <Informatik>VideokonferenzEndliche ModelltheorieTaskDienst <Informatik>VektorrechnungMathematikAusnahmebehandlungSummierbarkeitZeichenketteGewicht <Ausgleichsrechnung>Elektronische UnterschriftSynchronisierungLastRegulärer Ausdruck <Textverarbeitung>Kategorie <Mathematik>SynchronisierungEreignishorizontNatürliche ZahlQuick-SortMultiplikationsoperatorWort <Informatik>MultiplikationGruppenoperationZahlenbereichPunktObjekt <Kategorie>Projektive EbeneEndliche ModelltheorieSichtenkonzeptSystemaufrufURLDemo <Programm>DatensatzInterface <Schaltung>MereologieInformationsüberlastungSpeicherabzugEinsDienst <Informatik>Kategorie <Mathematik>Klassische PhysikUmwandlungsenthalpieApp <Programm>Computeranimation
21:22
BildschirmfensterKategorie <Mathematik>Regulärer Ausdruck <Textverarbeitung>ZeichenketteSichtenkonzeptDienst <Informatik>Arbeit <Physik>RechenwerkGammafunktionRich Media ContentMathematikGruppenoperationMessage-PassingQuaderSichtenkonzeptKategorie <Mathematik>GarbentheorieSpeicherabzugResultanteDatensatzEndliche ModelltheorieBrennen <Datenverarbeitung>UnrundheitComputeranimation
22:56
GammafunktionBildschirmfensterSichtenkonzeptLie-GruppeAusnahmebehandlungEmulationLemma <Logik>Normierter RaumMathematische LogikAnalog-Digital-UmsetzerFontGewicht <Ausgleichsrechnung>Inklusion <Mathematik>Gesetz <Physik>ThreadPhysikalisches SystemFunktion <Mathematik>Prozess <Informatik>Abelsche KategorieSingularität <Mathematik>Dienst <Informatik>QuellcodeZeichenketteLuenberger-BeobachterFolge <Mathematik>LoopMessage-PassingSynchronisierungKontextbezogenes SystemObjekt <Kategorie>Kategorie <Mathematik>ProgrammschemaSchedulingATMRechenwerkSoftwaretestHöhere ProgrammierspracheTaupunktEinfache GenauigkeitGruppenoperationThreadPunktRechenschieberUmwandlungsenthalpieQuick-SortLuenberger-BeobachterKartesische KoordinatenZweiMereologieMathematikSchedulingApp <Programm>MultifunktionEreignishorizontFlächentheorieGesetz <Physik>GlättungGeradeComputeranimation
25:50
BeschreibungskomplexitätInformationsmanagementBildschirmfensterSichtenkonzeptVirtuelle MaschineRechenwerkGammafunktionFehlermeldungSynchronisierungTaskElektronische UnterschriftAusnahmebehandlungThreadPhysikalisches SystemFunktion <Mathematik>Prozess <Informatik>Abelsche KategorieMenütechnikZeichenketteGesetz <Physik>GEDCOMAggregatzustandSchedulingLokales MinimumDienst <Informatik>RohdatenDivisionZufallszahlenClientKategorie <Mathematik>BitQuick-SortNichtlinearer OperatorResultanteHyperbelverfahrenImplementierungLuenberger-BeobachterMultiplikationsoperatorThreadDienst <Informatik>MultiplikationInteraktives FernsehenAggregatzustandTaskInformationsüberlastungGeradeZweiTypentheorieInstantiierungObjekt <Kategorie>GrenzschichtablösungElektronische UnterschriftMomentenproblemMathematikMessage-PassingSoftwaretestMapping <Computergraphik>AusnahmebehandlungSichtenkonzeptPunktGerichteter GraphPräkonditionierungFunktionalGraphfärbungPay-TVSkalarproduktGroßrechnerEndliche ModelltheorieOvalSoundverarbeitungComputeranimation
33:18
ZeichenketteBildschirmfensterSichtenkonzeptDienst <Informatik>VideokonferenzHöhere ProgrammierspracheGruppenoperationMathematikResultanteProjektive EbeneFramework <Informatik>AggregatzustandElektronische UnterschriftNichtflüchtiger SpeicherFunktionalComputeranimation
35:14
Elektronischer DatenaustauschSichtenkonzeptBildschirmfensterZeichenketteFehlermeldungAusnahmebehandlungDienst <Informatik>Hill-DifferentialgleichungTaupunktZufallszahlenClientEreignishorizontParametersystemLastSummierbarkeitRechenwerkLokales MinimumHilfesystemPrimzahlzwillingeGammafunktionEndliche ModelltheorieDeklarative ProgrammierspracheSchnelltasteDemoszene <Programmierung>Fächer <Mathematik>Endliche ModelltheorieFunktionalPunktTaskAusnahmebehandlungAggregatzustandGruppenoperationSystemplattformCodeQuick-SortRichtungStreaming <Kommunikationstechnik>Güte der AnpassungSchnelltasteFehlermeldungLuenberger-BeobachterResultanteObjekt <Kategorie>Nichtlinearer OperatorKategorie <Mathematik>SichtenkonzeptSCI <Informatik>Lesen <Datenverarbeitung>SinusfunktionBitMailing-ListeSynchronisierungFahne <Mathematik>Grundsätze ordnungsmäßiger DatenverarbeitungDiskrete UntergruppeDemo <Programm>Humanoider RoboterBoolesche AlgebraROM <Informatik>Computeranimation
40:46
ClientVirtuelle MaschineBildschirmfensterSichtenkonzeptPartielle DifferentiationDatenmodellProgrammbibliothekEigentliche AbbildungKategorie <Mathematik>HydrostatikMailing-ListePhysikalisches SystemLokales MinimumBenutzeroberflächep-BlockFontMathematische LogikMultiplikationsoperatorUmwandlungsenthalpieNabel <Mathematik>StichprobenumfangKategorie <Mathematik>QuaderSichtenkonzeptSchnelltasteEndliche ModelltheorieRechter WinkelComputerspielGruppenoperationTypentheorieComputeranimation
42:58
Physikalisches SystemNabel <Mathematik>SichtenkonzeptBildschirmfensterHöhere ProgrammierspracheRechenwerkFehlermeldungKategorie <Mathematik>HIP <Kommunikationsprotokoll>Lokales MinimumSchnelltasteHook <Programmierung>Kontextbezogenes SystemBitSichtenkonzeptMathematikMultiplikationsoperatorEndliche ModelltheorieMehrrechnersystemWärmeleitfähigkeitObjekt <Kategorie>Kategorie <Mathematik>Computeranimation
44:33
SichtenkonzeptWeg <Topologie>StatistikPERM <Computer>Interface <Schaltung>Virtuelle RealitätVirtuelle MaschineBildschirmfensterVerzeichnisdienstFehlermeldungSpeicherabzugBitmap-GraphikIndexberechnungSchreib-Lese-KopfMarketinginformationssystemMatchingDatenmodellPartielle DifferentiationNabel <Mathematik>Kontextbezogenes SystemGammafunktionKategorie <Mathematik>Umsetzung <Informatik>Regulärer Ausdruck <Textverarbeitung>RohdatenZählenAusnahmebehandlungZufallszahlenTaskZeichenketteFramework <Informatik>CodeHIP <Kommunikationsprotokoll>Minkowski-MetrikMailing-ListeSchnittmengeMathematikProdukt <Mathematik>ZweiTypentheorieSichtenkonzeptPunktMailing-ListeSampler <Musikinstrument>MathematikKonstruktor <Informatik>CodeObjekt <Kategorie>Message-PassingSchnelltasteMereologieGlobale OptimierungKategorie <Mathematik>Konfiguration <Informatik>AuswahlverfahrenEndliche ModelltheorieZeichenketteSystemplattformAggregatzustandMAPDatensatzDemo <Programm>SchnittmengeTextbausteinQuick-SortMapping <Computergraphik>FaserbündelDifferenteGebäude <Mathematik>ProgrammverifikationUmwandlungsenthalpieFächer <Mathematik>App <Programm>Ideal <Mathematik>Luenberger-BeobachterFehlermeldungErwartungswertZählenBoolesche AlgebraUmsetzung <Informatik>SchedulingProgramm/QuellcodeComputeranimation
49:33
ZählenRohdatenEmulationBildschirmfensterVirtuelle MaschineSichtenkonzeptLastSpezielle unitäre GruppeVirtuelle RealitätRechenwerkSpielkonsoleZählenMailing-ListeFahne <Mathematik>Objekt <Kategorie>Weg <Topologie>MathematikInteraktives FernsehenTermSystemplattformTouchscreenMaschinenschreibenBitMereologieComputeranimation
50:25
Dienst <Informatik>SichtenkonzeptDeklarative ProgrammierspracheEndliche ModelltheorieSoftwaretestEreignishorizontDatenparallelitätLokales MinimumSynchronisierungNavigierenDifferenteApp <Programm>Humanoider RoboterTouchscreenSystemplattformDienst <Informatik>URLProgrammbibliothekRechter WinkelNichtlinearer OperatorRichtungFramework <Informatik>FunktionalMereologieDatenparallelitätVisualisierungThreadDatenstrukturTaskKurvenanpassungQuick-SortBandmatrixStreaming <Kommunikationstechnik>Endliche ModelltheorieSichtenkonzeptNP-hartes ProblemWarpingKlassische PhysikCodeMultiplikationsoperatorBitInterface <Schaltung>BildverstehenFunktionale ProgrammierspracheSingularität <Mathematik>ProgrammierungGerichteter GraphErweiterungProgrammfehlerKartesische KoordinatenComputeranimation
53:42
Computeranimation
Transkript: Englisch(automatisch erzeugt)
00:01
So yeah, I'll do the intros while we're waiting for the last few to come in. For those of you who don't know me, my name is Brennan Forster. I work at GitHub on the Windows team. I do a bunch of open source hacking as well on the side. And if you need to, or if you want to follow me on Twitter or GitHub, my handle is shiftkey. So, apologies for the actual talk reference.
00:21
For those of you who know the movie, this is Spinal Tap. It's a very silly, out of context phrase. I just, yeah, I had to throw that in there and they accepted it. So, yeah, apologies for that. But the fun thing is that I'm going to make up for it with some live coding. It could be great, or it could end up like that.
00:42
And of course, the obligatory remarks here around, there's all these different ways to build out applications. Depending on the platform that you're on and the language that you use, things have picked up. Things have gone in certain directions in terms of what's popular, like versus iOS versus desktop apps on the Windows side. I am not going down that path around which pattern is best.
01:02
I'm just going to focus on MVVM and put all those other feelings aside. So I want to do this talk in three parts. The first part is around how our protagonist discovers this lovely pattern around building out applications and he starts to learn the ins and outs of how the stuff works. The second part is that he's dumped in this situation where he's made a series of bad life decisions
01:23
and he starts questioning everything about this pattern. And of course, the third part is that he comes back, he reflects, he licks his wounds and he comes back fighting with a different tool. Notice the different color of the light saber. But let's go back to the beginning. So in 2004, Martin Fowler wrote up a paper on the pattern called Presentation Model.
01:46
So there are a lot of cool things in this talk around how we should design these things to not be tied to a specific GUI framework. But for me, the real goal out of it was this thing called a presentation model. And so the goal of the presentation model was to encapsulate the data and behavior of a screen
02:02
without it being dependent on a specific UI or set of UI controls. And if you know how this play keeps going, you'll see some hints around the commanding side of things. Again, no spoilers, but hopefully you guys know a little bit about MVVM. But the thing that was in particular interesting here was
02:20
he mentioned how the synchronization code between the presentation model and the view was kind of annoying. He didn't want to write the boilerplate code. And in the actual paper, he mentions Microsoft doing something interesting with .NET and data binding. We skip forward a bit to 2005. And John Gosman, one of the program managers on the then Avalon team,
02:42
wrote up this blog post describing the model view model pattern. He cited presentation model as an influence. But what was different about this was he actually crystallized various concepts around how these interactions should happen. And of course, if we go back further a little bit more, WPF drops in 2006. That's a long time ago.
03:01
But what was interesting about this was they actually had implemented certain interactions between the view and the view model. So of course, we have data binding. Some changes happen in the view model. Things get propagated up to the view. These interfaces, for those of you who don't know, are iNotifyPropertyChanged, iNotifyCollectionChanged. Not many people go down into that. But as soon as you start doing collections in the view,
03:21
that's where iNotifyCollectionChanged comes into it. The flip side of that is the view then sending commands to the view model. So we have this interface called iCommand. Can you do something? And then do something very simple, very plain, very basic. But these are the two pieces that allow us to do our view and view model interactions
03:42
in terms of an actual framework rather than a pattern. These have various benefits around separating concerns, testing, composition, all fairly straightforward stuff. And we have a plethora of frameworks on the .NET stack around doing these MVM frameworks, and they've even branched out into JavaScript and also Java and probably another couple of languages out there
04:03
where these things have kind of become mainstream. We're not here to talk about those. I'm here to talk about reactive UI. You can go to the website there. It's kind of sad we're going to update it as part of the next big release. And reactive UI was started by Mr. Paul Betts. An internal joke, just, yeah, I do want to do his avatar.
04:24
He started that, it was a good couple of years ago. But he's not the only person working on the project. There's about 54 different contributors who have submitted code and got it merged in. And there's a core team of about four or five at the moment working on various things. So yeah, it's not just Paul. There's a community effort around this stuff.
04:40
And what's interesting is that it runs just about everywhere that .NET runs. So the latest version here, which is in beta at the moment, will run on all these platforms and universal apps, which is just new out of Visual Studio 2013 update two. So if you guys are doing Xamarin, if you guys are doing WPF,
05:00
this thing can actually be used in those environments. But reactive UI, the cool thing about it is that it's based on reactive extensions. For those of you who want to kind of learn more about reactive extensions and functional reactive programming, there's a couple of talks on this afternoon. They'll go into more depth than this. I'm not going to worry about that. What's really annoying is they're both at the same time slot.
05:21
But yeah, that's not up to me. So I'm going to do a quick introduction to reactive extensions. Let's see if we can do it in about 10-ish minutes. So who knows what the magic is that makes you able to do a for-each loop in C-sharp? I-numerable or I-numerator?
05:42
Numerator. So yes, I-numerable is one of the common interfaces. But the key thing here is that it's got a public method that has a get enumerator that returns you an I-numerator of T. And inside I-numerator, I'm going to just keep messing that up, we have these two methods, moveNext and current.
06:00
You keep churning through the collection until you're done. You can then check the current collection. Once you get false on moveNext, you're done with the collection. Here's a couple of questions for you. What if the data isn't present when you call moveNext? With numeral collections, it's going to be a blocking call until something comes up. If you're calling off to a database, that first record, you need to pull that stuff in.
06:21
It's not quite great for those scenarios where you need to be asynchronous. What if moveNext throws an exception? Do you just bail out of the collection? Do you bring down the app? You might have to wrap this thing in a try-catch box. It's not great for those situations where the data is unreliable. Of course, numeral collections are great for things like objects,
06:41
but events, particularly in the .NET side, behave very differently. How can we get these things out and do operations on them? At the moment, it's fairly terrible if you have to do event handlers. What happened inside Microsoft Research was this proposal for different interfaces. We have iObservable here, which has a subscribe method
07:02
who takes in an observable, returns a disposable subscription, and then we have iObserver there who has these three steps. Next, onComplete, onException. It's a lot more clear what the behavior of this interface is compared to iNumerator. We can actually see where exception handling is done, the completion is done, and when you enumerate each item.
07:23
If you look at iNumerable and iObservable, they're kind of similar but done in the opposite way. iNumerable returns some sort of object, but iObservable says, give me something to work with, and then I'll return you a small object. iNumerator and iObservable are also similar
07:41
in that we can see the operations are there kind of transformed. This is what, particularly Eric Meyer, who's excellent at talking about this, is sort of the duality. We have these two implementations of a similar concept, but they're done the opposite way. I've got some notes in there around Eric Meyer's white paper in particular
08:02
that was good about it. Talking about stuff is boring. Let's actually do some code. Over here on my machine, I have FizzBuzz. Everyone knows FizzBuzz, right? This is probably the worst implementation of FizzBuzz, but it does the job. I'll run that up like that.
08:20
This is just a quick way to generate a range of numbers. I'm going to flip this around and do observable.range. There's that issue with getEnumerator. iObservable of T doesn't have getEnumerator.
08:41
I don't know how to do a 4H over it. It's a different sort of collection that we're working with here. What I will do, step back out, is just do subscribe,
09:07
and in here, I can then do ex. No, I've got ex, come on.
09:32
What have I done here? I've registered a number of callbacks. The first one is just a lambda that takes in a number. In this case, it's going to be a long,
09:40
and then we do something with it, and then I've got exception handlers and uncompleted handlers. Because I know FizzBuzz isn't going to fail me, I'm not going to put anything in there, but I can do console, right line, done. Run that up, and so there's the same thing.
10:01
One, two, three, four, five. Yep, we do FizzBuzz there, we do FizzBuzz there, and then at the end, it says done. This collection of values there, one at a time, they get fed in to the callback. It then goes, oh, I've got no collections there. I'll call done. What if we wanted to flip this around?
10:21
Rather than doing a set of numbers, I'm going to use this guy here who's called interval. That's been done from seconds one. What this will do is it will just generate a sequence of numbers every second. One, two, three, four, five. This is where things will really start to blow your mind.
10:44
First off, that's a bug. Zero isn't part of the list, and we just keep going down, down, down, down, down. Of course, if I can scroll. Damn you, link pad. You get the picture.
11:00
I'm just going to stop that there. We could just keep that going on and on and on forever, but we also have link operators available. I'm going to fix up this bug on this first line, which says FizzBuzz. I'm going to do .skip. One.
11:24
That is neat. I think I might have found a bug in a link pad. Let's try doing that properly. We've stopped. Yes, that's better.
11:41
We've skipped that first number. We then run the same numbers through the subscriber, and it keeps on going forever and ever just to prove that it's doing that. We'll just watch it go past 30.
12:00
Where is that magic command? Let's do some link pad foo. Thank you.
12:21
We could just let this run forever until we run out of memory or the sun dies out, but let's not do that. If you know skip, you probably also know take in terms of link operators. I'll just do 10 to speed things up. Run that again, and it's done.
12:52
The combination of these streams of data coming in, we can manipulate them using link operators or whatever on earth we want, and then we do some actions with the results.
13:00
We can listen for completions. We can listen for error handlings. This is the essence of Rx. Switching back to my slides. There's a couple of things I didn't mention in that little demo. We have cold observables and hot observables.
13:21
Cold observables are generally what you'll see mostly out there in the wild, and cold observables will not fire until they have a subscription available. I could come back and do that observable.interval, and it will not fire anything until I actually subscribe to it. The opposite of that is obviously hot observables. They'll just keep firing off data forever. It might be something great like mouse movement events.
13:44
There's differences between that, and it's kind of hard to pick that up without experience. The other thing I didn't mention is schedulers. We have these streams of data, but schedulers are how we determine where they're run. You're running in a multi-threaded app. You'll have a main thread, and you'll have a number of background threads. Obviously, you want the right stuff to occur on the right thread
14:02
to make sure your app is performant and your users are happy. Some of the ones that ship in the box are fairly clear on what they do, the task pool for TPL-related stuff. If you want to do stuff on threads, you can use a thread scheduler. This matches for the main thread. There's even some ones for testing as well. My application.
14:21
Let's jump over here. I have this demo app. I'm just going to run it up, and then I'll show you some code. I decided to do a demo around searching for users. All the stuff is up on a GitHub repo that I'll show you the link for at the end.
14:40
Inside here, I start typing. Cool. It broke. I've made a service that's deliberately slow and unreliable to emphasize the asynchrony of stuff. I hope you guys as devs test things on slow connections because your users will have them. I'm just giving myself a very specific pain at this point. It's for demos, honestly.
15:01
Cool. I type that up, and then it succeeds, and then it gets a list of results and displays them to the user. Fairly straightforward, but the magic is just behind here. Of course, I haven't got it at the right spot because screen resolutions are amazing. Awesome. Just note that output window as I'm typing stuff.
15:23
See how it's firing off searches on every character change? If I try and move the cursor back, it also does that. We have this sort of eager search, essentially. What we want to do is we want to make this a lot more lazy and control more of what's going on. If I type like that,
15:43
we've just fired off five searches. Imagine that's going off to some sort of other server. We can do better than that. Let's actually go into what is asynchronous about it. Yeah, and that is absolutely not right. What do we have?
16:01
We have... I'll just show you the view first. This is just using some of Collabo Micro's action messages. I've got some scenarios here where the text is bound to way.
16:20
Actually, it doesn't need to be, but that's detailed. On every key up, I want to trigger off a method on the view model. Awesome. Fairly straightforward, but obviously something is messed up behind the scenes. In my view model, again, we're using Collabo Micro. We have a customer service that we pull in. Then we have a list of customers that we match to pull out. Inside here, here's our method.
16:42
We just run through a few steps here. We clear the customers out. We grab some sort of text. If it's empty, we just don't bother doing a search. Then further down here, we call that to a service. We're using async await because that was super easy to do. We then put those users into a view model
17:03
and then add them to the collection. If something gets wrong, we set this flag. It's a fairly simple method there, but there's a lot going on that we can actually drill down into. Was there anything else? In terms of the magic that's happening here,
17:22
we're just using a classic Collabo Micro application. What I'm going to do here is I'm going to pull in Reactive UI at my next step and just kind of introduce that in and kind of fix the bug and then go deeper into what we can do with Reactive UI.
17:47
First things first, we have this sort of disjoint between the actual search text and the event that fires and the actual action that gets done. We already saw that things got out of sync fairly easily and we saw the command fire multiple times when we didn't really need it to.
18:01
We're going to go fix that up. Inside here, I have... Awesome. Yeah, I need to have a word with the Visual Studio team about this because it's just ridiculous.
18:32
I've just fast-forwarded to a point where I've already installed Reactive UI. I'll just show you the actual packages that it pulls in.
18:57
We have Reactive UI and Reactive UI Core. Then we have, because it's a pen on Rx,
19:02
it just pulls in those packages there. XAML stuff is specifically for WPF apps. Splat is a cross-platform project for doing specific things, service location in particular, and there's a couple of other things that it does in there. Those are the packages that get pulled in as part of this app.
19:21
The first thing I'm going to introduce you to is Reactive Object. Reactive Object has a number of very interesting interfaces on it. You have your INotify property changed that comes from the classic MVVM,
19:40
but there's also other interfaces, custom Reactive UI ones. This gives us a number of cool little features, but first I'm going to fix this stuff up.
20:23
Lucky last. Wouldn't be a demo without some semicolons. Cool. This little one-liner takes care of,
20:41
has the value changed? If we need to, then we update it, and then we do the raise notification change. Very concise, very straightforward way to do all of that in one. And now we get into the Rx stuff. I have this dot,
21:00
just all the user properties there, but I'm going to go W. This is probably the coolest part of Reactive Object. Various overloads for you to say, when anything happens with the view model, give me an observable that I can then work with. I'm just going to do when any VM search text.
21:23
When the search text changes. At its core, there's this thing called IObserveChange. As you get these changes that come in
21:40
from the INotify property changed, we then can turn them into a collection, which we can then work with. That's the actual old and busted way, but I'm just going to do when any value, which is the new way, which takes away the need for this second section at all.
22:03
Like before, I can just subscribe. I'm just going to ignore the text. Then I'll do an async await on the search result.
22:20
Whenever the text changes, let's fire off the search. It builds and it runs. Excellent. Let's watch the text box again. And it did it twice. That was the actual action message in the view. Then the thing in my Reactive View model, totally intended.
22:43
That just confirms that they're both working. I'll delete the action message. Run it.
23:02
Why is it always starting in the middle? How annoying. It's still doing the exact same behavior as we had before. Let's see.
23:21
It's no longer firing when we cursor around. That's getting better. But I want to throttle. I'm using specific Rx terminology here. I want to throttle those events that come through around changing the text and get to this point where it's a smooth sort of search. That is literally a one-liner. One second.
23:49
Let's update it every half a second. And then up again. Awesome. We're getting straight into threads.
24:01
What's happened here is that my action is fired on a background thread. You can see over here. But the collection itself, the observable collection, is actually expecting things to happen on the main thread. How do we fix this? The cheat way.
24:20
Remember how I was mentioning schedulers? Observe on. These are schedulers that ship with Reactive UI. And there are ways for you to easily define what part of your application, or what threads on your application
24:41
you want this stuff to run on. Of course, main thread corresponds with the dispatcher in WPF, or I forget what it is in Android, but it's a specific sort of target you want to go to. I'm just going to choose Rx app main thread scheduler. Back out. F5.
25:05
We do that search. See how it bundled up those three changes? Put them together at once. That's the throttle kicking in.
25:26
A lot better, and it still picks up the changes at the end. It's just not firing for every single character change, which is basically what we want. But this doesn't feel great. Doing things on the main thread scheduler isn't great.
25:40
Let me just switch back to my slides. We ran through those operations there. I'll explain more about this observables and properties, sort of how we can map between the two a little bit later.
26:01
The idea is that we have properties, we can then transform them into observables, we can then do operations on them like any other observable, or we can transfer an observable into a property. We remember that lovely method for updating search results. I'm going to decompose that using what's called the reactive command, the implementation of ICommand in reactive UI.
26:23
Over here.
26:49
Reactive command is also subscribable. Like before, and inside here.
27:21
We're being a little bit more explicit here with how our interactions with the data will then trigger commands behind the scenes, because this isn't actually being interacted with by the user. We're doing the stuff inside the view model. But of course, there's a whole bunch of stuff inside update search results that isn't so great.
27:40
We're doing an await here, so things might take a while. Let me just run this up and show you why that's a concern. We're on the main thread. That's not great. Of course, the async await stuff will yield at the appropriate point,
28:02
but we want this actual search operation to happen in the background, and then we want to actually make some changes on the UI thread, because that's the last possible moment that we can get away with this stuff. There's two sort of steps in here. We have some preconditions.
28:20
We have some mutable state. I want to kill that off at some point. We then have our operation, which will take some time, and then we do some mapping of some data. There's some clear separation between the operation that happens and then what we do with the data that comes back from the service. I'm going to just pull this up with the right curly brace.
28:58
That would be great. Awesome.
29:24
I've just pulled it up inside the command. I'm going to refactor this out in a second to break it out and then just kill this sucker off. I just have a test here that's updating our search results.
29:43
I'm going to just cancel that out. We don't care. If I get time to talk about testing, we will do that. Run that up again. All seems legit.
30:01
Getting people back. We still haven't solved this separation behavior. One of the overloads on reactive command is to create something that you can then specify a task, a function, or an actual passing of an observable.
30:21
We actually have a task here, which is the user's firing off to the search service. That can be the task that we then use inside our command. Then we can move all that other stuff down to the subscription after. Async task.
31:00
I'm not going to do the try catch in here. I'm going to comment out this line because I don't care. ReSharper makes the problem go away.
31:22
I'm just changing the signature on my command to something that will return instances of type inumerable customer. I could fire this thing off multiple times and every time it will then return me a list of customers. Marvelous. Then the actual subscription, rather than getting an object out
31:42
or anything boring, we have our customers. I've done something wrong.
32:10
I probably have. Lots of red. Excellent.
32:37
I'll pull this guy out because he's been duplicated elsewhere.
32:56
That was not what I expected.
33:01
I have a situation where the text is passing in null and then my service is blowing up. Not great, Brendan. Not great. There's another overload in here. I'll just do this.
33:57
I just have the signature around the wrong way.
34:05
Like how with other NVM frameworks you can specify a function that will return a Boolean to indicate whether something can run. ReactiveUI has the same thing, but we just use observables. This little step here is just saying
34:22
whenever the text changes, let's do a filter. Sorry, let's do a projection to say if the text is null or empty, return true, otherwise return false. That then becomes our enable disable state on the command. Do we get any better? Let's see.
34:48
Cool. We didn't fire off the search result there. I've just got my old results, but I didn't do B. It then fires off. Just to prove there's nothing up my sleeve. Blah, blah, blah, blah, blah.
35:24
Much better. The other benefits of update command are these two suckers. Update command dot thrown exceptions.
35:40
This is an observable stream of exceptions that get thrown by the command itself. That function returns a task inside my setup of the command. If exceptions come up with that, they bubble up through here. I just do a subscribe.
36:07
Simple as that. Leave that there.
36:21
Let's see if I can trigger it, make the thing blow up.
36:46
All right, the demo gods are messing with me. Cool. That blows up inside the code. I then continue on.
37:03
It did show up the error. Ignore the fact that the loading got out of sync and I'll come to that one next. This other flag here, we set it when we start the search. We close it off when we complete the search. That's actually something that's exposed on the command.
37:43
An observable stream of booleans. Switch from true to false when the thing is executing. It's loading. Yep, that's all.
38:03
This little bit of syntax says my observable that I've got here, I'm going to map it to this property. It's going to be named this on the view model. Then I've got to do this.
38:33
My observable is property helper, which is that object that I got out of the two property action. I then have the value on it,
38:40
which is the current value of the observable, and I can then use that in the UIs as like a read-only property. And I get to delete even more code, which is just great. Let's run that up.
39:09
Loading as true, loading as false. And error shows up. I then do that.
39:20
Clears and starts loading again. Deleting code and using the actual stuff that's off the command. Let's go. There's one last little thing that I want to look at that's making the list disappear when there's no results, but first off, to do that, I need to talk about bindings.
39:40
Back over here. We found about create, which is the base command, the task one, which allows us to pass in long-running operations, throwing exceptions if we want to bubble things up to the user, and is executing, which lets us then track the state of the command. Observable is property helper, an easy way to turn things into read-only properties.
40:02
We're getting to this point where our view models are becoming more declarative. We're not having so much state lying around in actions, and it's becoming to this point where we have discrete chunks of code all floating around. The other thing that actually wasn't a huge fan of, it's when I found out, well, when I first found out about it, it's absolutely grown on me,
40:21
is the binding syntax in Reactive UI. In XAML land, you have syntax inside, sorry, the binding syntax, but on other platforms, you don't. Reactive UI has this agnostic binding syntax, so behind the scenes, it'll do bindings whether you're on WPF or Android. Because we don't have XAML bindings on all platforms,
40:42
this is what Reactive UI has. In my sample code, let's go to the shell view.
41:07
Inside here, I'm just going to implement this interface, iview4. The thing I really like about these bindings is that they are type-safe. We have a specific view model that we're working against,
41:20
and this will allow us to make sure that at compile time that we have all the right bindings. Of course, this is not right, so I need to have a dependency property.
41:51
When I wire up Reactive UI to use the bindings, we're going to use this dependency property.
42:30
This syntax here, once I actually make a compile, will say the view model's property named search text. I need to bind that to a text property on a text box.
42:44
I come in here and I find my text box like that. I go X, and I then delete all of this code. Close it out. Thank you, ReSharper. Switch back over here.
43:11
Let's see if that works.
43:28
Did I mess something up? Awesome. There's one little bit of magic that I've missed. Probably not found an object. Cool.
43:43
I'm not actually assigning anything to this view model property, which is then not kicking off the bindings. Inside here, I need to hook into data context change because Caliburn Micro is doing that.
44:10
Let's see if that makes any improvement. Bucket something up. Excuse me.
44:29
I'm going to cheat, and I'm just going to skip ahead because I'm running a long time.
44:49
This is the end product, which I know works. Like before, I'm binding my view model property for search text to that.
45:00
I can do one-way bindings for the specific properties. What's interesting here is I have a boolean to a boolean, which is fairly straightforward. If I had a different type of property on the view, there's a selector I can pass in. This guy here is trivial because it's mapping boolean to boolean,
45:22
but if I had different types, so rather than having to do i-value converters, I can just do straight-up funcs that take in a type A and then return a type B. I actually like that because I'm writing more C-sharp and less boilerplate code, which is what converters mostly are. The other thing that's particularly interesting here
45:40
is that I can mix up observables and values. This is my problem with the list. It was appearing when things were loaded but not empty. I've got here just two sets of observables that mix together using combine latest.
46:01
I then do a select to turn it into a visibility, and then I bind that to a property on the view. Let's see if I have all of this right. If I type in some garbage, it stays hidden.
46:24
Yep, error is out. And we get the error message as expected. Let's just have a look at this end product
46:41
and summarize a few things. I didn't have the preconditions as before. Probably the only other optimization that I do is the commands have an object that you get passed in, like old school i-command.
47:01
In an ideal world, I'd love that to be a string, so I don't need to do casting and filling around with all the options, but that's a minor quibble. Inside this guy here, I'm just not passing in anything. Maybe with the text changed, I could then say, pass this through to the command, which will then pass me the latest value, but I'm getting into real async behavior.
47:24
There's my throttle on the main app scheduler. I could probably kill that off, actually. There's my loading property, and then the callback, which is all about binding the data. This is getting towards the zen of reactive UI, which is having your view models, all of the stuff defined in the constructor, but then discrete little chunks,
47:41
because the less code you have at a certain point, it is easier to test and verify what's going on. The rest of it is just plain old properties. I'm not bothering with doing the race and get set of change stuff, because the stuff's defined in the constructor. If they were changing on the fly, then yes, I would do the race and set of change
48:00
to make sure that everything's fine. We did all those bindings. I particularly like it because compilation and using the correct type.
48:22
Yes, there's some things in ReSharper that let you do syntax checking, verification of types, but that's even simpler. Code behind. When I was deep into XAML land a couple years ago, I was of the view that don't do anything in code behind, do it all in XAML. Now that I've found the benefits of these bindings
48:41
and the fact that you can do things a lot more succinctly, I'm happy with doing things in code behind. The thing you've got to watch for is if you want to test this code, then maybe it shouldn't be in view code behind. Just a quick last one. Observable collections. They're actually in this demo. We have a thing in reactive UI called reactive list, because observable collection isn't available on all platforms.
49:02
This is something that we've ported across. For most intents and purposes, it'll behave just like an observable collection, but the fun stuff is that you get hooks. Before an item's added to the list, you can actually subscribe to that step
49:21
and maybe inspect it, manipulate it. Same thing with count changed. That was what I used to get the visibility of the grid to be right. I'll show you that code.
49:40
The reactive list there, when the count changes, just tell me when it's zero, and then that becomes the flag further down. Items changed as well. If your item implements a reactive object, you can also listen to the changes on that. Again, that's a way of the beaten track
50:01
for what we're looking to talk about. That was probably a lot to take in, in terms of I wanted to keep this very simple method, and we ended up going through reactive object, reactive command, and even reactive list a little bit.
50:23
There's some things I didn't actually touch on as part of this talk. Navigation. Navigating between screens is, again, kind of different between platforms. Reactive UI has that. I didn't even want to go into that, because that's so much of an issue. Mobile, it runs on Android and iOS, where you're doing Xamarin stuff. There's some extra things around spending your app
50:41
and bringing it back. That's built into reactive UI. And there's even service location. You could actually pull out all the caliber micro stuff and do service location using that splat library. It's a very powerful framework, and just the fact that we have all this functional reactive stuff in there is just one part of it.
51:00
Some notes about what I've learned. Reactive UI command, I used to hate this interface, and I still do. That's why I use reactive command instead. If you're defining your interfaces, just throw reactive command on there. You'll be fine. The other thing to look for is your view model start to look really more like functional programming, rather than the classic OO style.
51:24
Async everywhere is amazing, but there's some notes. I didn't even get to testing. I'm sorry. The hard parts about reactive UI are sort of the learning curve. We have these streams moving around, and if you're trying to nail down some sort of behavior and you're not looking in the right spot,
51:40
you can be in for a lot of pain. We're experimenting with tools around debugging, that sort of stuff, but it's a way off, and we'd love to get something out there, but yeah, we just haven't had any bandwidth. And make sure that things occur on the right thread. Like before, I was easy to slip up and structure the code in the wrong way. A tool that we like to use for that is Concurrency Visualizer.
52:01
It used to be an add-in as part of the higher-end Visual Studio SKUs, but as of 2013, it's a free add-in. What that does is you run up your application, you'll plug in the visualizer, and you'll do some stuff, and you'll see some things pop up like tasks being started, and then you can see what stuff's occurring on the main thread versus what's occurring on the background threads.
52:22
You'll use that to debug the concurrency of your application, and with Rx stuff, that is absolutely necessary. And of course, Async kind of warps the mind. I can't go back to doing regular programming now, and Rx is just, yeah. So I guess that's me. We've got five, seven minutes for questions.
52:46
Yeah, James. I don't like... Okay, so the question from James was, do you recommend using Async tasks, or would you use observables? I don't like how Async,
53:02
and await, and tasks kind of pervert your API. Like, once you start down this rabbit hole, you'll end up saying, having tasks where they're unnecessary, whereas I used to think that about iObservable, but after doing this stuff for a while, it just feels a lot more natural and less blunt, essentially.
53:23
Cool. Well, I'm going to be around for a little bit for any other questions, and I've got stickers if people want some GitHub swag. Yeah, thanks for your time.