diff --git a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServiceDetailsWindow.xaml b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServiceDetailsWindow.xaml
index a7da255..1f056bf 100644
--- a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServiceDetailsWindow.xaml
+++ b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServiceDetailsWindow.xaml
@@ -14,15 +14,26 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
public sealed partial class ServiceDetailsWindow : Window
{
- public AgentClient Agent { get; }
+ public AgentClient Client { get; }
public ServiceInfo Service { get; }
private CancellationTokenSource? _cts;
@@ -37,7 +40,7 @@ public sealed partial class ServiceDetailsWindow : Window
public ServiceDetailsWindow(AgentClient agentClient, ServiceInfo serviceInfo)
{
InitializeComponent();
- Agent = agentClient;
+ Client = agentClient;
Service = serviceInfo;
ExtendsContentIntoTitleBar = true;
@@ -50,15 +53,182 @@ public ServiceDetailsWindow(AgentClient agentClient, ServiceInfo serviceInfo)
this.Closed += (_, _) => _cts?.Cancel();
}
+ private async void ServiceStartMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
+ ServiceInfo serviceInfo = Service;
+
+ UnitActionReply response = await Client!.Service.PerformUnitActionAsync(new UnitActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitActionRequest.Types.UnitAction.Start
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully started the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "started");
+ await Task.Delay(500); // brief delay to allow logs to populate
+ await GetLogsAsync(CancellationToken.None);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
+ }
+
+ private async void ServiceStopMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
+
+ ServiceInfo serviceInfo = (ServiceInfo)menuFlyoutItem.DataContext;
+
+ ContentDialog dialog = new()
+ {
+ XamlRoot = this.Content.XamlRoot,
+ Title = $"Are you sure you want to Stop {serviceInfo.Name}?",
+ CloseButtonText = "Cancel",
+ PrimaryButtonText = "Stop",
+ };
+
+ ContentDialogResult result = await dialog.ShowAsync();
+
+ if (result == ContentDialogResult.Primary)
+ {
+ UnitActionReply response = await Client!.Service.PerformUnitActionAsync(request: new UnitActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitActionRequest.Types.UnitAction.Stop
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully stopped the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "stopped");
+ await Task.Delay(500); // brief delay to allow logs to populate
+ await GetLogsAsync(CancellationToken.None);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
+ }
+ else
+ {
+ // Cancel, do nothing
+ }
+
+ }
+
+ private async void ServiceRestartMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
+
+ ServiceInfo serviceInfo = Service;
+
+ ContentDialog dialog = new()
+ {
+ XamlRoot = this.Content.XamlRoot,
+ Title = $"Are you sure you want to Restart {serviceInfo.Name}?",
+ CloseButtonText = "Cancel",
+ PrimaryButtonText = "Restart",
+ };
+
+ ContentDialogResult result = await dialog.ShowAsync();
+
+ if (result == ContentDialogResult.Primary)
+ {
+ try
+ {
+ UnitActionReply response = await Client!.Service.PerformUnitActionAsync(new UnitActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitActionRequest.Types.UnitAction.Restart
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "restarted");
+ await Task.Delay(500); // brief delay to allow logs to populate
+ await GetLogsAsync(CancellationToken.None);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
+ }
+ catch (Exception ex)
+ {
+ if (ex is Grpc.Core.RpcException && serviceInfo.Name == "agent.service")
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the Agent!", InfoBarSeverity.Success);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync($"Exception during restart: {ex.Message}");
+ }
+ }
+ }
+ }
+
+ private async void ServiceEnableMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
+ ServiceInfo serviceInfo = Service;
+
+ UnitFileActionReply response = await Client!.Service.PerformUnitFileActionAsync(new UnitFileActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitFileActionRequest.Types.UnitFileAction.Enable
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully enabled the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "enabled");
+ await Task.Delay(500); // brief delay to allow logs to populate
+ await GetLogsAsync(CancellationToken.None);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
+ }
+
+ private async void ServiceDisableMenuItem_Click(object sender, RoutedEventArgs e)
+ {
+ MenuFlyoutItem menuFlyoutItem = (MenuFlyoutItem)sender;
+ ServiceInfo serviceInfo = Service;
+
+ UnitFileActionReply response = await Client!.Service.PerformUnitFileActionAsync(new UnitFileActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitFileActionRequest.Types.UnitFileAction.Disable
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully disabled the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "disabled");
+ await Task.Delay(500); // brief delay to allow logs to populate
+ await GetLogsAsync(CancellationToken.None);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
+ }
+
private async Task GetLogsAsync(CancellationToken cancellationToken)
{
- if (Agent == null) return;
+ if (Client == null) return;
AsyncServerStreamingCall? call = null;
try
{
- call = Agent.Journal.Action(new Journal.V1.JournalRequest()
+ call = Client.Journal.Action(new Journal.V1.JournalRequest()
{
NumFromTail = 50,
Field = Journal.V1.JournalRequest.Types.Field.Systemd,
@@ -152,5 +322,81 @@ private async Task GetLogsAsync(CancellationToken cancellationToken)
}
}
}
+
+ private async Task UpdateServiceVisualStateAsync(ServiceInfo serviceInfo, string action)
+ {
+ await DispatcherQueue.EnqueueAsync(() =>
+ {
+ switch (action)
+ {
+ case "enabled":
+ serviceInfo.State = "enabled";
+ serviceInfo.StateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"];
+ break;
+ case "disabled":
+ serviceInfo.State = "disabled";
+ serviceInfo.StateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"];
+ break;
+ case "started":
+ serviceInfo.ActiveState = "started";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorSuccessBrush"];
+ break;
+ case "restarted":
+ serviceInfo.ActiveState = "restarted";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCautionBrush"];
+ break;
+ case "stopped":
+ serviceInfo.ActiveState = "stopped";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"];
+ break;
+ default:
+ break;
+ }
+ });
+ }
+
+ private async Task ShowInfoBarAsync(string title, string message, InfoBarSeverity severity)
+ {
+ // Ensure UI thread
+ await DispatcherQueue.EnqueueAsync(() =>
+ {
+ if (GridRoot == null)
+ {
+ // fallback to page XamlRoot; but InfoBar must be in visual tree to be visible
+ // if GridRoot is not available the InfoBar won't be shown persistently.
+ return;
+ }
+
+ InfoBar infoBar = new()
+ {
+ Title = title,
+ Message = message,
+ Severity = severity,
+ IsOpen = true,
+ VerticalAlignment = VerticalAlignment.Top,
+ Margin = new Thickness(0, 0, 0, 0)
+ };
+
+ // Add to visual tree so it is visible
+ GridRoot.Children.Add(infoBar);
+
+ // Remove from visual tree when closed
+ void OnClosed(object? s, InfoBarClosedEventArgs args)
+ {
+ infoBar.Closed -= OnClosed;
+ if (GridRoot.Children.Contains(infoBar))
+ {
+ GridRoot.Children.Remove(infoBar);
+ }
+ }
+
+ infoBar.Closed += OnClosed;
+ });
+ }
+
+ private async Task ShowErrorInfoBarAsync(string message)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Error: {message}", InfoBarSeverity.Error);
+ }
}
}
diff --git a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml
index 7dbffea..a225039 100644
--- a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml
+++ b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml
@@ -49,10 +49,11 @@
ShowsScrollingPlaceholders="True"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
- Grid.Row="1">
+ Grid.Row="1"
+ >
-
+
@@ -66,33 +67,53 @@
-
+
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
-
-
+
+ Margin="0,0,0,8"/>
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml.cs b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml.cs
index cf31348..c68ca42 100644
--- a/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml.cs
+++ b/src/paradigm-ehb.CommandCenter.WinUI/srvMgnt/Views/ServicesPage.xaml.cs
@@ -1,5 +1,6 @@
using Grpc.Core;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@@ -119,9 +120,9 @@ private async void ServiceStopMenuItem_Click(object sender, RoutedEventArgs e)
ContentDialog dialog = new()
{
XamlRoot = this.XamlRoot,
- Title = $"Are you sure you want to Stop {serviceInfo.Name} ?",
+ Title = $"Are you sure you want to Stop {serviceInfo.Name}?",
CloseButtonText = "Cancel",
- PrimaryButtonText = "Kill",
+ PrimaryButtonText = "Stop",
};
ContentDialogResult result = await dialog.ShowAsync();
@@ -143,7 +144,8 @@ private async void ServiceStopMenuItem_Click(object sender, RoutedEventArgs e)
{
await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
}
- } else
+ }
+ else
{
// Cancel, do nothing
}
@@ -156,33 +158,46 @@ private async void ServiceRestartMenuItem_Click(object sender, RoutedEventArgs e
ServiceInfo serviceInfo = (ServiceInfo)menuFlyoutItem.DataContext;
- try
+ ContentDialog dialog = new()
{
- UnitActionReply response = await client!.Service.PerformUnitActionAsync(new UnitActionRequest
- {
- UnitName = serviceInfo.Name,
- Action = UnitActionRequest.Types.UnitAction.Restart
- });
+ XamlRoot = this.XamlRoot,
+ Title = $"Are you sure you want to Restart {serviceInfo.Name}?",
+ CloseButtonText = "Cancel",
+ PrimaryButtonText = "Restart",
+ };
- if (response.Success)
- {
- await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the service!", InfoBarSeverity.Success);
- await UpdateServiceVisualStateAsync(serviceInfo, "restarted");
- }
- else
- {
- await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
- }
- }
- catch (Exception ex)
+ ContentDialogResult result = await dialog.ShowAsync();
+
+ if (result == ContentDialogResult.Primary)
{
- if (ex is Grpc.Core.RpcException && serviceInfo.Name == "agent.service")
+ try
{
- await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the Agent!", InfoBarSeverity.Success);
+ UnitActionReply response = await client!.Service.PerformUnitActionAsync(new UnitActionRequest
+ {
+ UnitName = serviceInfo.Name,
+ Action = UnitActionRequest.Types.UnitAction.Restart
+ });
+
+ if (response.Success)
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the service!", InfoBarSeverity.Success);
+ await UpdateServiceVisualStateAsync(serviceInfo, "restarted");
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync(response.ErrorMessage ?? "Unknown error");
+ }
}
- else
+ catch (Exception ex)
{
- await ShowErrorInfoBarAsync($"Exception during restart: {ex.Message}");
+ if (ex is Grpc.Core.RpcException && serviceInfo.Name == "agent.service")
+ {
+ await ShowInfoBarAsync("Service Action Result", $"Successfully restarted the Agent!", InfoBarSeverity.Success);
+ }
+ else
+ {
+ await ShowErrorInfoBarAsync($"Exception during restart: {ex.Message}");
+ }
}
}
}
@@ -323,7 +338,6 @@ private async Task InitializeAsync(NavigationEventArgs e, System.Threading.Cance
await DispatcherQueue.EnqueueAsync(() =>
{
services.Clear();
- services.Add(new ServiceInfo { Name = "(error)", Description = ex.Message, Fill = new SolidColorBrush(Colors.Red) });
}).ConfigureAwait(false);
await ShowErrorInfoBarAsync($"Initialization failed: {ex.Message}");
}
@@ -332,7 +346,7 @@ await DispatcherQueue.EnqueueAsync(() =>
await DispatcherQueue.EnqueueAsync(() =>
{
services.Clear();
- services.Add(new ServiceInfo { Name = "(error)", Description = ex.Message, Fill = new SolidColorBrush(Colors.Red) });
+ services.Add(new ServiceInfo { Name = "(error)", Description = ex.Message, StateFill = new SolidColorBrush(Colors.Red) });
}).ConfigureAwait(false);
await ShowErrorInfoBarAsync($"Initialization failed: {ex.Message}");
@@ -368,33 +382,64 @@ private async Task LoadAllServices(CancellationToken cancellationToken = default
return;
}
- GetUnitsReply? response = await client.Service.GetAllUnitsAsync(request: new GetUnitsRequest(), cancellationToken: cancellationToken);
- if (response is null)
- {
- await ShowErrorInfoBarAsync("Failed to retrieve services: received null response from agent.");
- return;
- }
+ GetUnitsReply? response = await client.Service.GetAllUnitsAsync(request: new GetUnitsRequest(), cancellationToken: cancellationToken);
+ GetUnitsReply? loadedResponse = await client.Service.GetLoadedUnitsAsync(request: new GetUnitsRequest(), cancellationToken: cancellationToken);
+ if (response is null || loadedResponse is null)
+ {
+ await ShowErrorInfoBarAsync("Failed to retrieve services: received null response from agent.");
+ return;
+ }
- foreach (LoadedUnit? unit in response.Units)
+ IEnumerable units = response.Units;
+ IEnumerable loadedUnits = loadedResponse.Units;
+
+ // Returns the union of both, updating LoadState where possible
+ units = units.Join(
+ loadedUnits,
+ unit => ExtractShortUnitName(unit.Name),
+ loadedUnit => loadedUnit.Name,
+ (unit, loadedUnit) =>
{
- string unitName = ExtractShortUnitName(unit.Name);
- // Choose a color/brush based on unit state
- string state = (unit.LoadState ?? string.Empty).ToLowerInvariant();
- SolidColorBrush brush = state switch
- {
- "enabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"],
- "loaded" => (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"],
- "static" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"],
- "disabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"],
- _ => new SolidColorBrush(Colors.Goldenrod)
- };
-
- ServiceInfo serviceInfo = new ServiceInfo
+ if (loadedUnit is not null)
{
- Name = unitName,
- Description = $"State: {unit.LoadState}",
- Fill = brush
- };
+ loadedUnit.LoadState = unit.LoadState;
+ return loadedUnit;
+ }
+ return unit;
+ });
+
+ foreach (LoadedUnit? unit in units)
+ {
+ string unitName = ExtractShortUnitName(unit.Name);
+ // Choose a color/brush based on unit state
+ string state = (unit.LoadState ?? string.Empty).ToLowerInvariant();
+ SolidColorBrush brush = state switch
+ {
+ "enabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"],
+ "loaded" => (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"],
+ "static" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"],
+ "disabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"],
+ _ => new SolidColorBrush(Colors.Goldenrod)
+ };
+
+ SolidColorBrush activeStateFill = unit.ActiveState switch
+ {
+ "running" => (SolidColorBrush)Application.Current.Resources["SystemFillColorSuccessBrush"],
+ "exited" => (SolidColorBrush)Application.Current.Resources["SystemFillColorNeutralBrush"],
+ "dead" => (SolidColorBrush)Application.Current.Resources["SystemFillColorNeutralBrush"],
+ "failed" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBackgroundBrush"],
+ _ => new SolidColorBrush(Colors.Goldenrod)
+ };
+
+ ServiceInfo serviceInfo = new ServiceInfo
+ {
+ Name = unitName,
+ Description = unit.Description ?? unitName,
+ State = unit.LoadState ?? "Unknown",
+ ActiveState = unit.ActiveState ?? "",
+ StateFill = brush,
+ ActiveStateFill = activeStateFill
+ };
await DispatcherQueue.EnqueueAsync(() =>
{
@@ -461,28 +506,31 @@ private async Task UpdateServiceVisualStateAsync(ServiceInfo serviceInfo, string
{
await DispatcherQueue.EnqueueAsync(() =>
{
- string desc = action switch
- {
- "started" => "State: running",
- "stopped" => "State: stopped",
- "restarted" => "State: running",
- "enabled" => "State: enabled",
- "disabled" => "State: disabled",
- _ => serviceInfo.Description
- };
-
- SolidColorBrush brush = action switch
+ switch(action)
{
- "started" => new SolidColorBrush(Colors.Green),
- "stopped" => new SolidColorBrush(Colors.Gray),
- "restarted" => new SolidColorBrush(Colors.Green),
- "enabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"],
- "disabled" => (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"],
- _ => serviceInfo.Fill
- };
-
- serviceInfo.Description = desc;
- serviceInfo.Fill = brush;
+ case "enabled":
+ serviceInfo.State = "enabled";
+ serviceInfo.StateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorAttentionBrush"];
+ break;
+ case "disabled":
+ serviceInfo.State = "disabled";
+ serviceInfo.StateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"];
+ break;
+ case "started":
+ serviceInfo.ActiveState = "started";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorSuccessBrush"];
+ break;
+ case "restarted":
+ serviceInfo.ActiveState = "restarted";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCautionBrush"];
+ break;
+ case "stopped":
+ serviceInfo.ActiveState = "stopped";
+ serviceInfo.ActiveStateFill = (SolidColorBrush)Application.Current.Resources["SystemFillColorCriticalBrush"];
+ break;
+ default:
+ break;
+ }
});
}
@@ -498,17 +546,17 @@ private void Order_Services()
List ordered = order switch
{
"Name" => services.OrderBy(s => s.Name).ThenBy(s => s.Description).ToList(),
- "State" => services.OrderBy(p => p.Description).ThenBy(s => s.Name).ToList(),
+ "State" => services.OrderBy(p => p.State).ThenBy(s => s.Name).ToList(),
_ => services
.OrderBy(s =>
{
- if (!string.IsNullOrEmpty(s.Description) && s.Description.Contains("State: enabled", StringComparison.InvariantCultureIgnoreCase))
+ if (!string.IsNullOrEmpty(s.State) && s.State.Contains("enabled", StringComparison.InvariantCultureIgnoreCase))
return 0;
- if (!string.IsNullOrEmpty(s.Description) && s.Description.Contains("State: disabled", StringComparison.InvariantCultureIgnoreCase))
+ if (!string.IsNullOrEmpty(s.State) && s.State.Contains("disabled", StringComparison.InvariantCultureIgnoreCase))
return 1;
return 2;
})
- .ThenBy(s => s.Description, StringComparer.InvariantCultureIgnoreCase)
+ .ThenBy(s => s.State, StringComparer.InvariantCultureIgnoreCase)
.ThenBy(s => s.Name, StringComparer.InvariantCultureIgnoreCase)
.ToList()
};
@@ -592,52 +640,94 @@ await DispatcherQueue.EnqueueAsync(() =>
}
}
}
-
- // Small view-model used by the DataTemplate in XAML.
- public sealed class ServiceInfo : INotifyPropertyChanged
+
+ // Small view-model used by the DataTemplate in XAML.
+ public sealed class ServiceInfo : INotifyPropertyChanged
+ {
+ private string _name = string.Empty;
+ public string Name
{
- private string _name = string.Empty;
- public string Name
+ get => _name;
+ set
{
- get => _name;
- set
+ if (_name != value)
{
- if (_name != value)
- {
- _name = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
- }
+ _name = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
+ }
- private string _description = string.Empty;
- public string Description
+ private string _description = string.Empty;
+ public string Description
+ {
+ get => _description;
+ set
{
- get => _description;
- set
+ if (_description != value)
{
- if (_description != value)
- {
- _description = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
- }
+ _description = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
+ }
+ }
+ }
+
+ private string _state = string.Empty;
+ public string State
+ {
+ get => _state;
+ set
+ {
+ if (_state != value)
+ {
+ _state = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(State)));
}
}
+ }
- private SolidColorBrush _fill = new SolidColorBrush(Colors.Transparent);
- public SolidColorBrush Fill
+ private string _activeState = string.Empty;
+ public string ActiveState
+ {
+ get => _activeState;
+ set
{
- get => _fill;
- set
+ if (_activeState != value)
{
- if (_fill != value)
- {
- _fill = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Fill)));
- }
+ _activeState = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ActiveState)));
+ }
+ }
+ }
+
+ private SolidColorBrush _stateFill = new SolidColorBrush(Colors.Transparent);
+ public SolidColorBrush StateFill
+ {
+ get => _stateFill;
+ set
+ {
+ if (_stateFill != value)
+ {
+ _stateFill = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(StateFill)));
}
}
+ }
- public event PropertyChangedEventHandler? PropertyChanged;
+ private SolidColorBrush _activeStateFill = new SolidColorBrush(Colors.Transparent);
+ public SolidColorBrush ActiveStateFill
+ {
+ get => _activeStateFill;
+ set
+ {
+ if (_activeStateFill != value)
+ {
+ _activeStateFill = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ActiveStateFill)));
+ }
+ }
}
+
+ public event PropertyChangedEventHandler? PropertyChanged;
}
+}