Forge
csharpdeeb25a2
1using System.Diagnostics.CodeAnalysis;
2using Avalonia.Controls;
3using Avalonia.Controls.Templates;
4using CascadeIDE.ViewModels;
5
6namespace CascadeIDE;
7
8/// <summary>
9/// Given a view model, returns the corresponding view if possible.
10/// </summary>
11[RequiresUnreferencedCode(
12 "Default implementation of ViewLocator involves reflection which may be trimmed away.",
13 Url = "https://docs.avaloniaui.net/docs/concepts/view-locator")]
14public class ViewLocator : IDataTemplate
15{
16 public Control? Build(object? param)
17 {
18 if (param is null)
19 return null;
20
21 var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
22 var type = ResolveViewType(name);
23
24 if (type != null)
25 {
26 return (Control)Activator.CreateInstance(type)!;
27 }
28
29 TryLogViewResolutionFailure(name, param.GetType());
30
31 return new TextBlock { Text = "Not Found: " + name };
32 }
33
34 public bool Match(object? data)
35 {
36 if (data is null)
37 return false;
38
39 // Support classic MVVM VMs and Dock's document VMs
40 // (e.g., DockDocumentViewModel) that don't inherit ViewModelBase.
41 return data is ViewModelBase
42 || data.GetType().Name.EndsWith("ViewModel", StringComparison.Ordinal);
43 }
44
45 private static Type? ResolveViewType(string fullName)
46 {
47 var type = Type.GetType(fullName);
48 if (type is not null)
49 return type;
50
51 type = typeof(ViewLocator).Assembly.GetType(fullName);
52 if (type is not null)
53 return type;
54
55 return AppDomain.CurrentDomain
56 .GetAssemblies()
57 .Select(a => a.GetType(fullName, throwOnError: false))
58 .FirstOrDefault(t => t is not null);
59 }
60
61 private static void TryLogViewResolutionFailure(string viewTypeName, Type viewModelType)
62 {
63 try
64 {
65 var dir = Path.Combine(AppContext.BaseDirectory, ".cascade-ide");
66 Directory.CreateDirectory(dir);
67 var path = Path.Combine(dir, "view-locator-log.txt");
68 File.AppendAllText(
69 path,
70 $"[{DateTimeOffset.Now:O}] view='{viewTypeName}' vm='{viewModelType.FullName}'{Environment.NewLine}");
71 }
72 catch
73 {
74 // Ignore locator logging failures.
75 }
76 }
77}
78
View only · write via MCP/CIDE