public void RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment) { // A component might be in the render queue already before getting disposed by an // earlier entry in the render queue. In that case, rendering is a no-op. if (_componentWasDisposed) { return; } // Swap the old and new tree builders (CurrentRenderTree, _renderTreeBuilderPrevious) = (_renderTreeBuilderPrevious, CurrentRenderTree); CurrentRenderTree.Clear(); renderFragment(CurrentRenderTree); var diff = RenderTreeDiffBuilder.ComputeDiff( _renderer, batchBuilder, ComponentId, _renderTreeBuilderPrevious.GetFrames(), CurrentRenderTree.GetFrames()); batchBuilder.UpdatedComponentDiffs.Append(diff); batchBuilder.InvalidateParameterViews(); }
public static void UpdateToMatchClientState(RenderTreeBuilder renderTreeBuilder, ulong eventHandlerId, object newFieldValue) { // We only allow the client to supply string or bool currently, since those are the only kinds of // values we output on attributes that go to the client if (!(newFieldValue is string || newFieldValue is bool)) { return; } // Find the element that contains the event handler var frames = renderTreeBuilder.GetFrames(); var framesArray = frames.Array; var framesLength = frames.Count; var closestElementFrameIndex = -1; for (var frameIndex = 0; frameIndex < framesLength; frameIndex++) { ref var frame = ref framesArray[frameIndex]; switch (frame.FrameTypeField) { case RenderTreeFrameType.Element: closestElementFrameIndex = frameIndex; break; case RenderTreeFrameType.Attribute: if (frame.AttributeEventHandlerIdField == eventHandlerId) { if (!string.IsNullOrEmpty(frame.AttributeEventUpdatesAttributeNameField)) { UpdateFrameToMatchClientState( renderTreeBuilder, framesArray, closestElementFrameIndex, frame.AttributeEventUpdatesAttributeNameField, newFieldValue); } // Whether or not we did update the frame, that was the one that matches // the event handler ID, so no need to look any further return; } break; } }
public void RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, out Exception?renderFragmentException) { renderFragmentException = null; // A component might be in the render queue already before getting disposed by an // earlier entry in the render queue. In that case, rendering is a no-op. if (_componentWasDisposed) { return; } _nextRenderTree.Clear(); try { renderFragment(_nextRenderTree); } catch (Exception ex) { // If an exception occurs in the render fragment delegate, we won't process the diff in any way, so child components, // event handlers, etc., will all be left untouched as if this component didn't re-render at all. The Renderer will // then forcibly clear the descendant subtree by rendering an empty fragment for this component. renderFragmentException = ex; return; } // We don't want to make errors from this be recoverable, because there's no legitimate reason for them to happen _nextRenderTree.AssertTreeIsValid(Component); // Swap the old and new tree builders (CurrentRenderTree, _nextRenderTree) = (_nextRenderTree, CurrentRenderTree); var diff = RenderTreeDiffBuilder.ComputeDiff( _renderer, batchBuilder, ComponentId, _nextRenderTree.GetFrames(), CurrentRenderTree.GetFrames()); batchBuilder.UpdatedComponentDiffs.Append(diff); batchBuilder.InvalidateParameterViews(); }