/// <summary> /// Return a <see cref="ManagedWeakReference"/> to the pool. /// </summary> /// <param name="owner">The instance returning the reference to the pool.</param> /// <param name="managedWeakReference">A <see cref="ManagedWeakReference"/> to return</param> /// <remarks> /// The returned <see cref="ManagedWeakReference"/> may not be owner by the <paramref name="owner"/>, /// in which case, the <paramref name="managedWeakReference"/> will not be returned to the pool. If the reference /// if an <see cref="IWeakReferenceProvider"/> it is not returned as well. /// A null <paramref name="managedWeakReference"/> is ignored. /// </remarks> public static void ReturnWeakReference(object owner, ManagedWeakReference managedWeakReference) { if (Enabled && managedWeakReference != null && managedWeakReference.Owner == owner && !managedWeakReference.IsSelfReference ) { lock (_gate) { if (_weakReferencePool.Count < MaxReferences) { ReturnUnsafeWeakReference(managedWeakReference.GetUnsafeTargetHandle()); if (!(managedWeakReference.Owner is IWeakReferenceProvider)) { // The owner's weak reference may have been borrowed from an IWeakReferenceProvider instance // We're not release it if it's the case. ReturnUnsafeWeakReference(managedWeakReference.GetUnsafeOwnerHandle()); } managedWeakReference.Dispose(); } } } }
internal void SetWeakDataContext(ManagedWeakReference weakDataContext) { if (!_disposed) { var previousStorage = _dataContextWeakStorage; _dataContextWeakStorage = weakDataContext; OnDataContextChanged(); // Return the reference to the pool after it's been released from the underlying BindingItem instances. // Failing to do so makes the reference change without the bindings knowing about it, // making the reference comparison always equal. Uno.UI.DataBinding.WeakReferencePool.ReturnWeakReference(this, previousStorage); } }
internal void SetWeakDataContext(ManagedWeakReference weakDataContext, bool transferReferenceOwnership = false) { if (!_disposed && DependencyObjectStore.AreDifferent(DataContext, weakDataContext?.Target)) { var previousStorage = _dataContextWeakStorage; _dataContextWeakStorage = weakDataContext; OnDataContextChanged(); // Return the reference to the pool after it's been released from the next BindingItem instances. // Failing to do so makes the reference change without the bindings knowing about it, // making the reference comparison always equal. Uno.UI.DataBinding.WeakReferencePool.ReturnWeakReference(this, previousStorage); } }
/// <summary> /// Subscibes for updates to the INotifyPropertyChanged interface. /// </summary> private static IDisposable SubscribeToNotifyPropertyChanged(ManagedWeakReference dataContextReference, string propertyName, Action newValueAction) { // Attach to the Notify property changed events var notify = dataContextReference.Target as INotifyPropertyChanged; if (notify != null) { if (propertyName.Length != 0 && propertyName[0] == '[') { propertyName = "Item" + propertyName; } var newValueActionWeak = Uno.UI.DataBinding.WeakReferencePool.RentWeakReference(null, newValueAction); PropertyChangedEventHandler handler = (s, args) => { if (args.PropertyName == propertyName) { if (typeof(BindingPath).Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) { typeof(BindingPath).Log().Debug("Property changed for {0} on [{1}]".InvariantCultureFormat(propertyName, dataContextReference.Target?.GetType())); } (newValueActionWeak.Target as Action)?.Invoke(); } }; notify.PropertyChanged += handler; return(Disposable.Create(() => { // This weak reference ensure that the closure will not link // the caller and the callee, in the same way "newValueActionWeak" // does not link the callee to the caller. var that = dataContextReference.Target as INotifyPropertyChanged; if (that != null) { that.PropertyChanged -= handler; } Uno.UI.DataBinding.WeakReferencePool.ReturnWeakReference(null, newValueActionWeak); })); } return(null); }