Cache selected views in SimpleViewLocator

Add a `ConditionalWeakTable`-based view cache keyed by view model instance for `MsgViewModel`, `ClashProxiesViewModel`, and `ClashConnectionsViewModel` so repeated bindings reuse the same control. The locator now also handles missing registrations and null factory results more explicitly by returning descriptive `TextBlock` messages.
This commit is contained in:
2dust
2026-09-04 15:14:00 +08:00
parent b8e8321603
commit 8ebbd7f4f8
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using v2rayN.Desktop.ViewModels; using v2rayN.Desktop.ViewModels;
using v2rayN.Desktop.Views; using v2rayN.Desktop.Views;
@@ -9,6 +10,7 @@ public class SimpleViewLocator : IDataTemplate
private static readonly Lazy<SimpleViewLocator> _instance = new(() => new SimpleViewLocator()); private static readonly Lazy<SimpleViewLocator> _instance = new(() => new SimpleViewLocator());
private readonly Dictionary<Type, Func<Control?>> _locator = new(); private readonly Dictionary<Type, Func<Control?>> _locator = new();
private readonly ConditionalWeakTable<object, Control> _cachedViews = new();
private SimpleViewLocator() private SimpleViewLocator()
{ {
@@ -45,9 +47,18 @@ public class SimpleViewLocator : IDataTemplate
return new TextBlock { Text = "No VM provided" }; return new TextBlock { Text = "No VM provided" };
} }
_locator.TryGetValue(data.GetType(), out var factory); var vmType = data.GetType();
if (!_locator.TryGetValue(vmType, out var factory))
{
return new TextBlock { Text = $"VM Not Registered: {vmType}" };
}
return factory?.Invoke() ?? new TextBlock { Text = $"VM Not Registered: {data.GetType()}" }; if (ShouldCache(vmType))
{
return _cachedViews.GetValue(data, _ => CreateView(factory, vmType));
}
return CreateView(factory, vmType);
} }
public bool Match(object? data) public bool Match(object? data)
@@ -55,6 +66,18 @@ public class SimpleViewLocator : IDataTemplate
return data is MyReactiveObject; return data is MyReactiveObject;
} }
private static bool ShouldCache(Type vmType)
{
return vmType == typeof(MsgViewModel)
|| vmType == typeof(ClashProxiesViewModel)
|| vmType == typeof(ClashConnectionsViewModel);
}
private static Control CreateView(Func<Control?> factory, Type vmType)
{
return factory.Invoke() ?? new TextBlock { Text = $"View Factory Returned Null: {vmType}" };
}
public void RegisterViewFactory<TViewModel>(Func<Control> factory) where TViewModel : class public void RegisterViewFactory<TViewModel>(Func<Control> factory) where TViewModel : class
{ {
_locator.Add(typeof(TViewModel), factory); _locator.Add(typeof(TViewModel), factory);