using System.Runtime.CompilerServices; using Avalonia.Controls.Templates; using v2rayN.Desktop.ViewModels; using v2rayN.Desktop.Views; namespace v2rayN.Desktop.Common; public class SimpleViewLocator : IDataTemplate { private static readonly Lazy _instance = new(() => new SimpleViewLocator()); private readonly Dictionary> _locator = new(); private readonly ConditionalWeakTable _cachedViews = new(); private SimpleViewLocator() { RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); RegisterViewFactory(); } public static SimpleViewLocator Instance => _instance.Value; public Control Build(object? data) { if (data is null) { return new TextBlock { Text = "No VM provided" }; } var vmType = data.GetType(); if (!_locator.TryGetValue(vmType, out var factory)) { return new TextBlock { Text = $"VM Not Registered: {vmType}" }; } if (ShouldCache(vmType)) { return _cachedViews.GetValue(data, _ => CreateView(factory, vmType)); } return CreateView(factory, vmType); } public bool Match(object? data) { 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 factory, Type vmType) { return factory.Invoke() ?? new TextBlock { Text = $"View Factory Returned Null: {vmType}" }; } public void RegisterViewFactory(Func factory) where TViewModel : class { _locator.Add(typeof(TViewModel), factory); } public void RegisterViewFactory() where TViewModel : class where TView : Control, new() { _locator.Add(typeof(TViewModel), () => new TView()); } }