- Slow inflation time: All resources are instantiated upfront during XAML inflation, even if never used
- No
x:Sharedsupport: Resources that need parenting (e.g.,StrokeShape) cannot be StaticResources because the same instance is shared - causing crashes when multiple elements try to parent the same object
Store Func<object> factories instead of object instances in ResourceDictionary. Resources are created on-demand when accessed.
public class ResourceDictionary
{
// NEW: Add a resource factory instead of an instance
[EditorBrowsable(EditorBrowsableState.Never)]
public void AddFactory(string key, Func<object> factory, bool shared = true);
// NEW: Add an implicit style factory (uses TargetType.FullName as key)
[EditorBrowsable(EditorBrowsableState.Never)]
public void AddFactory(Func<Style> factory, bool shared = true);
// MODIFIED: TryGetValue now invokes factory if stored value is a factory
// For shared=true: invoke once, cache result
// For shared=false: invoke every time (x:Shared="false")
}// Wrapper to distinguish factories from regular values
internal readonly struct LazyResource
{
public Func<object> Factory { get; }
public bool Shared { get; }
}
// _innerDictionary stores either:
// - object (existing behavior)
// - LazyResource (new lazy behavior)| Scenario | shared=true (default) |
shared=false |
|---|---|---|
| First access | Invoke factory, cache result, return | Invoke factory, return |
| Subsequent | Return cached | Invoke factory, return |
SourceGen-only: This is a compile-time optimization. XamlC cannot emit lambdas.
// Generated code (SourceGen)
Resources.AddFactory("MyStyle", () => new Style { ... }, shared: true); // explicit key
Resources.AddFactory(() => new Style { TargetType = typeof(Button), ... }); // implicit style
Resources.AddFactory("MyShape", () => new RoundRectangle { ... }, shared: false);
// XamlC continues to emit
Resources.Add("MyStyle", new Style { ... });<!-- Default: x:Shared="true" (cached, current behavior) -->
<Style x:Key="MyStyle" TargetType="Button">...</Style>
<!-- New: x:Shared="false" (new instance per access) -->
<RoundRectangle x:Key="MyShape" x:Shared="false" CornerRadius="10"/>| Inflator | Lazy RD | x:Shared |
|---|---|---|
| SourceGen | ✅ | ✅ |
| Runtime | ❌ (could add) | ❌ |
| XamlC | ❌ (possible but hard) | ❌ |
AddFactory is [EditorBrowsable(Never)] - internal use only.
Public iteration behavior:
Keys→ returns keys only, does NOT invoke factoriesValues→ resolves lazy values (invokes factory, caches if shared)GetEnumerator()/foreach→ returnsKeyValuePair<string, object>with resolved values
Internal _innerDictionary stores LazyResource, but public API always resolves — no breaking change.
- ⚡ Faster startup: Resources created only when needed
- 🔧 x:Shared for free:
StrokeShapein StaticResource finally works - 📦 No runtime cost for unused resources
⚠️ x:Sharedonly works with SourceGen (acceptable trade-off)
- Default
x:Shared=falsevia attribute: Mark types likeStrokeShape,RoundRectangle, etc. with an attribute (e.g.,[NotSharedByDefault]) so SourceGen automatically treats them asx:Shared="false"without explicit XAML markup. This would prevent common pitfalls where elements that need parenting are incorrectly shared.