using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace Sandbox.UI;
public partial class Panel
{
///
/// true when the tree should be re-rendered next frame.
///
bool razorTreeDirty = true;
string razorLastTreeChecksum = null;
[Parameter] public RenderFragment ChildContent { get; set; }
///
/// For razor panels, call when the state of the render tree has changed such that
/// it would be a good idea to re-render the tree. You would usually not need to call
/// this manually.
///
public void StateHasChanged()
{
ThreadSafe.AssertIsMainThread();
razorTreeDirty = true;
}
///
/// Overridden/implemented by Razor templating, contains render tree checksum to determine when the render tree content has changed.
///
protected virtual string GetRenderTreeChecksum() => ChildContent == null ? null : "1";
internal bool HasRenderTree => GetRenderTreeChecksum() is not null;
PanelRenderTreeBuilder renderTree;
///
/// Overridden/implemented by Razor templating to build a render tree.
///
protected virtual void BuildRenderTree( RenderTreeBuilder tree )
{
ChildContent?.Invoke( tree );
}
int previousHash;
///
/// By overriding this you can return a hash of variables used by the Razor layout, which
/// will cause a rebuild when changed. This is useful when your layout uses a global variable
/// because by adding it to a HashCode.Combine here you can easily trigger a build when it changes.
///
protected virtual int BuildHash()
{
return 0;
}
///
/// A RenderFragment has been set on us, so our tree has potential changes now.
/// Lets update and see.
///
public void OnRenderFragmentChanged( Panel upTo )
{
if ( upTo == this )
return;
razorTreeDirty = true;
Parent?.OnRenderFragmentChanged( upTo );
}
internal void InternalTreeBinds()
{
if ( renderTree == null )
return;
try
{
var hash = BuildHash();
if ( previousHash != hash )
{
previousHash = hash;
razorTreeDirty = true;
}
}
catch ( System.Exception e )
{
Log.Warning( e, $"Error calculating hash on {GetType()} - {e.Message}" );
}
if ( renderTree.UpdateBinds() )
{
razorTreeDirty = true;
}
}
///
/// Allows building render tree from outside of the class.
///
internal RenderTreeBuilder InternalRenderTree()
{
if ( !HasRenderTree )
return null;
razorTreeDirty = false;
renderTree ??= new PanelRenderTreeBuilder( this );
razorLastTreeChecksum = GetRenderTreeChecksum();
renderTree.Start();
try
{
BuildRenderTree( renderTree );
}
catch ( System.Exception e )
{
Log.Warning( e, $"Error when building render tree on {GetType()} - {e.Message}" );
}
renderTree.Finish();
return renderTree;
}
///
/// Called after the razor tree has been created/rendered.
///
protected virtual void OnAfterTreeRender( bool firstTime )
{
}
///
/// Delete all children generated by the Razor render tree.
///
internal void ClearRenderTree()
{
renderTree?.Clear();
renderTree = null;
}
}