diff --git a/CursorLang/Services/ILocalizationService.cs b/CursorLang/Services/ILocalizationService.cs
index 16efc3f..6bab8a0 100644
--- a/CursorLang/Services/ILocalizationService.cs
+++ b/CursorLang/Services/ILocalizationService.cs
@@ -5,7 +5,11 @@ namespace CursorLang.Services;
/// Язык интерфейса для выбора в настройках.
/// Код культуры: «ru», «en».
/// Название на самом этом языке.
-public sealed record LanguageOption(string Code, string DisplayName);
+public sealed record LanguageOption(string Code, string DisplayName)
+{
+ // Средства доступности берут имя элемента списка отсюда
+ public override string ToString() => DisplayName;
+}
///
/// Даёт строки интерфейса и умеет менять язык без перезапуска.
diff --git a/CursorLang/ViewModels/SettingsViewModel.cs b/CursorLang/ViewModels/SettingsViewModel.cs
index 3b55be6..97506ed 100644
--- a/CursorLang/ViewModels/SettingsViewModel.cs
+++ b/CursorLang/ViewModels/SettingsViewModel.cs
@@ -7,8 +7,32 @@ using CursorLang.Services;
namespace CursorLang.ViewModels;
-/// Вариант выбора в списке: значение и его подпись на текущем языке.
-public sealed record EnumOption(T Value, string Display);
+///
+/// Вариант выбора в списке. Подпись меняется вместе с языком, а сам объект
+/// живёт всё время работы окна: если пересоздавать элементы списка,
+/// ComboBox сбрасывает выбранное значение.
+///
+public sealed class EnumOption : ObservableObject where T : struct, Enum
+{
+ private string _display;
+
+ public EnumOption(T value, string display)
+ {
+ Value = value;
+ _display = display;
+ }
+
+ public T Value { get; }
+
+ public string Display
+ {
+ get => _display;
+ set => SetProperty(ref _display, value);
+ }
+
+ // Средства доступности берут имя элемента списка отсюда
+ public override string ToString() => Display;
+}
///
/// Окно настроек. Значения правятся прямо в ,
@@ -38,7 +62,9 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable
Settings.PropertyChanged += OnSettingsChanged;
Localization.PropertyChanged += OnLocalizationChanged;
- BuildLocalizedOptions();
+ PlacementModes = CreateOptions();
+ CursorCorners = CreateOptions();
+ ScreenPositions = CreateOptions();
}
public AppSettings Settings { get; }
@@ -47,11 +73,11 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable
public IReadOnlyList BackgroundPalette { get; } = Palette;
- public IReadOnlyList> PlacementModes { get; private set; } = [];
+ public IReadOnlyList> PlacementModes { get; }
- public IReadOnlyList> CursorCorners { get; private set; } = [];
+ public IReadOnlyList> CursorCorners { get; }
- public IReadOnlyList> ScreenPositions { get; private set; } = [];
+ public IReadOnlyList> ScreenPositions { get; }
public void Dispose()
{
@@ -68,26 +94,31 @@ public sealed partial class SettingsViewModel : ObservableObject, IDisposable
}
// Подписи вариантов приходят из ресурсов, поэтому при смене языка
- // списки нужно собрать заново — привязки сами перечитают их
+ // обновляем только текст — сами элементы списков остаются прежними
private void OnLocalizationChanged(object? sender, PropertyChangedEventArgs e)
{
- if (e.PropertyName == Binding.IndexerName)
+ if (e.PropertyName != Binding.IndexerName)
{
- BuildLocalizedOptions();
+ return;
+ }
+
+ Translate(PlacementModes);
+ Translate(CursorCorners);
+ Translate(ScreenPositions);
+ }
+
+ private EnumOption[] CreateOptions() where T : struct, Enum =>
+ [.. Enum.GetValues().Select(value => new EnumOption(value, GetDisplayName(value)))];
+
+ private void Translate(IReadOnlyList> options) where T : struct, Enum
+ {
+ foreach (EnumOption option in options)
+ {
+ option.Display = GetDisplayName(option.Value);
}
}
- private void BuildLocalizedOptions()
- {
- PlacementModes = BuildOptions(nameof(PopupPlacementMode));
- CursorCorners = BuildOptions(nameof(CursorCorner));
- ScreenPositions = BuildOptions(nameof(ScreenPosition));
-
- OnPropertyChanged(nameof(PlacementModes));
- OnPropertyChanged(nameof(CursorCorners));
- OnPropertyChanged(nameof(ScreenPositions));
- }
-
- private EnumOption[] BuildOptions(string resourcePrefix) where T : struct, Enum =>
- [.. Enum.GetValues().Select(value => new EnumOption(value, Localization[$"{resourcePrefix}_{value}"]))];
+ // Ключ ресурса собирается из имени типа и значения: PopupPlacementMode_AtCursor
+ private string GetDisplayName(T value) where T : struct, Enum =>
+ Localization[$"{typeof(T).Name}_{value}"];
}