diff --git a/App.xaml.cs b/App.xaml.cs
index 0aba97692..74b4fc8bb 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -3,6 +3,7 @@
using System.Reflection;
using System.Threading;
using System.Windows;
+using System.Windows.Controls;
using System.Windows.Threading;
namespace ArIED61850Tester;
@@ -19,6 +20,12 @@ protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
+ // Keep every IED card on one reusable template key while replacing the
+ // legacy bitmap fallback with the compact ARVREL-derived vector fascia.
+ // Installing this before StartupUri materializes also makes the portable
+ // smoke test validate that the vector ResourceDictionary is packaged.
+ InstallArvrelMiniIedFascia();
+
if (Array.Exists(e.Args, argument =>
string.Equals(argument, "--portable-smoke-test", StringComparison.OrdinalIgnoreCase)))
{
@@ -37,6 +44,24 @@ protected override void OnStartup(StartupEventArgs e)
new Action(() => _ = AppUpdateCoordinator.RunLazyAsync(_updateCancellation.Token)));
}
+ private void InstallArvrelMiniIedFascia()
+ {
+ var fasciaResources = new ResourceDictionary
+ {
+ Source = new Uri(
+ "/ARSAS;component/Resources/ArvrelMiniIedFascia.xaml",
+ UriKind.Relative)
+ };
+
+ if (fasciaResources["ArvrelMiniIedRelayFrontPanelTemplate"] is not ControlTemplate template)
+ {
+ throw new InvalidOperationException(
+ "The packaged ARVREL mini IED fascia resource is missing its ControlTemplate.");
+ }
+
+ Resources["IedRelayFrontPanelTemplate"] = template;
+ }
+
private static int RunPortableSmokeTest()
{
try
diff --git a/Resources/ArvrelMiniIedFascia.xaml b/Resources/ArvrelMiniIedFascia.xaml
new file mode 100644
index 000000000..d1642376e
--- /dev/null
+++ b/Resources/ArvrelMiniIedFascia.xaml
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs b/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs
new file mode 100644
index 000000000..c5a49ff0d
--- /dev/null
+++ b/tests/ARSAS.Tests/ArvrelMiniIedFasciaTests.cs
@@ -0,0 +1,86 @@
+using System.Xml.Linq;
+
+namespace ARSAS.Tests;
+
+public sealed class ArvrelMiniIedFasciaTests
+{
+ [Fact]
+ public void CompactArvrelFascia_IsVectorOnlyAndKeepsRecognizableRelayHardware()
+ {
+ var document = XDocument.Load(FindRepoFile("Resources/ArvrelMiniIedFascia.xaml"));
+ XNamespace presentation = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
+ XNamespace x = "http://schemas.microsoft.com/winfx/2006/xaml";
+
+ var template = document
+ .Descendants(presentation + "ControlTemplate")
+ .Single(node =>
+ (string?)node.Attribute(x + "Key") == "ArvrelMiniIedRelayFrontPanelTemplate");
+
+ var root = template.Elements(presentation + "Grid").Single();
+ Assert.Equal("50", (string?)root.Attribute("Width"));
+ Assert.Equal("50", (string?)root.Attribute("Height"));
+
+ var namedParts = template
+ .Descendants()
+ .Select(node => (string?)node.Attribute(x + "Name"))
+ .Where(name => !string.IsNullOrWhiteSpace(name))
+ .Cast()
+ .ToHashSet(StringComparer.Ordinal);
+
+ Assert.Contains("ArvrelMiniShell", namedParts);
+ Assert.Contains("ArvrelMiniLedBank", namedParts);
+ Assert.Contains("ArvrelMiniLcd", namedParts);
+ Assert.Contains("ArvrelMiniKeypad", namedParts);
+ Assert.Contains("RelayStateRail", namedParts);
+
+ Assert.Empty(template.Descendants(presentation + "Image"));
+ Assert.Empty(template.Descendants(presentation + "TextBlock"));
+ Assert.Contains("{TemplateBinding Foreground}", template.ToString(), StringComparison.Ordinal);
+ Assert.Contains("#2E6F9E", document.ToString(), StringComparison.OrdinalIgnoreCase);
+ }
+
+ [Fact]
+ public void AppStartup_ReplacesLegacyCardTemplateWithPackagedArvrelVector()
+ {
+ var source = File.ReadAllText(FindRepoFile("App.xaml.cs"));
+
+ Assert.Contains("InstallArvrelMiniIedFascia();", source, StringComparison.Ordinal);
+ Assert.Contains(
+ "/ARSAS;component/Resources/ArvrelMiniIedFascia.xaml",
+ source,
+ StringComparison.Ordinal);
+ Assert.Contains(
+ "fasciaResources[\"ArvrelMiniIedRelayFrontPanelTemplate\"]",
+ source,
+ StringComparison.Ordinal);
+ Assert.Contains(
+ "Resources[\"IedRelayFrontPanelTemplate\"] = template;",
+ source,
+ StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void ExplorerAndIoFatCards_ContinueToUseOneReusableTemplateKey()
+ {
+ var explorer = File.ReadAllText(FindRepoFile("MainWindow.xaml"));
+ var ioFat = File.ReadAllText(FindRepoFile("IoListTestingWindow.xaml"));
+
+ Assert.Contains("Template=\"{StaticResource IedRelayFrontPanelTemplate}\"", explorer, StringComparison.Ordinal);
+ Assert.Contains("Template=\"{StaticResource IedRelayFrontPanelTemplate}\"", ioFat, StringComparison.Ordinal);
+ }
+
+ private static string FindRepoFile(string relativePath)
+ {
+ DirectoryInfo? directory = new(AppContext.BaseDirectory);
+ while (directory != null)
+ {
+ var candidate = Path.Combine(directory.FullName, relativePath);
+ if (File.Exists(candidate))
+ return candidate;
+ directory = directory.Parent;
+ }
+
+ throw new FileNotFoundException(
+ $"Could not locate repository file '{relativePath}' from '{AppContext.BaseDirectory}'.");
+ }
+}