/// <summary> /// Handles view model update from a browser client. /// </summary> /// <param name="connectionId">Identifies the client connection.</param> /// <param name="vmId">Identifies the view model.</param> /// <param name="iData">View model update.</param> public virtual void OnUpdateVM(string connectionId, string vmId, Dictionary <string, object> data) { bool isRecreated = false; if (!_activeVMs.ContainsKey(vmId)) { // No view model found; it must have expired and needs to be recreated. isRecreated = true; OnRequestVM(connectionId, vmId); if (!_activeVMs.ContainsKey(vmId)) { return; } } // Update the new values from the client to the server view model. var vmInstance = _activeVMs[vmId].Instance; // Invoke the interception delegate. UpdateVMFilter.Invoke(vmId, vmInstance, data, filteredData => { lock (vmInstance) { foreach (var kvp in filteredData as Dictionary <string, object> ) { UpdateVM(vmInstance, kvp.Key, kvp.Value != null ? kvp.Value.ToString() : ""); } } // If the updates cause some properties of this and other view models to change, push those new values back to the client. // For multicast view models, use their PushUpdates method to push to any other connected clients. if (vmInstance is MulticastVM) { vmInstance.PushUpdates(); } else { // Unless the view model was recreated, exclude the changes that trigger this update if their values don't change. if (!isRecreated) { foreach (var kvp in data) { if (vmInstance.IsEqualToChangedPropertyValue(kvp.Key, kvp.Value)) { vmInstance.ChangedProperties.TryRemove(kvp.Key, out object dummy); } } } PushUpdates(); } }); }
/// <summary> /// Handles view model update from a browser client. /// </summary> /// <param name="connectionId">Identifies the client connection.</param> /// <param name="vmId">Identifies the view model.</param> /// <param name="iData">View model update.</param> public virtual void OnUpdateVM(string connectionId, string vmId, Dictionary <string, object> data) { bool isRecreated = false; if (!_activeVMs.ContainsKey(vmId)) { // No view model found; it must have expired and needs to be recreated. isRecreated = true; OnRequestVM(connectionId, vmId); if (!_activeVMs.ContainsKey(vmId)) { return; } } // Update the new values from the client to the server view model. var vmInstance = _activeVMs[vmId].Instance; // Invoke the interception delegate. UpdateVMFilter.Invoke(vmId, vmInstance, data, filteredData => { lock (vmInstance) { foreach (var kvp in filteredData as Dictionary <string, object> ) { UpdateVM(vmInstance, kvp.Key, kvp.Value != null ? kvp.Value.ToString() : ""); // If the view model was recreated, include the changes that trigger this update to overwrite their initial values. if (isRecreated && !vmInstance.ChangedProperties.ContainsKey(kvp.Key)) { vmInstance.ChangedProperties.TryAdd(kvp.Key, kvp.Value); } } } // If the updates cause some properties of this and other view models to change, push those new values back to the client. PushUpdates(); }); }
/// <summary> /// Handles view model update from a browser client. /// </summary> /// <param name="connectionId">Identifies the client connection.</param> /// <param name="vmId">Identifies the view model.</param> /// <param name="iData">View model update.</param> public virtual void OnUpdateVM(string connectionId, string vmId, Dictionary <string, object> data) { bool isRecreated = false; if (!_activeVMs.ContainsKey(vmId)) { // No view model found; it must have expired and needs to be recreated. isRecreated = true; OnRequestVM(connectionId, vmId); if (!_activeVMs.ContainsKey(vmId)) { return; } } // Update the new values from the client to the server view model. var vmInstance = _activeVMs[vmId].Instance; // Invoke the interception delegate. UpdateVMFilter.Invoke(vmId, vmInstance, data, filteredData => { lock (vmInstance) { foreach (var kvp in filteredData as Dictionary <string, object> ) { UpdateVM(vmInstance, kvp.Key, kvp.Value != null ? kvp.Value.ToString() : ""); } } // If the updates cause some properties of this and other view models to change, push those new values back to the client. lock (vmInstance) { var vmInfo = _activeVMs.Values.FirstOrDefault(vm => vm.Instance == vmInstance); var changedProperties = new Dictionary <string, object>(vmInstance.ChangedProperties); // Unless the view model was recreated, exclude the changes that trigger this update if their values don't change. if (!isRecreated) { foreach (var kvp in data) { if (vmInstance.IsEqualToChangedPropertyValue(kvp.Key, kvp.Value)) { changedProperties.Remove(kvp.Key); } } } if (changedProperties.Count > 0) { var vmData = vmInstance.Serialize(changedProperties); PushUpdates(vmInfo, vmData); } if (vmInstance is MulticastVM) { (vmInstance as MulticastVM).PushUpdatesExcept(vmInfo.ConnectionId); } else { vmInstance.AcceptChangedProperties(); } } // Push updates on other view model instances in case they too change. foreach (var vmInfo in _activeVMs.Values.Where(vm => vm.Instance != vmInstance)) { PushUpdates(vmInfo); } }); }
/// <summary> /// Handles view model update from a browser client. /// </summary> /// <param name="connectionId">Identifies the client connection.</param> /// <param name="vmId">Identifies the view model.</param> /// <param name="iData">View model update.</param> public async Task OnUpdateVMAsync(string connectionId, string vmId, Dictionary <string, object> data) { if (!_activeVMs.ContainsKey(vmId)) { Logger.LogError($"Update to '{vmId}' received before connect request"); return; } // Update the new values from the client to the server view model. var vmInstance = _activeVMs[vmId].Instance; // Invoke the interception delegate. await UpdateVMFilter.Invoke(vmId, vmInstance, data, async filteredData => { List <Task> asyncCommands = null; lock (vmInstance) { foreach (var kvp in filteredData as Dictionary <string, object> ) { UpdateVM(vmInstance, kvp.Key, kvp.Value != null ? kvp.Value.ToString() : ""); } if (vmInstance.AsyncCommands.Count > 0) { asyncCommands = new List <Task>(vmInstance.AsyncCommands); vmInstance.AsyncCommands.Clear(); } } /// Await for any asynchronous command executed during deserialization. if (asyncCommands != null) { await Task.WhenAll(asyncCommands); } // If the updates cause some properties of this and other view models to change, push those new values back to the client. lock (vmInstance) { var vmInfo = _activeVMs.Values.FirstOrDefault(vm => vm.Instance == vmInstance); if (vmInfo != null) { var changedProperties = new Dictionary <string, object>(vmInstance.ChangedProperties); // Exclude the changes that trigger this update if their values don't change. foreach (var kvp in data) { if (vmInstance.IsEqualToChangedPropertyValue(kvp.Key, kvp.Value)) { changedProperties.Remove(kvp.Key); } } if (changedProperties.Count > 0) { var vmData = vmInstance.Serialize(changedProperties); PushUpdates(vmInfo, vmData); } if (vmInstance is MulticastVM) { (vmInstance as MulticastVM).PushUpdatesExcept(vmInfo.ConnectionId); } else { vmInstance.AcceptChangedProperties(); } } } // Push updates on other view model instances in case they too change. foreach (var vmInfo in _activeVMs.Values.Where(vm => vm.Instance != vmInstance)) { PushUpdates(vmInfo); } }); }