private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { this.client.VerifyAccess(); this.client.VerifyConnected(); // Check if object is ignored if (this.IgnoreChanges) { return; } if (!this.IsDynamic && this.IsIgnoredProperty(e.PropertyName)) { return; } // Check if object is connected if (!this.IsConnected) { throw new InvalidOperationException("Changes cannot be made to this named object until it is connected with the server"); } // Try to extract property information SharedProperty property; // If dynamic, pull value from dictionary object dynamicVal = null; if (this.IsDynamic) { var dictionary = this.Object as IDictionary<string, object>; if (!dictionary.TryGetValue(e.PropertyName, out dynamicVal)) { throw new ArgumentException("Dictionary doesn't contains the value: " + e.PropertyName); } } if (!this.Properties.TryGetValue(e.PropertyName, out property)) { if (this.IsDynamic) { // Add new property if dynamic if (dynamicVal != null) { property = new SharedProperty() { Attributes = new SharedAttributes(), Index = -1, ETag = new ETag(this.client.ClientId), Name = e.PropertyName, PropertyType = DynamicTypeMapping.Instance.GetValueFromType(dynamicVal.GetType()) }; } } if (property == null) { throw new ArgumentException("Dictionary doesn't contains the value: " + e.PropertyName); } } // Throw exception if property cannot be updated by the client if (property.IsServerAppliedProperty()) { throw new InvalidOperationException("Client cannot modify properties with server-applied attributes"); } // Create payload PropertyChangedPayload data = new PropertyChangedPayload(this.client.ClientId, property.Index, this.Id, property.ETag, this.IsDynamic ? dynamicVal : this.Object.GetPropertyValue(e.PropertyName)); if (this.IsDynamic) { data.PropertyName = e.PropertyName; // Property type might change, we need to re-get each time data.PropertyType = DynamicTypeMapping.Instance.GetValueFromType(dynamicVal.GetType()); } // Add to pending update list property.LocalUpdates.Add(new PropertyUpdateOperation() { Payload = data, ReapplyUpdate = false }); // Send to server this.client.SendPublishEvent(data); }
public bool IsStudentProgressReportProperty(PropertyChangedPayload<IStudentInformationService> payload) { return payload.PropertyName == "StudentProgressReport"; }
private void UpdateSharedObject(PropertyChangedPayload data) { Debug.Assert(this.client.CheckAccess()); ObjectEntry entry = null; try { if (!this.TryGetValue(data.ObjectId, out entry)) { // Received update for an object we are not tracking Debug.WriteLine("[PropertyChanged] Missing shared object for update in incoming event."); return; } SharedProperty property = entry.IsDynamic ? entry.Properties[data.PropertyName] : entry.Properties[data.PropertyIndex]; // In case of dynamic properties, this could be the first time this property is seen if (property == null && entry.IsDynamic) { property = new SharedProperty() { Attributes = new SharedAttributes(), Index = (short)entry.Properties.Count, Name = data.PropertyName, ETag = new ETag(this.client.ClientId), PropertyType = data.PropertyType }; entry.Properties.Add(property.Index, property); } // Ignore changes for given object, add to list entry.IgnoreChanges = true; // Don't apply update if we made it locally bool applyUpdate = data.ClientId != this.client.ClientId; bool conflictDetected = false; PropertyUpdateOperation matchingUpdate = property.LocalUpdates.Where(x => x.Payload.Equals(data)).FirstOrDefault(); if (matchingUpdate != null) { // Remove update from pending list Debug.WriteLine("[PropertyChanged] Received acknowledgement of matching property update"); if (matchingUpdate.ReapplyUpdate) { applyUpdate = true; } property.LocalUpdates.Remove(matchingUpdate); } // Check for conflict, but won't stop us from applying update conflictDetected = data.IsConflict(property.LocalUpdates) && !property.IsServerAppliedProperty() && (property.Attributes.ConcurrencyAttribute != ConcurrencyPolicy.Overwrite); if (applyUpdate) { // Mark pending updates to re-apply if we are applying a change from another endpoint if (data.ClientId != this.client.ClientId) { property.LocalUpdates.ForEach(x => x.ReapplyUpdate = true); } if (entry.IsDynamic) { var dictionary = entry.Object as IDictionary <string, object>; if (dictionary == null) { throw new ArgumentException("Dictionary is null"); } // Insert up-to-date value for property dictionary[data.PropertyName] = Json.ReadObject(DynamicTypeMapping.Instance.GetTypeFromValue(data.PropertyType), data.PropertyValue); } else { Json.AssignProperty(entry.Object, property.Name, data.PropertyValue); } property.Value = data.PropertyValue; } property.ETag = data.ETag; if (conflictDetected) { Debug.WriteLine("[PropertyChanged] Conflict detected on property update"); IEnumerable <PropertyChangedPayload> rejectedUpdates = property.LocalUpdates.Select(x => x.Payload); if (property.Attributes.ConcurrencyAttribute == ConcurrencyPolicy.RejectAndNotify) { var notify = new ConcurrencyUpdateRejectedEventArgs(entry.Object, property.Name, rejectedUpdates.Select(x => Json.ReadProperty(entry.Object, property.Name, x.PropertyValue))); this.client.RaiseError(notify); } property.LocalUpdates.Clear(); } } finally { if (entry != null) { entry.IgnoreChanges = false; } } }
public void StudentProgressReportChanged(PropertyChangedPayload<IStudentInformationService> payload) { AssignStudentProgressReport(payload.Sender); }
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { this.client.VerifyAccess(); this.client.VerifyConnected(); // Check if object is ignored if (this.IgnoreChanges) { return; } if (!this.IsDynamic && this.IsIgnoredProperty(e.PropertyName)) { return; } // Check if object is connected if (!this.IsConnected) { throw new InvalidOperationException("Changes cannot be made to this named object until it is connected with the server"); } // Try to extract property information SharedProperty property; // If dynamic, pull value from dictionary object dynamicVal = null; if (this.IsDynamic) { var dictionary = this.Object as IDictionary <string, object>; if (!dictionary.TryGetValue(e.PropertyName, out dynamicVal)) { throw new ArgumentException("Dictionary doesn't contains the value: " + e.PropertyName); } } if (!this.Properties.TryGetValue(e.PropertyName, out property)) { if (this.IsDynamic) { // Add new property if dynamic if (dynamicVal != null) { property = new SharedProperty() { Attributes = new SharedAttributes(), Index = -1, ETag = new ETag(this.client.ClientId), Name = e.PropertyName, PropertyType = DynamicTypeMapping.Instance.GetValueFromType(dynamicVal.GetType()) }; } } if (property == null) { throw new ArgumentException("Dictionary doesn't contains the value: " + e.PropertyName); } } // Throw exception if property cannot be updated by the client if (property.IsServerAppliedProperty()) { throw new InvalidOperationException("Client cannot modify properties with server-applied attributes"); } // Create payload PropertyChangedPayload data = new PropertyChangedPayload(this.client.ClientId, property.Index, this.Id, property.ETag, this.IsDynamic ? dynamicVal : this.Object.GetPropertyValue(e.PropertyName)); if (this.IsDynamic) { data.PropertyName = e.PropertyName; // Property type might change, we need to re-get each time data.PropertyType = DynamicTypeMapping.Instance.GetValueFromType(dynamicVal.GetType()); } // Add to pending update list property.LocalUpdates.Add(new PropertyUpdateOperation() { Payload = data, ReapplyUpdate = false }); // Send to server this.client.SendPublishEvent(data); }