/// <summary>
        /// Handles the creation of a view.
        /// </summary>
        /// <param name="node">The shadow node for the view.</param>
        /// <param name="themedContext">The themed context.</param>
        /// <param name="initialProperties">
        /// The initial properties for the view.
        /// </param>
        public void HandleCreateView(
            ReactShadowNode node,
            ThemedReactContext themedContext, 
            ReactStylesDiffMap initialProperties)
        {
#if !ENABLED
            _uiViewOperationQueue.EnqueueCreateView(
                    themedContext,
                    node.ReactTag,
                    node.ViewClass,
                    initialProperties);
#else
            var isLayoutOnly = node.ViewClass == ViewProps.ViewClassName
                && IsLayoutOnlyAndCollapsible(initialProperties);

            node.IsLayoutOnly = isLayoutOnly;

            if (!isLayoutOnly)
            {
                _uiViewOperationQueue.EnqueueCreateView(
                    themedContext,
                    node.ReactTag,
                    node.ViewClass,
                    initialProperties);
            }
#endif
        }
        public void ViewManagersPropertyCache_ViewManager_Set()
        {
            var instance = new ViewManagerValueTest();

            var setters = ViewManagersPropertyCache.GetNativePropertySettersForViewManagerType(typeof(ViewManagerValueTest));
            Assert.AreEqual(3, setters.Count);

            var props = new ReactStylesDiffMap(new JObject
            {
                { "Foo", "v1" },
                { "Bar1", "v2" },
                { "Bar2", "v3" },
            });

            AssertEx.Throws<NotSupportedException>(() => setters["Foo"].UpdateShadowNodeProperty(new ShadowNodeValueTest(), props));
            AssertEx.Throws<ArgumentNullException>(
                () => setters["Foo"].UpdateViewManagerProperty(null, null, props),
                ex => Assert.AreEqual("viewManager", ex.ParamName));
            AssertEx.Throws<ArgumentNullException>(
                () => setters["Foo"].UpdateViewManagerProperty(instance, null, null),
                ex => Assert.AreEqual("props", ex.ParamName));

            setters["Foo"].UpdateViewManagerProperty(instance, null, props);
            setters["Bar1"].UpdateViewManagerProperty(instance, null, props);
            setters["Bar2"].UpdateViewManagerProperty(instance, null, props);

            Assert.AreEqual("v1", instance.FooValue);
            Assert.AreEqual("v2", instance.BarValues[0]);
            Assert.AreEqual("v3", instance.BarValues[1]);
        }
Beispiel #3
0
 protected override object[] GetViewManagerArgs(DependencyObject view, ReactStylesDiffMap props)
 {
     s_args[0] = view;
     s_args[1] = _index;
     s_args[2] = ExtractProperty(props);
     return(s_args);
 }
 private void HandleCreateView(ReactShadowNode cssNode, int rootViewTag, ReactStylesDiffMap styles)
 {
     if (!cssNode.IsVirtual)
     {
         _nativeViewHierarchyOptimizer.HandleCreateView(cssNode, cssNode.ThemedContext, styles);
     }
 }
        /// <summary>
        /// Handles the creation of a view.
        /// </summary>
        /// <param name="node">The shadow node for the view.</param>
        /// <param name="themedContext">The themed context.</param>
        /// <param name="initialProperties">
        /// The initial properties for the view.
        /// </param>
        public void HandleCreateView(
            ReactShadowNode node,
            ThemedReactContext themedContext,
            ReactStylesDiffMap initialProperties)
        {
#if !ENABLED
            _uiViewOperationQueue.EnqueueCreateView(
                themedContext,
                node.ReactTag,
                node.ViewClass,
                initialProperties);
#else
            var isLayoutOnly = node.ViewClass == ViewProps.ViewClassName &&
                               IsLayoutOnlyAndCollapsible(initialProperties);

            node.IsLayoutOnly = isLayoutOnly;

            if (!isLayoutOnly)
            {
                _uiViewOperationQueue.EnqueueCreateView(
                    themedContext,
                    node.ReactTag,
                    node.ViewClass,
                    initialProperties);
            }
#endif
        }
Beispiel #6
0
        /// <summary>
        /// Handles the creation of a view.
        /// </summary>
        /// <param name="node">The shadow node for the view.</param>
        /// <param name="rootViewTag">The react tag id of the root.</param>
        /// <param name="themedContext">The themed context.</param>
        /// <param name="initialProperties">
        /// The initial properties for the view.
        /// </param>
        public void HandleCreateView(
            ReactShadowNode node,
            int rootViewTag,
            ThemedReactContext themedContext,
            ReactStylesDiffMap initialProperties)
        {
#if DISABLE_NATIVE_VIEW_HIERARCHY_OPTIMIZER
            _uiViewOperationQueue.EnqueueCreateView(
                themedContext,
                node.ReactTag,
                node.ViewClass,
                initialProperties,
                rootViewTag);
#else
            var isLayoutOnly = node.ViewClass == ViewProps.ViewClassName &&
                               IsLayoutOnlyAndCollapsible(initialProperties);

            node.IsLayoutOnly = isLayoutOnly;

            if (!isLayoutOnly)
            {
                _uiViewOperationQueue.EnqueueCreateView(
                    themedContext,
                    node.ReactTag,
                    node.ViewClass,
                    initialProperties,
                    rootViewTag);
            }
#endif
        }
        /// <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);
        }
Beispiel #8
0
        public static T GetProperty <T>(this ReactStylesDiffMap props, string name)
        {
            var property = props.GetProperty(name, typeof(T));

            if (property == null)
            {
                throw new Exception("ReactStylesDiffMapExtensions GetProperty error, property is null");
            }
            return((T)property);
        }
 private void HandleUpdateView(
     ReactShadowNode cssNode,
     string className,
     ReactStylesDiffMap styles)
 {
     if (!cssNode.IsVirtual)
     {
         _nativeViewHierarchyOptimizer.HandleUpdateView(cssNode, className, styles);
     }
 }
Beispiel #10
0
        protected object ExtractProperty(ReactStylesDiffMap props)
        {
            if (props.IsNull(Name) && s_defaultValues.TryGetValue(PropertyType, out var defaultFunc))
            {
                return(defaultFunc(_attribute));
            }

            return(props.GetProperty(Name)?
                   .ToObject(PropertyType));
        }
Beispiel #11
0
        private void TransitionLayoutOnlyViewToNativeView(ReactShadowNode node, ReactStylesDiffMap props)
        {
            var parent = node.Parent;

            if (parent == null)
            {
                node.IsLayoutOnly = false;
                return;
            }

            // First, remove the node from its parent. This causes the parent
            // to update its native children count. The call will cause all the
            // view's children to be detached from their native parent.
            var childIndex = parent.IndexOf(node);

            parent.RemoveChildAt(childIndex);
            RemoveNodeFromParent(node, false);

            node.IsLayoutOnly = false;

            // Create the view since it doesn't exist in the native hierarchy yet.
            _uiViewOperationQueue.EnqueueCreateView(
                node.RootNode.ThemedContext,
                node.ReactTag,
                node.ViewClass,
                props,
                node.RootNode.ReactTag);

            // Add the node and all its children as if adding new nodes.
            parent.AddChildAt(node, childIndex);
            AddNodeToNode(parent, node, childIndex);
            for (var i = 0; i < node.ChildCount; ++i)
            {
                AddNodeToNode(node, node.GetChildAt(i), i);
            }

            // Update layouts since the children of the node were offset by its
            // x/y position previously. (Warning: bit of a hack) We need to
            // update the layout of this node's children now that it's no
            // longer layout-only, but we may still receive more layout updates
            // at the end of this batch that we don't want to ignore.
            // Also <node>.DispatchUpdates optimizes the layout applying out
            // if screen position/sizes didn't change, yet in this particular case
            // we want to force the applying of those values since the native view
            // is a freshly created one with no history.
            ApplyLayoutBase(node);
            for (var i = 0; i < node.ChildCount; ++i)
            {
                ApplyLayoutBase(node.GetChildAt(i));
            }

            _tagsWithLayoutVisited.Clear();

            node.MarkForceLayout();
        }
Beispiel #12
0
 /// <summary>
 /// Enqueues an operation to create a view.
 /// </summary>
 /// <param name="themedContext">The React context.</param>
 /// <param name="viewReactTag">The view React tag.</param>
 /// <param name="viewClassName">The view class name.</param>
 /// <param name="initialProps">The initial properties.</param>
 public void EnqueueCreateView(
     ThemedReactContext themedContext,
     int viewReactTag,
     string viewClassName,
     ReactStylesDiffMap initialProps)
 {
     EnqueueOperation(() => _nativeViewHierarchyManager.CreateView(
                          themedContext,
                          viewReactTag,
                          viewClassName,
                          initialProps));
 }
Beispiel #13
0
 /// <summary>
 /// Enqueues an operation to create a view.
 /// </summary>
 /// <param name="themedContext">The React context.</param>
 /// <param name="viewReactTag">The view React tag.</param>
 /// <param name="viewClassName">The view class name.</param>
 /// <param name="initialProps">The initial properties.</param>
 /// <param name="rootViewTag">Root view tag.</param>
 public void EnqueueCreateView(
     ThemedReactContext themedContext,
     int viewReactTag,
     string viewClassName,
     ReactStylesDiffMap initialProps,
     int rootViewTag)
 {
     EnqueueCreateView(
         themedContext,
         viewReactTag,
         viewClassName,
         initialProps);
 }
Beispiel #14
0
        public void UpdateShadowNodeProperty(ReactShadowNode shadowNode, ReactStylesDiffMap props)
        {
            if (shadowNode == null)
            {
                throw new ArgumentNullException(nameof(shadowNode));
            }
            if (props == null)
            {
                throw new ArgumentNullException(nameof(props));
            }

            Invoke(shadowNode, GetShadowNodeArgs(props));
        }
Beispiel #15
0
        /// <summary>
        /// Updates the properties of the node.
        /// </summary>
        /// <param name="props">The properties.</param>
        public void UpdateProperties(ReactStylesDiffMap props)
        {
            var setters = ViewManagersPropertyCache.GetNativePropertySettersForShadowNodeType(GetType());

            foreach (var key in props.Keys)
            {
                if (setters.TryGetValue(key, out var setter))
                {
                    setter.UpdateShadowNodeProperty(this, props);
                }
            }

            OnAfterUpdateTransaction();
        }
Beispiel #16
0
        /// <summary>
        /// Checks if the property key is layout-only.
        /// </summary>
        /// <param name="props">The prop collection.</param>
        /// <param name="prop">The prop name.</param>
        /// <returns>
        /// <b>true</b> if the property is layout-only, <b>false</b> otherwise.
        /// </returns>
        public static bool IsLayoutOnly(ReactStylesDiffMap props, string prop)
        {
            if (s_layoutOnlyProperties.Contains(prop))
            {
                return(true);
            }
            else if (PointerEvents == prop)
            {
                var value = props.GetProperty(prop).Value <string>();
                return(value == "auto" || value == "box-none");
            }

            return(false);
        }
 /// <summary>
 /// Enqueues an operation to create a view.
 /// </summary>
 /// <param name="themedContext">The React context.</param>
 /// <param name="viewReactTag">The view React tag.</param>
 /// <param name="viewClassName">The view class name.</param>
 /// <param name="initialProps">The initial properties.</param>
 public void EnqueueCreateView(
     ThemedReactContext themedContext,
     int viewReactTag,
     string viewClassName,
     ReactStylesDiffMap initialProps)
 {
     lock (_nonBatchedGate)
     {
         _nonBatchedOperations.Add(() => _nativeViewHierarchyManager.CreateView(
                                       themedContext,
                                       viewReactTag,
                                       viewClassName,
                                       initialProps));
     }
 }
        /// <summary>
        /// Enqueues an operation to create a view.
        /// </summary>
        /// <param name="themedContext">The React context.</param>
        /// <param name="viewReactTag">The view React tag.</param>
        /// <param name="viewClassName">The view class name.</param>
        /// <param name="initialProps">The initial properties.</param>
        /// <param name="rootViewTag">Root view tag.</param>
        public void EnqueueCreateView(
            ThemedReactContext themedContext,
            int viewReactTag,
            string viewClassName,
            ReactStylesDiffMap initialProps,
            int rootViewTag)
        {
            // Called on layout manager thread

            UIViewOperationQueueInstance queue = GetQueueByTag(rootViewTag);

            _reactTagToOperationQueue.Add(viewReactTag, queue);

            queue.EnqueueCreateView(themedContext, viewReactTag, viewClassName, initialProps);
        }
Beispiel #19
0
        /// <summary>
        /// Handles a call to <see cref="UIManagerModule.updateView(int, string, Newtonsoft.Json.Linq.JObject)"/>.
        /// If a view transitions from being layout-only to not (or vice versa)
        /// this could result in some number of additional create view or
        /// manage children calls. If the view is layout only, no update view
        /// call will be dispatched to the native hierarchy.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="className">The class name.</param>
        /// <param name="props">The properties.</param>
        public void HandleUpdateView(ReactShadowNode node, string className, ReactStylesDiffMap props)
        {
#if DISABLE_NATIVE_VIEW_HIERARCHY_OPTIMIZER
            _uiViewOperationQueue.EnqueueUpdateProperties(node.ReactTag, className, props);
#else
            var needsToLeaveLayoutOnly = node.IsLayoutOnly && !IsLayoutOnlyAndCollapsible(props);
            if (needsToLeaveLayoutOnly)
            {
                TransitionLayoutOnlyViewToNativeView(node, props);
            }
            else if (!node.IsLayoutOnly)
            {
                _uiViewOperationQueue.EnqueueUpdateProperties(node.ReactTag, className, props);
            }
#endif
        }
Beispiel #20
0
        protected object ExtractProperty(ReactStylesDiffMap props)
        {
            if (props.IsNull(Name) && s_defaultValues.TryGetValue(PropertyType, out var defaultFunc))
            {
                return(defaultFunc(_attribute));
            }

            var prop = props.GetProperty(Name)?
                       .ToObject(PropertyType);

            if (prop == null && PropertyType.GetTypeInfo().IsValueType)
            {
                return(Activator.CreateInstance(PropertyType));
            }

            return(prop);
        }
Beispiel #21
0
        /// <summary>
        /// Update the properties of the given view.
        /// </summary>
        /// <param name="viewToUpdate">The view to update.</param>
        /// <param name="props">The properties.</param>
        public void UpdateProperties(TFrameworkElement viewToUpdate, ReactStylesDiffMap props)
        {
            var propertySetters =
                ViewManagersPropertyCache.GetNativePropertySettersForViewManagerType(GetType());

            var keys = props.Keys;

            foreach (var key in keys)
            {
                if (propertySetters.TryGetValue(key, out var setter))
                {
                    setter.UpdateViewManagerProperty(this, viewToUpdate, props);
                }
            }

            OnAfterUpdateTransaction(viewToUpdate);
        }
        /// <summary>
        /// Update the properties of the given view.
        /// </summary>
        /// <param name="viewToUpdate">The view to update.</param>
        /// <param name="props">The properties.</param>
        public void UpdateProperties(TDependencyObject viewToUpdate, ReactStylesDiffMap props)
        {
            var propertySetters =
                ViewManagersPropertyCache.GetNativePropertySettersForViewManagerType(GetType());

            var keys = props.Keys;

            foreach (var key in keys)
            {
                var setter = default(IPropertySetter);
                if (propertySetters.TryGetValue(key, out setter))
                {
                    setter.UpdateViewManagerProperty(this, viewToUpdate, props);
                }
            }

            OnAfterUpdateTransaction(viewToUpdate);
        }
        /// <summary>
        /// Used by the native animated module to bypass the process of
        /// updating the values through the shadow view hierarchy. This method
        /// will directly update the native views, which means that updates for
        /// layout-related properties won't be handled properly.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="props">The properties</param>
        /// <remarks>
        /// Make sure you know what you're doing before calling this method :)
        /// </remarks>
        public bool SynchronouslyUpdateViewOnDispatcherThread(int tag, ReactStylesDiffMap props)
        {
            DispatcherHelpers.AssertOnDispatcher();

            // First check if the view exists, as the views are created in
            // batches, and native modules attempting to synchronously interact
            // with views may attempt to update properties before the batch has
            // been processed.
            if (_operationsQueue.NativeViewHierarchyManager.ViewExists(tag))
            {
                _operationsQueue.NativeViewHierarchyManager.UpdateProperties(tag, props);
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// Invoked by React when the properties change for a node with the
        /// given tag.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="className">The view class name.</param>
        /// <param name="props">The properties.</param>
        public void UpdateView(int tag, string className, JObject props)
        {
            var viewManager = _viewManagers.Get(className);
            var cssNode     = _shadowNodeRegistry.GetNode(tag);

            if (cssNode == null)
            {
                throw new InvalidOperationException(
                          $"Trying to update view with invalid tag '{tag}'.");
            }

            if (props != null)
            {
                var styles = new ReactStylesDiffMap(props);
                cssNode.UpdateProperties(styles);
                HandleUpdateView(cssNode, className, styles);
            }
        }
        /// <summary>
        /// Enqueues an operation to create a view.
        /// </summary>
        /// <param name="themedContext">The React context.</param>
        /// <param name="viewReactTag">The view React tag.</param>
        /// <param name="viewClassName">The view class name.</param>
        /// <param name="initialProps">The initial properties.</param>
        public void EnqueueCreateView(
            ThemedReactContext themedContext,
            int viewReactTag,
            string viewClassName,
            ReactStylesDiffMap initialProps)
        {
            lock (_nonBatchedGate)
            {
                _nonBatchedOperations.Add(() => _nativeViewHierarchyManager.CreateView(
                                              themedContext,
                                              viewReactTag,
                                              viewClassName,
                                              initialProps));
            }

            // Dispatch event from non-layout thread to avoid queueing
            // main dispatcher callbacks from the layout thread
            Task.Run(() => ReactChoreographer.Instance.ActivateCallback(NonBatchedChoreographerKey));
        }
Beispiel #26
0
        protected object ExtractProperty(ReactStylesDiffMap props)
        {
            var defaultFunc = default(Func <ReactPropBaseAttribute, object>);

            if (props.IsNull(Name) && s_defaultValues.TryGetValue(PropertyType, out defaultFunc))
            {
                return(defaultFunc(_attribute));
            }
            try
            {
                return(props.GetProperty(Name)?
                       .ToObject(PropertyType));
            }
            catch (Exception ex)
            {
                Log.Error(ReactConstants.Tag, $"ExtractProperty failed, Name is {Method.Name}, PropertyType is {PropertyType}");
                throw ex;
            }
        }
        /// <summary>
        /// Used by the native animated module to bypass the process of
        /// updating the values through the shadow view hierarchy. This method
        /// will directly update the native views, which means that updates for
        /// layout-related properties won't be handled properly.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="props">The properties</param>
        /// <remarks>
        /// Make sure you know what you're doing before calling this method :)
        /// </remarks>
        public bool SynchronouslyUpdateViewOnDispatcherThread(int tag, ReactStylesDiffMap props)
        {
            // The native animations module is a single threaded implementation affinitized to the "main" dispatcher thread.
            // As a result all calls of this method are on main dispatcher thread.
            // Yet, for secondary views we have to dispatch to correct dispatcher as fast as possible
            DispatcherHelpers.AssertOnDispatcher();

            UIViewOperationQueueInstance queue = GetQueueByTag(tag, true);

            if (queue == null)
            {
                // Returns false as per the caller's expectation
                return(false);
            }

            if (queue == MainUIViewOperationQueue)
            {
                // Main queue case. Just forward.
                if (!MainUIViewOperationQueue.NativeViewHierarchyManager.ViewExists(tag))
                {
                    return(false);
                }

                MainUIViewOperationQueue.NativeViewHierarchyManager.UpdateProperties(tag, props);
            }
            else
            {
                // Dispatch to the correct thread.
                DispatcherHelpers.RunOnDispatcher(queue.Dispatcher, CoreDispatcherPriority.High, () =>
                {
                    if (queue.NativeViewHierarchyManager.ViewExists(tag))
                    {
                        queue.NativeViewHierarchyManager.UpdateProperties(tag, props);
                    }
                    else
                    {
                        Debug.WriteLine($"View with tag {tag} not found due to race condition");
                    }
                });
            }
            return(true);
        }
        /// <summary>
        /// Invoked by React to create a new node with the given tag, class
        /// name, and properties.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="className">The class name.</param>
        /// <param name="rootViewTag">The root view tag.</param>
        /// <param name="props">The properties.</param>
        public void CreateView(int tag, string className, int rootViewTag, JObject props)
        {
            var cssNode  = CreateShadowNode(className);
            var rootNode = _shadowNodeRegistry.GetNode(rootViewTag);

            cssNode.ReactTag      = tag;
            cssNode.ViewClass     = className;
            cssNode.RootNode      = rootNode;
            cssNode.ThemedContext = rootNode.ThemedContext;

            _shadowNodeRegistry.AddNode(cssNode);

            var styles = default(ReactStylesDiffMap);

            if (props != null)
            {
                styles = new ReactStylesDiffMap(props);
                cssNode.UpdateProperties(styles);
            }

            HandleCreateView(cssNode, rootViewTag, styles);
        }
Beispiel #29
0
        private bool IsLayoutOnlyAndCollapsible(ReactStylesDiffMap props)
        {
            if (props == null)
            {
                return(true);
            }

            if (props.ContainsKey(ViewProps.Collapsible) && !props.GetProperty <bool>(ViewProps.Collapsible))
            {
                return(false);
            }

            foreach (var key in props.Keys)
            {
                if (!ViewProps.IsLayoutOnly(props, key))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        /// Handles a call to <see cref="UIManagerModule.updateView(int, string, Newtonsoft.Json.Linq.JObject)"/>.
        /// If a view transitions from being layout-only to not (or vice versa)
        /// this could result in some number of additional create view or
        /// manage children calls. If the view is layout only, no update view
        /// call will be dispatched to the native hierarchy.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="className">The class name.</param>
        /// <param name="props">The properties.</param>
        public void HandleUpdateView(ReactShadowNode node, string className, ReactStylesDiffMap props)
        {
#if !ENABLED
            _uiViewOperationQueue.EnqueueUpdateProperties(node.ReactTag, className, props);
#else
            var needsToLeaveLayoutOnly = node.IsLayoutOnly && !IsLayoutOnlyAndCollapsible(props);
            if (needsToLeaveLayoutOnly)
            {
                TransitionLayoutOnlyViewToNativeView(node, props);
            }
            else if (!node.IsLayoutOnly)
            {
                _uiViewOperationQueue.EnqueueUpdateProperties(node.ReactTag, className, props);
            }
#endif
        }
        private void TransitionLayoutOnlyViewToNativeView(ReactShadowNode node, ReactStylesDiffMap props)
        {
            var parent = node.Parent;
            if (parent == null)
            {
                node.IsLayoutOnly = false;
                return;
            }

            // First, remove the node from its parent. This causes the parent
            // to update its native children count. The call will cause all the
            // view's children to be detached from their native parent.
            var childIndex = parent.IndexOf(node);
            parent.RemoveChildAt(childIndex);
            RemoveNodeFromParent(node, false);

            node.IsLayoutOnly = false;

            // Create the view since it doesn't exist in the native hierarchy yet.
            _uiViewOperationQueue.EnqueueCreateView(
                node.RootNode.ThemedContext,
                node.ReactTag,
                node.ViewClass,
                props);

            // Add the node and all its children as if adding new nodes.
            parent.AddChildAt(node, childIndex);
            AddNodeToNode(parent, node, childIndex);
            for (var i = 0; i < node.ChildCount; ++i)
            {
                AddNodeToNode(node, node.GetChildAt(i), i);
            }

            // Update layouts since the children of the node were offset by its
            // x/y position previously. (Warning: bit of a hack) We need to
            // update the layout of this node's children now that it's no 
            // longer layout-only, but we may still receive more layout updates
            // at the end of this batch that we don't want to ignore.
            ApplyLayoutBase(node);
            for (var i = 0; i < node.ChildCount; ++i)
            {
                ApplyLayoutBase(node.GetChildAt(i));
            }

            _tagsWithLayoutVisited.Clear();
        }
        private bool IsLayoutOnlyAndCollapsible(ReactStylesDiffMap props)
        {
            if (props == null)
            {
                return true;
            }

            if (props.ContainsKey(ViewProps.Collapsible) && !props.GetProperty<bool>(ViewProps.Collapsible))
            {
                return false;
            }

            foreach (var key in props.Keys)
            {
                if (!ViewProps.IsLayoutOnly(key))
                {
                    return false;
                }
            }

            return true;
        }
        /// <summary>
        /// Creates a view with the given tag and class name.
        /// </summary>
        /// <param name="themedContext">The context.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="className">The class name.</param>
        /// <param name="initialProperties">The properties.</param>
        public void CreateView(ThemedReactContext themedContext, int tag, string className, ReactStylesDiffMap initialProperties)
        {
            DispatcherHelpers.AssertOnDispatcher();
            using (RNTracer.Trace(RNTracer.TRACE_TAG_REACT_VIEW, "NativeViewHierarcyManager.CreateView")
                   .With("tag", tag)
                   .With("className", className)
                   .Start())
            {
                var viewManager = _viewManagers.Get(className);
                var view        = viewManager.CreateView(themedContext /*, _jsResponderHandler*/);
                _tagsToViews.Add(tag, view);
                _tagsToViewManagers.Add(tag, viewManager);

                // Uses an extension method and `Tag` property on
                // EvasObject to store the tag of the view.
                view.SetTag(tag);
                view.SetReactContext(themedContext);

                if (initialProperties != null)
                {
                    viewManager.UpdateProperties(view, initialProperties);
                }
            }
        }
Beispiel #34
0
 /// <summary>
 /// Used by the native animated module to bypass the process of
 /// updating the values through the shadow view hierarchy. This method
 /// will directly update the native views, which means that updates for
 /// layout-related properties won't be handled properly.
 /// </summary>
 /// <param name="tag">The view tag.</param>
 /// <param name="props">The properties</param>
 /// <remarks>
 /// Make sure you know what you're doing before calling this method :)
 /// </remarks>
 public void SynchronouslyUpdateViewOnDispatcherThread(int tag, ReactStylesDiffMap props)
 {
     DispatcherHelpers.AssertOnDispatcher();
     _operationsQueue.NativeViewHierarchyManager.UpdateProperties(tag, props);
 }
 private void HandleUpdateView(
     ReactShadowNode cssNode,
     string className,
     ReactStylesDiffMap styles)
 {
     if (!cssNode.IsVirtual)
     {
         _nativeViewHierarchyOptimizer.HandleUpdateView(cssNode, className, styles);
     }
 }
        public void ViewManagersPropertyCache_Defaults()
        {
            var instance = new DefaultsTest();
            var setters = ViewManagersPropertyCache.GetNativePropertySettersForViewManagerType(typeof(DefaultsTest));

            var props = new ReactStylesDiffMap(new JObject());

            instance.ByteValue = byte.MaxValue;
            instance.SByteValue = sbyte.MaxValue;
            instance.Int16Value = short.MaxValue;
            instance.UInt16Value = ushort.MaxValue;
            instance.Int32Value = int.MaxValue;
            instance.UInt32Value = uint.MaxValue;
            instance.Int64Value = long.MaxValue;
            instance.UInt64Value = ulong.MaxValue;
            instance.SingleValue = float.MaxValue;
            instance.DoubleValue = double.MaxValue;
            instance.DecimalValue = decimal.MaxValue;
            instance.BooleanValue = true;
            instance.StringValue = "foo";
            instance.ArrayValue = new int[0];
            instance.MapValue = new object();
            instance.NullableValue = true;
            instance.GroupValue = new[] { "a", "b", "c" };

            setters["TestByte"].UpdateViewManagerProperty(instance, null, props);
            setters["TestSByte"].UpdateViewManagerProperty(instance, null, props);
            setters["TestInt16"].UpdateViewManagerProperty(instance, null, props);
            setters["TestUInt16"].UpdateViewManagerProperty(instance, null, props);
            setters["TestInt32"].UpdateViewManagerProperty(instance, null, props);
            setters["TestUInt32"].UpdateViewManagerProperty(instance, null, props);
            setters["TestInt64"].UpdateViewManagerProperty(instance, null, props);
            setters["TestUInt64"].UpdateViewManagerProperty(instance, null, props);
            setters["TestSingle"].UpdateViewManagerProperty(instance, null, props);
            setters["TestDouble"].UpdateViewManagerProperty(instance, null, props);
            setters["TestDecimal"].UpdateViewManagerProperty(instance, null, props);
            setters["TestBoolean"].UpdateViewManagerProperty(instance, null, props);
            setters["TestString"].UpdateViewManagerProperty(instance, null, props);
            setters["TestArray"].UpdateViewManagerProperty(instance, null, props);
            setters["TestMap"].UpdateViewManagerProperty(instance, null, props);
            setters["TestNullable"].UpdateViewManagerProperty(instance, null, props);
            setters["foo"].UpdateViewManagerProperty(instance, null, props);
            setters["bar"].UpdateViewManagerProperty(instance, null, props);
            setters["baz"].UpdateViewManagerProperty(instance, null, props);

            Assert.AreEqual(0, instance.ByteValue);
            Assert.AreEqual(0, instance.SByteValue);
            Assert.AreEqual(0, instance.Int16Value);
            Assert.AreEqual(0, instance.UInt16Value);
            Assert.AreEqual(0, instance.Int32Value);
            Assert.AreEqual((uint)0, instance.UInt32Value);
            Assert.AreEqual(0, instance.Int64Value);
            Assert.AreEqual((ulong)0, instance.UInt64Value);
            Assert.AreEqual(0, instance.SingleValue);
            Assert.AreEqual(0, instance.DoubleValue);
            Assert.AreEqual(0, instance.DecimalValue);
            Assert.IsFalse(instance.BooleanValue);
            Assert.IsNull(instance.StringValue);
            Assert.IsNull(instance.ArrayValue);
            Assert.IsNull(instance.MapValue);
            Assert.IsFalse(instance.NullableValue.HasValue);
            Assert.IsNull(instance.GroupValue[0]);
            Assert.IsNull(instance.GroupValue[1]);
            Assert.IsNull(instance.GroupValue[2]);
        }
        /// <summary>
        /// Invoked by React to create a new node with the given tag, class
        /// name, and properties.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="className">The class name.</param>
        /// <param name="rootViewTag">The root view tag.</param>
        /// <param name="props">The properties.</param>
        public void CreateView(int tag, string className, int rootViewTag, JObject props)
        {
            var cssNode = CreateShadowNode(className);
            var rootNode = _shadowNodeRegistry.GetNode(rootViewTag);
            cssNode.ReactTag = tag;
            cssNode.ViewClass = className;
            cssNode.RootNode = rootNode;
            cssNode.ThemedContext = rootNode.ThemedContext;

            _shadowNodeRegistry.AddNode(cssNode);

            var styles = default(ReactStylesDiffMap);
            if (props != null)
            {
                styles = new ReactStylesDiffMap(props);
                cssNode.UpdateProperties(styles);
            }

            HandleCreateView(cssNode, rootViewTag, styles);
        }
        /// <summary>
        /// Invoked by React when the properties change for a node with the
        /// given tag.
        /// </summary>
        /// <param name="tag">The view tag.</param>
        /// <param name="className">The view class name.</param>
        /// <param name="props">The properties.</param>
        public void UpdateView(int tag, string className, JObject props)
        {
            var viewManager = _viewManagers.Get(className);
            var cssNode = _shadowNodeRegistry.GetNode(tag);
            if (cssNode == null)
            {
                throw new InvalidOperationException(
                    Invariant($"Trying to update view with invalid tag '{tag}'."));
            }

            if (props != null)
            {
                var styles = new ReactStylesDiffMap(props);
                cssNode.UpdateProperties(styles);
                HandleUpdateView(cssNode, className, styles);
            }
        }
 /// <summary>
 /// Used by the native animated module to bypass the process of
 /// updating the values through the shadow view hierarchy. This method
 /// will directly update the native views, which means that updates for
 /// layout-related properties won't be handled properly.
 /// </summary>
 /// <param name="tag">The view tag.</param>
 /// <param name="props">The properties</param>
 /// <remarks>
 /// Make sure you know what you're doing before calling this method :)
 /// </remarks>
 public void SynchronouslyUpdateViewOnDispatcherThread(int tag, ReactStylesDiffMap props)
 {
     DispatcherHelpers.AssertOnDispatcher();
     _operationsQueue.NativeViewHierarchyManager.UpdateProperties(tag, props);
 }
 /// <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>
        /// Creates a view with the given tag and class name.
        /// </summary>
        /// <param name="themedContext">The context.</param>
        /// <param name="tag">The tag.</param>
        /// <param name="className">The class name.</param>
        /// <param name="initialProperties">The properties.</param>
        public void CreateView(ThemedReactContext themedContext, int tag, string className, ReactStylesDiffMap initialProperties)
        {
            DispatcherHelpers.AssertOnDispatcher();
            using (Tracer.Trace(Tracer.TRACE_TAG_REACT_VIEW, "NativeViewHierarcyManager.CreateView")
                .With("tag", tag)
                .With("className", className)
                .Start())
            {
                var viewManager = _viewManagers.Get(className);
                var view = viewManager.CreateView(themedContext, _jsResponderHandler);
                _tagsToViews.Add(tag, view);
                _tagsToViewManagers.Add(tag, viewManager);

                // Uses an extension method and `Tag` property on 
                // DependencyObject to store the tag of the view.
                view.SetTag(tag);
                view.SetReactContext(themedContext);

                if (initialProperties != null)
                {
                    viewManager.UpdateProperties(view, initialProperties);
                }
            }
        }
 public virtual void UpdateProperties(DependencyObject viewToUpdate, ReactStylesDiffMap props)
 {
     throw new NotImplementedException();
 }
 void IViewManager.UpdateProperties(Widget viewToUpdate, ReactStylesDiffMap props)
 {
     UpdateProperties((TView)viewToUpdate, props);
 }
 private void HandleCreateView(ReactShadowNode cssNode, int rootViewTag, ReactStylesDiffMap styles)
 {
     if (!cssNode.IsVirtual)
     {
         _nativeViewHierarchyOptimizer.HandleCreateView(cssNode, cssNode.ThemedContext, styles);
     }
 }