Page 39 - MSDN Magazine, September 2019
P. 39

Figure 7 Charlie.razor Function Block Excerpt
on the UI thread. If the StateHasChanged method is called from a non-UI thread, an exception is raised.
Requesting Qubits from Charlie The Charlie razor page indi- cates the number of qubits sent to Alice and Bob. As Figure 7 shows, this page has slightly more going on in its functions block.
Besides view-model initialization, the page is also tasked with opening a new browser window for both Alice and Bob. It does this by calling JSRuntime.InvokeAsync and using the JavaScript eval function to run JavaScript in the browser. The eval script opens and retains the windows as variables. When the Charlie page’s beforeunload event occurs, the windows are closed. This prevents the accumulation of orphaned browser windows when you stop the debugger.
Be aware that most browsers today block popups by default, or at least request consent before opening one. If this happens, you’ll need to OK the popups and refresh the page. My use of popups in this project is merely as a convenience to open all three actor windows at once.
The Charlie.razor page contains a single dynamic element—a counter that displays the number of qubits that have been dispatched:
<p>Qubit sent count: @Model.QubitSentCount</p>
The value within the paragraph is bound to the view-model’s QubitSentCount property.
When classes derive from Codon.UIModel.ViewModelBase, any implementation of IMessageSubscriber<T> automatically subscribes to messages of type T. CharlieViewModel implements IMessage- Subscriber<RequestQubitsMessage> and IMessageSubscriber<Re- leaseQubitsMessage>; therefore, when a RequestQubitsMessage is published by the AliceViewModel or a ReleaseQubitsMessage is published by BobViewModel, it’s handled within the Charlie- ViewModel class. This is all Charlie is tasked with; he sends out entangled qubits to Alice and Bob when they’re needed.
When CharlieViewModel receives a RequestQubitsMessage, it uses the QOperations instance to retrieve a list of entangled qubit pairs, as shown in Figure 8.
CharlieViewModel then sends the first item of each pair to Alice, and the second to Bob, via the IMessenger.
Finally, QubitSentCount is increased, which updates the Charlie page.
Sending Messages as Alice Let’s take a look at the Alice page and its associated view-model. The AliceViewModel class contains an AsyncActionCommand, which is defined like so:
ICommand sendCommand;
public ICommand SendCommand => sendCommand ??
(sendCommand = new AsyncActionCommand(SendAsync));
Figure 8 CharlieViewModel ReceiveMessageAsync (RequestQubitsMessage) Method
@functions {
bool scriptInvoked;
...
protected override void OnAfterRender() {
if (!scriptInvoked) {
scriptInvoked = true;
jsRuntime.InvokeAsync<object>(“eval”, evalScript); }
}
const string evalScript = @”var w1 = window.open(‘/alice’, ‘_blank’, ‘left=100,top=50,width=500,height=350,toolbar=0,resizable=0’);
var w2 = window.open(‘/bob’, ‘_blank’, ‘left=100,top=500,width=500,height=350,toolbar=0,resizable=0’);
window.addEventListener(‘beforeunload’, function (e) { try {
w1.close();
} catch (err) {} try {
w2.close();
} catch (err) {}
(e || window.event).returnValue = null; return null;
});”; }
downloadable sample code. If you don’t feel like installing Blazor, and just wish to see the app in action, feel free to just run the UWP version. Both applications are identical in behavior.
Porting the app to Blazor was a piece of cake. No code changes were required; NuGet references to the Codon (codonfx.com) MVVM framework were fine and everything just worked.
I chose Blazor’s server-side model for this project to allow me to share a single QuantumSimulator object among the three view-models representing Alice, Bob, and Charlie, and to pass Qubit objects around.
Dissecting the Blazor Application The Blazor application con- tains three Razor pages, shown in Figure 6, representing the three actors: Alice.razor, Bob.razor and Charlie.razor.
Each page has an associated view-model. All three view-models in the project subclass Codon’s ViewModelBase class, which pro- vides built-in support for INotifyPropertyChanged (INPC) events, an IoC container reference, and loosely coupled messaging between components within the application.
Each razor page has a functions block that includes a property for its respective view-model. Here’s the functions block in Alice.razor:
@functions {
AliceViewModel ViewModel { get; set; }
protected override async Task OnInitAsync() {
ViewModel = Dependency.Resolve<AliceViewModel>();
ViewModel.PropertyChanged += (o, e) => Invoke(StateHasChanged); }
}
The view-model is retrieved from Codon’s IoC container during the OnInitAsync method.
View-model property changes don’t automatically cause the page content to update. For that you subscribe to the ViewModelBase classes PropertyChanged event. When the event occurs, the razor page’s StateHasChanged method is called, which triggers an update of the HTML elements that are data-bound to the view-model.
You use the page’s Invoke method to ensure that updates occur
async Task IMessageSubscriber<RequestQubitsMessage>.ReceiveMessageAsync( RequestQubitsMessage message)
{
IList<(Qubit, Qubit)> qubits =
await QOperations.GetEntangledPairsAsync(message.QubitCount);
await Messenger.PublishAsync(new BobQubitMessage(qubits.Select(x => x.Item2))); await Messenger.PublishAsync(new AliceQubitMessage(qubits.Select(x => x.Item1)));
QubitSentCount += message.QubitCount; }
msdnmagazine.com
September 2019 31


































































































   37   38   39   40   41