Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
4dd3880
FAT P5.4: wire semantic structured reports into live runtime
github-actions[bot] Sep 1, 2026
6cb29fe
Pin sparse structured report semantic matching fix
masarray Sep 2, 2026
88674fd
Lock ARSAS regression to sparse structured report identity fix
masarray Sep 2, 2026
c669fe2
Fix FAT structured sibling binding and expose SCL import
masarray Sep 2, 2026
7f47304
Fix multiline SCL menu regression assertion
masarray Sep 2, 2026
b77e9d7
Restrict FAT DataSet merge to exact IEC identity
masarray Sep 2, 2026
480eb36
Add cached structured MMS alias regression
masarray Sep 2, 2026
988c994
Preserve distinct static DataSet membership rows for FAT
masarray Sep 2, 2026
fab6370
Remove connected reconciliation gate from direct SCL FAT
masarray Sep 2, 2026
08aba0d
Prefer exact static DataSet identity in direct SCL FAT
masarray Sep 2, 2026
32c2ff5
Add direct SCL FAT latency and THD identity regressions
masarray Sep 2, 2026
4c525b6
Throttle repeated structured report warnings
masarray Sep 2, 2026
47becc8
Preserve scalar MMS reuse without collapsing structured FAT members
masarray Sep 2, 2026
b047703
Remove reconciliation from direct SCL FAT critical path
masarray Sep 2, 2026
22c0e7a
Allow explicit DataSet THD scalar signals into runtime
masarray Sep 2, 2026
e488f79
Lock THD runtime publication and nonblocking SCL FAT startup
masarray Sep 2, 2026
88e7901
Fix FAT runtime responsiveness and multi-IED workflow
masarray Sep 2, 2026
a1db1f0
Fix fresh SCL selection authority
masarray Sep 2, 2026
d31c0b9
Add fresh SCL selection authority regression coverage
masarray Sep 2, 2026
2fb5b27
Add schema-safe aggregate value projector
masarray Sep 2, 2026
a30d716
Align workspace bridge regression with fresh SCL authority
masarray Sep 2, 2026
3e5c946
Define schema-proven aggregate read plans
masarray Sep 2, 2026
dfca8f9
Expose schema-safe aggregate read authority
masarray Sep 2, 2026
738ce9a
Route aggregate FAT reads through exact schema leaves
masarray Sep 2, 2026
6fd04b2
Add schema-safe THD and demand aggregate regressions
masarray Sep 2, 2026
3eef76a
Fix Removed Signals restore authority
masarray Sep 2, 2026
6c0d1c5
Add Removed Signals authority regression
masarray Sep 2, 2026
d4102a2
Keep demand companion reads on proven scalar leaf
masarray Sep 2, 2026
f642c74
Keep FAT disposition independent from shared selection
masarray Sep 2, 2026
2ae8986
Align THD fast-path regression with schema-safe parent reads
masarray Sep 2, 2026
277378e
Regress Removed Signals selection independence
masarray Sep 2, 2026
7bc5e1b
P0.3 make FAT plan locks per IED
masarray Sep 2, 2026
7c5cdc5
P0.3 lock Removed Signals per IED
masarray Sep 2, 2026
c5b438d
Regress P0.3 per-IED FAT UI locks
masarray Sep 2, 2026
9df05ad
P0.3 make checkbox lock synchronous per IED
masarray Sep 2, 2026
a35ba65
Regress synchronous per-IED checkbox locking
masarray Sep 2, 2026
e3f9705
Exercise P0.3 per-IED editability behavior
masarray Sep 2, 2026
a6a48ba
Add P0.4 loaded FAT SCL append transaction
masarray Sep 2, 2026
9316fb8
Route FAT Add IED through append gate
masarray Sep 2, 2026
c716573
Make loaded FAT SCL import additive by default
masarray Sep 2, 2026
d17851a
Allow SCL append during independent IED workflows
masarray Sep 2, 2026
cf817b7
Add P0.4 loaded FAT SCL append regression
masarray Sep 2, 2026
91a19f0
Fix P0.4 append result namespace
masarray Sep 2, 2026
35ddc22
Align workspace mode regression with P0.4 append semantics
masarray Sep 2, 2026
60a1732
Align IO testing add-IED contract with P0.4
masarray Sep 2, 2026
0f73368
Decouple IED connect from FAT checkbox scope
masarray Sep 2, 2026
5ac2e3b
Add FAT acquisition scope independent of TEST selection
masarray Sep 2, 2026
49229c6
Fix FAT monitor helper namespace
masarray Sep 2, 2026
f22648d
Harden independent multi-IED FAT acquisition
masarray Sep 2, 2026
efec317
Keep FAT evidence scope separate from connection acquisition
masarray Sep 2, 2026
32a5860
Lock P1 multi-IED connection and acquisition contract
masarray Sep 2, 2026
6dc4370
Resolve direct SCL acquisition independently of TEST
masarray Sep 2, 2026
b3a9610
Regress unchecked direct-SCL acquisition in P1
masarray Sep 2, 2026
4940877
Fix P1 direct-SCL regression fixture
masarray Sep 2, 2026
2c6b3a3
Align continuation scope regression with P1 acquisition authority
masarray Sep 2, 2026
0483f63
Document P1 monitor-start compatibility seam
masarray Sep 2, 2026
4a897e6
Add per-IED parallel FAT evidence coordinator
masarray Sep 2, 2026
1ff4df9
Wire parallel FAT evidence leaves to runtime
masarray Sep 2, 2026
62bce48
Enable per-IED parallel FAT evidence sessions
masarray Sep 2, 2026
4089fd0
Add P2 parallel FAT evidence regression coverage
masarray Sep 2, 2026
5b3f68f
Lock P2 per-IED evidence session contract
masarray Sep 2, 2026
345058f
Route runtime snapshots to parallel FAT leaves
masarray Sep 2, 2026
0d16214
Align P2 runtime wiring regression
masarray Sep 2, 2026
02f64bd
Project P2 session state by selected IED
masarray Sep 2, 2026
6451d86
Guard P2 export and close across all IED sessions
masarray Sep 2, 2026
ba56d17
Align P2 regression with selected-context session state
masarray Sep 2, 2026
99ecabe
Keep P2 FAT plan locks scoped to owning IED
masarray Sep 2, 2026
254bc91
Regress P2 per-IED restore and remove locks
masarray Sep 2, 2026
30e1237
Unify Engineering and FAT SCL signal workspace
masarray Sep 3, 2026
f4cdbf7
Modernize shared SCL import workflow
masarray Sep 3, 2026
32a2a90
Separate shared workspace selection from FAT scope
masarray Sep 3, 2026
2c7bfc8
Scope direct SCL acquisition to shared workspace selection
masarray Sep 3, 2026
bada688
Materialize manual SCL selections as FAT workspace rows
masarray Sep 3, 2026
b5b4e3d
Preserve FAT scope during manual workspace selection
masarray Sep 3, 2026
88e6630
Refresh FAT projection after shared workspace mutations
masarray Sep 3, 2026
cccd059
Allow true manual SCL workspace projection into FAT
masarray Sep 3, 2026
ee31457
Preserve Engineering selection in direct SCL FAT preparation
masarray Sep 3, 2026
4c41ee1
Project FAT rows from shared workspace selection
masarray Sep 3, 2026
33fa27f
Keep FAT evidence scope inside shared workspace selection
masarray Sep 3, 2026
eb0c7da
Preflight only shared workspace FAT scope
masarray Sep 3, 2026
d7131af
Make FAT disposition a hard report scope boundary
masarray Sep 3, 2026
20fad32
Exclude removed FAT rows from print preview scope
masarray Sep 3, 2026
5faf31b
Exclude removed rows from every FAT report layout
masarray Sep 3, 2026
8f852e6
Keep selected IED preview identity while filtering at render boundary
masarray Sep 3, 2026
5ad24e2
Use one scoped report contract for PDF and print preview
masarray Sep 3, 2026
009e239
Regress Remove from FAT across testing report boundaries
masarray Sep 3, 2026
fa715ae
Restore shared workspace selection and manual SCL rows on reopen
masarray Sep 3, 2026
22661c2
Regress shared SCL workspace persistence across reopen
masarray Sep 3, 2026
b014c02
Regress Remove from FAT as a hard test and report exclusion
masarray Sep 3, 2026
a4f9ad8
Fix manual workspace projection compile shadowing
masarray Sep 3, 2026
1c3727b
Align partial live regression with shared SCL authority
masarray Sep 3, 2026
8e058f0
Regress Engineering selection as shared workspace authority
masarray Sep 3, 2026
ad0424e
Preserve preflight duplicate contract wording
masarray Sep 3, 2026
5670a82
Align selection authority regression with shared workspace state
masarray Sep 3, 2026
dbe440b
Align P1 regression with shared SCL acquisition authority
masarray Sep 3, 2026
7017208
Persist shared SCL selection and manual row identity
masarray Sep 3, 2026
bb68b42
Align workspace bridge regression with shared selection authority
masarray Sep 3, 2026
f35ffc2
Align workspace mode regression with shared selection authority
masarray Sep 3, 2026
41594ab
P3 add generic FAT value capture provenance and stages
masarray Sep 3, 2026
35f250b
P3 add automatic stable Value 1 and Value 2 capture coordinator
masarray Sep 3, 2026
a1d48a3
P3 make Value 1 and Value 2 effective evidence generic
masarray Sep 3, 2026
514ce75
P3 distinguish operator recapture provenance
masarray Sep 3, 2026
4713074
P3 add auto capture and transactional bulk recapture engine
masarray Sep 3, 2026
bb9f029
P3 route bulk Recapture through isolated IED sessions
masarray Sep 3, 2026
c78fda9
P3 add multi-row selection and Recapture context menu
masarray Sep 3, 2026
dcef256
Preserve full IED precision in FAT snapshot tooltips
masarray Sep 3, 2026
f8fc485
Regress full precision FAT snapshot timestamp tooltips
masarray Sep 3, 2026
00bd100
P3 regress auto capture, transactional Recapture and multi-row UX
masarray Sep 3, 2026
9087e4f
Fix P3 regression fixture init-only identity
masarray Sep 3, 2026
59515ba
Align legacy session tests with P3 capture contract
masarray Sep 3, 2026
8e96f14
Align point-update regression with P3 completion status
masarray Sep 3, 2026
6a201e3
Fix P3 pair journal regression to verify sealed evidence
masarray Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .release/windows.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "1.6.32",
"version": "1.6.33",
"channel": "stable",
"platform": "windows-x64",
"primaryAsset": "ARSAS-Windows-x64-Setup.exe",
"publicationRequest": 20
"publicationRequest": 21
}
21 changes: 21 additions & 0 deletions App.WindowsIdentity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Runtime.InteropServices;

namespace ArIED61850Tester;

internal static class WindowsApplicationIdentity
{
private const string AppUserModelId = "masarray.ARSAS.IEC61850";

internal static void Apply()
{
if (!OperatingSystem.IsWindows())
return;

// A stable explicit identity makes Windows use the ARSAS executable icon for
// taskbar grouping even when the app was launched by dotnet or a portable host.
_ = SetCurrentProcessExplicitAppUserModelID(AppUserModelId);
}

[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SetCurrentProcessExplicitAppUserModelID(string appId);
}
1 change: 1 addition & 0 deletions App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public partial class App : Application

protected override void OnStartup(StartupEventArgs e)
{
WindowsApplicationIdentity.Apply();
base.OnStartup(e);

// P2 installs one calm industrial visual system before StartupUri materializes.
Expand Down
6 changes: 3 additions & 3 deletions ArIED61850Tester.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
<Product>ARSAS</Product>
<AssemblyTitle>ARSAS - IEC 61850 Engineering Workstation</AssemblyTitle>
<Description>Open-source Windows IEC 61850 engineering workstation for MMS model discovery, reporting, independent multi-IED monitoring, GOOSE subscription, fault-record file transfer, Sampled Values engineering and evidence export, SCL workflows, diagnostics, sequence of events, and guarded control validation.</Description>
<Version>1.6.32</Version>
<AssemblyVersion>1.6.32.0</AssemblyVersion>
<FileVersion>1.6.32.0</FileVersion>
<Version>1.6.33</Version>
<AssemblyVersion>1.6.33.0</AssemblyVersion>
<FileVersion>1.6.33.0</FileVersion>
<PackageProjectUrl>https://github.com/masarray/arsas</PackageProjectUrl>
<RepositoryUrl>https://github.com/masarray/arsas</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ Notable public changes to ARSAS are recorded here. Application releases must ide

## Unreleased

## 1.6.33 — 2026-09-02

### Added

- FAT workspaces can import additional CID/SCD/ICD/IID sources without replacing the current project, including while another IED evidence session remains active.
- Engineering and FAT workspaces now share imported SCL signal selection, so operator selection remains consistent when switching modes.

### Fixed

- Direct-SCL FAT connection now reuses the imported model and returns after the MMS association and bounded point setup instead of rediscovering or waiting through the legacy settle path.
- Structured THD current/voltage aggregates and demand-energy values retain exact parent and phase identities and use authoritative MMS projections instead of remaining `Unknown`.
- FAT live updates are coalesced below operator input priority; steady telemetry no longer refreshes the whole collection or schedules autosave for every sample, restoring smooth scrolling and reliable Capture clicks.
- The Add IED action is independent from the active evidence-session edit lock while preserving the running IED's immutable capture mapping.
- Windows receives a stable ARSAS AppUserModelID in addition to the embedded executable icon, fixing generic taskbar grouping for portable and `dotnet`-hosted launches.

## 1.6.31 — 2026-08-15

### Fixed
Expand Down
8 changes: 4 additions & 4 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<Version>1.6.32</Version>
<AssemblyVersion>1.6.32.0</AssemblyVersion>
<FileVersion>1.6.32.0</FileVersion>
<InformationalVersion>1.6.32</InformationalVersion>
<Version>1.6.33</Version>
<AssemblyVersion>1.6.33.0</AssemblyVersion>
<FileVersion>1.6.33.0</FileVersion>
<InformationalVersion>1.6.33</InformationalVersion>
</PropertyGroup>
</Project>
82 changes: 82 additions & 0 deletions IoListTestingWindow.AddIed.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.IO;
using System.Windows;
using ArIED61850Tester.Models.IoTesting;
using ArIED61850Tester.Services.IoTesting;
using Microsoft.Win32;

namespace ArIED61850Tester;

public partial class IoListTestingWindow
{
private async void AddFatIedFromScl_Click(object sender, RoutedEventArgs e)
{
if (!CanAddFatIed || Owner is not MainWindow engineeringWindow)
return;

var dialog = new OpenFileDialog
{
Title = "Add IEC 61850 IED to current FAT workspace",
Filter = "IEC 61850 SCL (*.scd;*.cid;*.icd;*.iid;*.ssd)|*.scd;*.cid;*.icd;*.iid;*.ssd|XML SCL (*.xml)|*.xml|All files (*.*)|*.*",
CheckFileExists = true,
Multiselect = true
};
if (dialog.ShowDialog(this) != true)
return;

var result = await ImportAdditionalSclSourcesAsync(engineeringWindow, dialog.FileNames);
if (!result.Succeeded)
ShowActionResult(result, "IED could not be added");
}

internal async Task<IoTestSessionActionResult> ImportAdditionalSclSourcesAsync(
MainWindow engineeringWindow,
IReadOnlyCollection<string> sclPaths)
{
ArgumentNullException.ThrowIfNull(engineeringWindow);
ArgumentNullException.ThrowIfNull(sclPaths);
if (_isAddingFatIeds)
return IoTestSessionActionResult.Failure("Another SCL append is already being prepared for this FAT workspace.");

SetAddingFatIeds(true);
PreparationStatusText = $"Importing {sclPaths.Count} SCL source(s) into the current FAT workspace…";
try
{
var result = await engineeringWindow.AppendSclIedsToLoadedFatAsync(this, sclPaths);
PreparationStatusText = result.Message;
return result;
}
catch (OperationCanceledException)
{
const string message = "SCL append was cancelled.";
PreparationStatusText = message;
return IoTestSessionActionResult.Failure(message);
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or InvalidDataException or InvalidOperationException or ArgumentException)
{
PreparationStatusText = ex.Message;
return IoTestSessionActionResult.Failure(ex.Message);
}
finally
{
SetAddingFatIeds(false);
}
}

internal void RegisterAddedIeds(IReadOnlyCollection<Models.IoTesting.IoTestIedPlan> addedIeds)
{
Project.InitializeRuntimeNotifications();
foreach (var ied in addedIeds)
{
if (_selectedIedContextInstalled)
ied.PropertyChanged += ContextIed_PropertyChanged;
Storage?.TrackAddedIed(ied);
}

FatIedList.Items.Refresh();
SelectedIed = addedIeds.FirstOrDefault() ?? SelectedIed;
Raise(nameof(ProjectSummary));
RaiseStatusProperties();
RaiseSelectedIedContextProperties();
Storage?.ScheduleSave();
}
}
76 changes: 44 additions & 32 deletions IoListTestingWindow.ContextUx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ namespace ArIED61850Tester;
public partial class IoListTestingWindow
{
private bool _selectedIedContextInstalled;
private bool _contextRefreshScheduled;
private bool _contextRowRefreshScheduled;

public bool SelectedCanStartWorkflow =>
SelectedIed != null && !SelectedIed.IsPreparing && Session.CanStart;
Expand Down Expand Up @@ -168,19 +170,10 @@ private async void ConnectIed_Click(object sender, RoutedEventArgs e)
if (targetIed == null || targetIed.IsPreparing)
return;

var enabledReady = targetIed.TestPoints
.Where(point => point.IsIncludedInFat && point.TestEnabled && point.ImportReady)
.ToList();
if (enabledReady.Count == 0)
{
ShowActionResult(
IoTestSessionActionResult.Failure("No import-ready operator-selected signal is enabled in the active FAT scope for this IED."),
"IED connection scope is not ready");
return;
}

IReadOnlyCollection<IoTestPointPlan> connectionScope = enabledReady;

// P1: Connect owns endpoint/MMS/live-acquisition state, never FAT evidence
// selection. The preparation path receives no checkbox scope here and therefore
// acquires every shared-workspace-selected included import-ready SCL row for this
// IED. TEST remains authoritative only when Start FAT builds captureScope below.
if (ReferenceEquals(SelectedIed, targetIed))
PreparationStatusText = $"Connecting {targetIed.IedName} · {targetIed.IpAddress}:102";
RaisePreparationProperties();
Expand All @@ -202,8 +195,7 @@ private async void ConnectIed_Click(object sender, RoutedEventArgs e)
var preparation = await PrepareIndependentIedConnectionAsync(
engineeringWindow,
targetIed,
progress,
connectionScope);
progress);

RaiseStatusProperties();
RaiseSelectedIedContextProperties();
Expand Down Expand Up @@ -259,8 +251,11 @@ private async void StartSelectedIedSafely_Click(object sender, RoutedEventArgs e
return;
}

// TEST is evidence authority only. Keep this selected capture scope for the
// evidence controller, while connection/live acquisition below remains the full
// shared-workspace-selected included import-ready IED scope.
var captureScope = selectedIed.TestPoints
.Where(point => point.IsIncludedInFat && point.TestEnabled && point.ImportReady)
.Where(point => point.WorkspaceSelected && point.IsIncludedInFat && point.TestEnabled && point.ImportReady)
.ToList();

try
Expand All @@ -277,8 +272,7 @@ private async void StartSelectedIedSafely_Click(object sender, RoutedEventArgs e
var preparation = await engineeringWindow.PrepareIoTestIedForFatAsync(
Project,
selectedIed,
progress,
captureScope);
progress);
RaiseStatusProperties();
RaiseSelectedIedContextProperties();
if (!preparation.Succeeded)
Expand All @@ -291,7 +285,7 @@ private async void StartSelectedIedSafely_Click(object sender, RoutedEventArgs e
await CaptureTimeSyncEvidenceAfterPreparationAsync(engineeringWindow, selectedIed);
}

// Operator selection remains authoritative. A selected static DataSet row that
// Operator selection remains authoritative. A selected SCL workspace row that
// has no unique live point stays checked/included and visible, but it cannot be
// allowed to manufacture evidence. Arm only the currently proven live subset.
// Legacy source-contract spelling retained only as documentation:
Expand Down Expand Up @@ -347,41 +341,57 @@ private async void StartSelectedIedSafely_Click(object sender, RoutedEventArgs e
private Task<IoTestSessionActionResult> PrepareIndependentIedConnectionAsync(
MainWindow engineeringWindow,
IoTestIedPlan targetIed,
IProgress<string> progress,
IReadOnlyCollection<IoTestPointPlan> connectionScope)
IProgress<string> progress)
=> engineeringWindow.PrepareIoTestIedForFatAsync(
Project,
targetIed,
progress,
connectionScope);
progress);

private void ContextWindow_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName is nameof(SelectedIed) or nameof(IsPreparingIed) or nameof(PreparationStatusText))
{
RaiseSelectedIedContextProperties();
if (e.PropertyName == nameof(SelectedIed))
Dispatcher.BeginInvoke(new Action(RefreshFatV2WorkspaceUx), DispatcherPriority.DataBind);
Dispatcher.BeginInvoke(
new Action(() => RefreshFatV2WorkspaceUx(refreshRows: true)),
DispatcherPriority.Background);
}
}

private void ContextSession_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
RaiseSelectedIedContextProperties();
RefreshFatV2WorkspaceUx();
ScheduleContextRefresh();
}

private void ContextIed_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(IoTestIedPlan.IsPreparing))
RaisePreparationProperties();

RefreshFatV2WorkspaceUx();
if (!ReferenceEquals(sender, SelectedIed))
return;
ScheduleContextRefresh(e.PropertyName is
nameof(IoTestIedPlan.EnabledCount) or
nameof(IoTestIedPlan.RemovedCount));
}

Raise(nameof(SelectedIedSummary));
RaiseSelectedIedContextProperties();
private void ScheduleContextRefresh(bool refreshRows = false)
{
_contextRowRefreshScheduled |= refreshRows;
if (_contextRefreshScheduled)
return;
_contextRefreshScheduled = true;
Dispatcher.BeginInvoke(new Action(() =>
{
_contextRefreshScheduled = false;
var refreshFilteredRows = _contextRowRefreshScheduled;
_contextRowRefreshScheduled = false;
// Session/runtime notifications update summaries and visible cells through
// normal bindings. Re-filter only when shared selection/disposition changes;
// live value traffic must never interrupt scrolling or Capture clicks.
RefreshFatV2WorkspaceUx(refreshFilteredRows);
Raise(nameof(SelectedIedSummary));
RaiseSelectedIedContextProperties();
}), DispatcherPriority.Background);
}

private void RaiseSelectedIedContextProperties()
Expand Down Expand Up @@ -409,7 +419,9 @@ private void ContextWindow_Closed(object? sender, EventArgs e)
}

private static List<IoTestPointPlan> EnabledPoints(IoTestIedPlan ied)
=> ied.TestPoints.Where(point => point.IsIncludedInFat && point.TestEnabled).ToList();
=> ied.TestPoints
.Where(point => point.WorkspaceSelected && point.IsIncludedInFat && point.TestEnabled)
.ToList();
}

public sealed class IoFatAllPassedVisibilityConverter : IMultiValueConverter
Expand Down
Loading
Loading