/// <summary> /// Updates the extra data for the view with the given tag. /// </summary> /// <param name="tag">The view tag.</param> /// <param name="extraData">The extra data.</param> public void UpdateViewExtraData(int tag, object extraData) { DispatcherHelpers.AssertOnDispatcher(); var viewManager = ResolveViewManager(tag); var viewToUpdate = ResolveView(tag); viewManager.UpdateExtraData(viewToUpdate, extraData); }
/// <summary> /// Updates the properties of the view with the given tag. /// </summary> /// <param name="tag">The view tag.</param> /// <param name="props">The properties.</param> public void UpdateProperties(int tag, ReactStylesDiffMap props) { DispatcherHelpers.AssertOnDispatcher(); var viewManager = ResolveViewManager(tag); var viewToUpdate = ResolveView(tag); viewManager.UpdateProperties(viewToUpdate, props); }
/// <summary> /// Initializes the <see cref="ReactChoreographer"/> instance. /// </summary> public static void Initialize() { if (s_instance == null) { DispatcherHelpers.AssertOnDispatcher(); s_instance = new ReactChoreographer(); } }
/// <summary> /// Adds a root view to the hierarchy. /// </summary> /// <param name="tag">The root view tag.</param> /// <param name="rootView">The root view.</param> /// <param name="themedRootContext">The React context.</param> public void AddRootView( int tag, SizeMonitoringCanvas rootView, ThemedReactContext themedRootContext) { DispatcherHelpers.AssertOnDispatcher(); _nativeViewHierarchyManager.AddRootView(tag, rootView, themedRootContext); }
/// <summary> /// Removes the value with the specified key. /// </summary> /// <param name="key"></param> public bool Remove(TKey key) { DispatcherHelpers.AssertOnDispatcher(key); #if WINDOWS_UWP return(_dictionary.TryRemove(key, out _)); #else return(_dictionary.TryRemove(key, out _)); #endif }
/// <summary> /// Set the value associated with the key. Replaces existing value associated with the key, if any. /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void AddOrUpdate(TKey key, TValue value) { DispatcherHelpers.AssertOnDispatcher(key); #if WINDOWS_UWP _dictionary.AddOrUpdate(key, value, (k, v) => value); #else _dictionary.AddOrUpdate(key, value, (k, v) => value); #endif }
private void AddRootViewParent(int tag, FrameworkElement view, ThemedReactContext themedContext) { DispatcherHelpers.AssertOnDispatcher(); _tagsToViews.Add(tag, view); _tagsToViewManagers.Add(tag, _rootViewManager); _rootTags.Add(tag, true); view.SetTag(tag); view.SetReactContext(themedContext); }
/// <summary> /// Awaits the currently initializing React context, or returns null if context fails to initialize. /// </summary> /// <param name="token">A token to cancel the request.</param> /// <returns> /// A task to await the React context. /// </returns> public async Task <ReactContext> TryGetReactContextAsync(CancellationToken token) { DispatcherHelpers.AssertOnDispatcher(); using (await _lock.LockAsync()) { // By this point context has already been created due to the serialized aspect of context initialization. return(_currentReactContext); } }
/// <summary> /// Disposes the <see cref="ReactChoreographer"/> instance. /// </summary> public static void Dispose() { if (s_instance != null) { DispatcherHelpers.AssertOnDispatcher(); ((IDisposable)s_instance).Dispose(); s_instance = null; } }
private void DropView(Widget view) { DispatcherHelpers.AssertOnDispatcher(); var tag = view.GetTag(); if (!_rootTags.ContainsKey(tag)) { Log.Fatal(ReactConstants.Tag, "## DropView ## tag:" + tag); // For non-root views, we notify the view manager with `OnDropViewInstance` var mgr = ResolveViewManager(tag); mgr.OnDropViewInstance(view.GetReactContext(), view); } var viewManager = default(IViewManager); if (_tagsToViewManagers.TryGetValue(tag, out viewManager)) { var ViewParentManager = viewManager as IViewParentManager; if (ViewParentManager != null) { // it should be a view with 'Container' props Log.Fatal(ReactConstants.Tag, "## ViewParentManager:" + ViewParentManager + ", ChildCount:" + ViewParentManager.GetChildCount(view)); for (var i = ViewParentManager.GetChildCount(view) - 1; i >= 0; --i) { var child = ViewParentManager.GetChildAt(view, i); var managedChild = default(Widget); if (_tagsToViews.TryGetValue(child.GetTag(), out managedChild)) { DropView(managedChild); } } ViewParentManager.RemoveAllChildren(view); } } Log.Fatal(ReactConstants.Tag, "## Remove View:[" + tag + "] & ViewMgr Mapping Relationship"); _tagsToViews.Remove(tag); _tagsToViewManagers.Remove(tag); // release sub views ('rootview' will only be destroyed while OnTeminate being invoked) if (1 != tag) { Log.Fatal(ReactConstants.Tag, ">>>>> release view component:[" + tag + "]"); // Clean View <-> Tag if (false == view.RemoveViewInfo()) { Log.Fatal(ReactConstants.Tag, "Failed to clean current view info"); } // hmm ... Life is Over view.Unrealize(); } }
/// <summary> /// Animation loop performs BFS over the graph of animated nodes. /// </summary> /// <remarks> /// We use incremented <see cref="_animatedGraphBFSColor"/> to mark /// nodes as visited in each of the BFS passes, which saves additional /// loops for clearing "visited" states. /// /// First BFS starts with nodes that are in <see cref="_updatedNodes" /> /// (this is, their value has been modified from JS in the last batch /// of JS operations) or directly attached to an active animation /// (thus linked to objects from <see cref="_activeAnimations"/>). In /// that step we calculate an attribute <see cref="AnimatedNode.ActiveIncomingNodes"/>. /// The second BFS runs in topological order over the sub-graph of /// *active* nodes. This is done by adding nodes to the BFS queue only /// if all its "predecessors" have already been visited. /// </remarks> /// <param name="renderingTime">Frame rendering time.</param> public void RunUpdates(TimeSpan renderingTime) { DispatcherHelpers.AssertOnDispatcher(); var hasFinishedAnimations = false; for (var i = 0; i < _updatedNodes.Count; ++i) { var node = _updatedNodes[i]; _runUpdateNodeList.Add(node); } // Clean _updatedNodes queue _updatedNodes.Clear(); for (var i = 0; i < _activeAnimations.Count; ++i) { var animation = _activeAnimations[i]; animation.RunAnimationStep(renderingTime); var valueNode = animation.AnimatedValue; _runUpdateNodeList.Add(valueNode); if (animation.HasFinished) { hasFinishedAnimations = true; } } UpdateNodes(_runUpdateNodeList); _runUpdateNodeList.Clear(); // Cleanup finished animations. Iterate over the array of animations and override ones that has // finished, then resize `_activeAnimations`. if (hasFinishedAnimations) { int dest = 0; for (var i = 0; i < _activeAnimations.Count; ++i) { var animation = _activeAnimations[i]; if (!animation.HasFinished) { _activeAnimations[dest++] = animation; } else { animation.EndCallback.Invoke(new JObject { { "finished", true }, }); } } for (var i = _activeAnimations.Count - 1; i >= dest; --i) { _activeAnimations.RemoveAt(i); } } }
private void DetachViewFromInstance(ReactRootView rootView, IReactInstance reactInstance) { DispatcherHelpers.AssertOnDispatcher(); var uiManagerModule = reactInstance.GetNativeModule <UIManagerModule>(); uiManagerModule.DetachRootView(rootView); reactInstance.GetJavaScriptModule <AppRegistry>().unmountApplicationComponentAtRootTag(rootView.GetTag()); }
/// <summary> /// Awaits the currently initializing React context, or returns null if context fails to initialize. /// </summary> /// <param name="token">A token to cancel the request.</param> /// <returns> /// A task to await the React context. /// </returns> public async Task <ReactContext> TryGetReactContextAsync(CancellationToken token) { RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: TryGetReactContextAsync - entry"); DispatcherHelpers.AssertOnDispatcher(); using (await _lock.LockAsync()) { // By this point context has already been created due to the serialized aspect of context initialization. RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: TryGetReactContextAsync - execute/returning existing {(_currentReactContext == null ? "null" : "valid")} context"); return(_currentReactContext); } }
/// <summary> /// Hooks into the measurement event to potentially attach the React /// root view. /// </summary> /// <param name="availableSize">The available size.</param> /// <returns>The desired size.</returns> protected override Size MeasureOverride(Size availableSize) { DispatcherHelpers.AssertOnDispatcher(this); var result = base.MeasureOverride(availableSize); // Fire and forget async Forget(MeasureOverrideHelperAsync()); return(result); }
/// <summary> /// Instantiates the <see cref="DeviceEventManagerModule"/>. /// </summary> /// <param name="reactContext">The React context.</param> /// <param name="onBackPressed"> /// The action to take when back is pressed. /// </param> public DeviceEventManagerModule( ReactContext reactContext, Action onBackPressed) : base(reactContext) { _invokeDefaultBackPressAction = () => { DispatcherHelpers.AssertOnDispatcher(); onBackPressed(); }; }
/// <summary> /// Frees resources associated with this root view. /// </summary> /// <remarks> /// Has to be called under the dispatcher associated with the view. /// </remarks> public async Task StopReactApplicationAsync() { DispatcherHelpers.AssertOnDispatcher(this); var reactInstanceManager = _reactInstanceManager; if (!_attachScheduled && reactInstanceManager != null) { await reactInstanceManager.DetachRootViewAsync(this); } }
/// <summary> /// Called when the host receives the resume event. /// </summary> public void OnResume() { DispatcherHelpers.AssertOnDispatcher(); if (_rctEventEmitter == null) { _rctEventEmitter = _reactContext.GetJavaScriptModule <RCTEventEmitter>(); } CompositionTarget.Rendering += ScheduleDispatch; }
private void AddRootViewParent(int tag, Widget view, ThemedReactContext themedContext) { Log.Info(ReactConstants.Tag, "### [BGN] AddRootViewParent ### "); DispatcherHelpers.AssertOnDispatcher(); _tagsToViews.Add(tag, view); _tagsToViewManagers.Add(tag, _rootViewManager); _rootTags.Add(tag, true); view.SetTag(tag); view.SetReactContext(themedContext); Log.Info(ReactConstants.Tag, "### [END] AddRootViewParent ### "); }
/// <summary> /// Registers a new root view. /// </summary> /// <param name="rootView">The root view instance.</param> /// <returns>The root view tag.</returns> /// <remarks> /// JavaScript can use the returned tag with to add or remove children /// to this view through <see cref="manageChildren(int, int[], int[], int[], int[], int[])"/>. /// </remarks> public async Task <int> AddMeasuredRootViewAsync(ReactRootView rootView) { // Called on main dispatcher thread DispatcherHelpers.AssertOnDispatcher(); var tag = _nextRootTag; _nextRootTag += RootViewTagIncrement; // Set tag early in case of concurrent DetachRootViewAsync rootView.SetTag(tag); var context = new ThemedReactContext(Context); await DispatcherHelpers.CallOnDispatcher(rootView.Dispatcher, () => { var width = rootView.ActualWidth; var height = rootView.ActualHeight; _layoutActionQueue.Dispatch(() => { _uiImplementation.RegisterRootView(rootView, tag, width, height, context); }); var resizeCount = 0; rootView.SetOnSizeChangedListener((sender, args) => { var currentCount = ++resizeCount; var newWidth = args.NewSize.Width; var newHeight = args.NewSize.Height; _layoutActionQueue.Dispatch(() => { if (currentCount == resizeCount) { _layoutActionQueue.AssertOnThread(); _uiImplementation.UpdateRootNodeSize(tag, newWidth, newHeight); } }); }); rootView.StartTouchHandling(); #if WINDOWS_UWP // Register view in DeviceInfoModule for tracking its dimensions Context.GetNativeModule <DeviceInfoModule>().RegisterRootView(rootView, tag); #endif return(true); }, true); // Allow inlining return(tag); }
/// <summary> /// Gets the animation with the given identifier. /// </summary> /// <param name="animationId">The animation identifier.</param> /// <returns>The animation with the given identifier.</returns> public ReactAnimation GetAnimation(int animationId) { DispatcherHelpers.AssertOnDispatcher(); var result = default(ReactAnimation); if (_registry.TryGetValue(animationId, out result)) { return(result); } return(null); }
/// <summary> /// Removes the animation with the given identifier. /// </summary> /// <param name="animationId">The animation identifier.</param> /// <returns>The animation with the given identifier.</returns> public ReactAnimation RemoveAnimation(int animationId) { DispatcherHelpers.AssertOnDispatcher(); var animation = GetAnimation(animationId); if (animation != null) { _registry.Remove(animationId); } return(animation); }
private void DetachViewFromInstance(ReactRootView rootView, IReactInstance reactInstance) { DispatcherHelpers.AssertOnDispatcher(); if (-1 != rootView.GetTag()) { reactInstance.GetJavaScriptModule <AppRegistry>().unmountApplicationComponentAtRootTag(rootView.GetTag()); } // timming issue Thread.Sleep(2 * 1000); }
/// <summary> /// Unregister <paramref name="rootView"/> and stop keeping track of his dimensions /// </summary> /// <param name="rootView">The react root view</param> public void UnregisterRootView(ReactRootView rootView) { DispatcherHelpers.AssertOnDispatcher(rootView); var info = _registeredViews.Values.SingleOrDefault(i => i.RootView == rootView); if (info != null && _registeredViews.TryRemove(info.ApplicationView, out info)) { info.ApplicationView.VisibleBoundsChanged -= OnVisibleBoundsChanged; info.DisplayInformation.OrientationChanged -= OnOrientationChanged; } }
private void RecreateReactContextInBackgroundInner() { DispatcherHelpers.AssertOnDispatcher(); if (_useDeveloperSupport && _jsBundleFile == null && _jsMainModuleName != null) { _devSupportManager.HandleReloadJavaScript(); } else { RecreateReactContextInBackgroundFromBundleFile(); } }
private Task <ReactContext> CreateReactContextCoreAsync(CancellationToken token) { DispatcherHelpers.AssertOnDispatcher(); if (_useDeveloperSupport && _jsBundleFile == null) { return(CreateReactContextFromDevManagerAsync(token)); } else { return(CreateReactContextFromBundleAsync(token)); } }
/// <summary> /// Called when the application is suspended. /// </summary> public void OnSuspend() { DispatcherHelpers.AssertOnDispatcher(); _defaultBackButtonHandler = null; if (_useDeveloperSupport) { _devSupportManager.IsEnabled = false; } MoveToBeforeResumeLifecycleState(); }
/// <summary> /// Used when the application resumes to reset the back button handling /// in JavaScript. /// </summary> /// <param name="onBackPressed"> /// The action to take when back is pressed. /// </param> public void OnResume(Action onBackPressed) { DispatcherHelpers.AssertOnDispatcher(); _defaultBackButtonHandler = onBackPressed; if (_useDeveloperSupport) { _devSupportManager.IsEnabled = true; } MoveToResumedLifecycleState(false); }
/// <summary> /// Unsets the size changed event handler. /// </summary> public void RemoveSizeChanged() { DispatcherHelpers.AssertOnDispatcher(this); var sizeChangedEventHandler = _sizeChangedEventHandler; if (sizeChangedEventHandler != null) { SizeChanged -= sizeChangedEventHandler; } _sizeChangedEventHandler = null; }
private void ScheduleDispatch(object sender, object e) { DispatcherHelpers.AssertOnDispatcher(); var activity = Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, "ScheduleDispatch").Start(); MoveStagedEventsToDispatchQueue(); if (!Volatile.Read(ref _hasDispatchScheduled)) { _hasDispatchScheduled = true; _reactContext.RunOnJavaScriptQueueThread(() => DispatchEvents(activity)); } }
/// <summary> /// Remove the root view with the given tag. /// </summary> /// <param name="rootViewTag">The root view tag.</param> public void RemoveRootView(int rootViewTag) { DispatcherHelpers.AssertOnDispatcher(); if (!_rootTags.ContainsKey(rootViewTag)) { throw new InvalidOperationException( Invariant($"View with tag '{rootViewTag}' is not registered as a root view.")); } var rootView = _tagsToViews[rootViewTag]; DropView(rootView); _rootTags.Remove(rootViewTag); }