Skip to content

Instantly share code, notes, and snippets.

@SteveSandersonMS
Created November 27, 2020 16:29
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save SteveSandersonMS/4f08efe2ad32178add12bfa3eb6e4559 to your computer and use it in GitHub Desktop.
Save SteveSandersonMS/4f08efe2ad32178add12bfa3eb6e4559 to your computer and use it in GitHub Desktop.
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Components
{
public class SectionContent : IComponent, IDisposable
{
private SectionRegistry _registry;
[Parameter] public string Name { get; set; }
[Parameter] public RenderFragment ChildContent { get; set; }
public void Attach(RenderHandle renderHandle)
{
_registry = SectionRegistry.GetRegistry(renderHandle);
}
public Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
_registry.SetContent(Name, ChildContent);
return Task.CompletedTask;
}
public void Dispose()
{
if (!string.IsNullOrEmpty(Name))
{
// This relies on the assumption that the old SectionContent gets disposed before the
// new one is added to the output. This won't be the case in all possible scenarios.
// We should have the registry keep track of which SectionContent is the most recent
// one to supply new content, and disregard updates from ones that were superseded.
_registry.SetContent(Name, null);
}
}
}
}
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Components
{
public class SectionOutlet : IComponent, IDisposable
{
private static RenderFragment EmptyRenderFragment = builder => { };
private string _subscribedName;
private SectionRegistry _registry;
private Action<RenderFragment> _onChangeCallback;
public void Attach(RenderHandle renderHandle)
{
_onChangeCallback = content => renderHandle.Render(content ?? EmptyRenderFragment);
_registry = SectionRegistry.GetRegistry(renderHandle);
}
public Task SetParametersAsync(ParameterView parameters)
{
var suppliedName = parameters.GetValueOrDefault<string>("Name");
if (suppliedName != _subscribedName)
{
_registry.Unsubscribe(_subscribedName, _onChangeCallback);
_registry.Subscribe(suppliedName, _onChangeCallback);
_subscribedName = suppliedName;
}
return Task.CompletedTask;
}
public void Dispose()
{
_registry?.Unsubscribe(_subscribedName, _onChangeCallback);
}
}
}
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Microsoft.AspNetCore.Components
{
internal class SectionRegistry
{
private static ConditionalWeakTable<Dispatcher, SectionRegistry> _registries
= new ConditionalWeakTable<Dispatcher, SectionRegistry>();
private Dictionary<string, List<Action<RenderFragment>>> _subscriptions
= new Dictionary<string, List<Action<RenderFragment>>>();
public static SectionRegistry GetRegistry(RenderHandle renderHandle)
{
return _registries.GetOrCreateValue(renderHandle.Dispatcher);
}
public void Subscribe(string name, Action<RenderFragment> callback)
{
if (!_subscriptions.TryGetValue(name, out var existingList))
{
existingList = new List<Action<RenderFragment>>();
_subscriptions.Add(name, existingList);
}
existingList.Add(callback);
}
public void Unsubscribe(string name, Action<RenderFragment> callback)
{
if (name != null && _subscriptions.TryGetValue(name, out var existingList))
{
existingList.Remove(callback);
}
}
public void SetContent(string name, RenderFragment content)
{
if (_subscriptions.TryGetValue(name, out var existingList))
{
foreach (var callback in existingList)
{
callback(content);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment