Кнопка обновления и столбец актуального значения
This commit is contained in:
@@ -36,6 +36,16 @@ public sealed class LinuxEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
return System.Environment.GetEnvironmentVariable(name);
|
||||
}
|
||||
|
||||
public string? GetUserPersistedValue(string name)
|
||||
{
|
||||
if (LoadMergedFromDirectory().TryGetValue(name, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Set(string name, string value)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32;
|
||||
using Sms.Environment;
|
||||
|
||||
namespace Sms.Environment.Windows;
|
||||
@@ -7,14 +8,23 @@ public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
{
|
||||
private const int HWND_BROADCAST = 0xffff;
|
||||
private const int WM_SETTINGCHANGE = 0x001A;
|
||||
private const string EnvironmentKeyPath = "Environment";
|
||||
|
||||
public string? Get(string name) =>
|
||||
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User)
|
||||
GetUserPersistedValue(name)
|
||||
?? System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
|
||||
|
||||
public string? GetUserPersistedValue(string name)
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath);
|
||||
return key?.GetValue(name) as string;
|
||||
}
|
||||
|
||||
public void Set(string name, string value)
|
||||
{
|
||||
System.Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.User);
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath, writable: true)
|
||||
?? Registry.CurrentUser.CreateSubKey(EnvironmentKeyPath, writable: true);
|
||||
key.SetValue(name, value, RegistryValueKind.ExpandString);
|
||||
System.Environment.SetEnvironmentVariable(name, value, EnvironmentVariableTarget.Process);
|
||||
BroadcastEnvironmentChange();
|
||||
}
|
||||
@@ -39,15 +49,36 @@ public sealed class WindowsEnvironmentVariableStore : IEnvironmentVariableStore
|
||||
public IReadOnlyDictionary<string, string> GetProcessEnvironment() =>
|
||||
ToDictionary(System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Process));
|
||||
|
||||
public IReadOnlyDictionary<string, string> GetUserPersistedEnvironment() =>
|
||||
ToDictionary(System.Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User));
|
||||
public IReadOnlyDictionary<string, string> GetUserPersistedEnvironment()
|
||||
{
|
||||
var result = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath);
|
||||
if (key is null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool IsPersistedInUserStore(string name) =>
|
||||
System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User) is not null;
|
||||
foreach (var name in key.GetValueNames())
|
||||
{
|
||||
if (key.GetValue(name) is string value)
|
||||
{
|
||||
result[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool IsPersistedInUserStore(string name)
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath);
|
||||
return key?.GetValue(name) is not null;
|
||||
}
|
||||
|
||||
public void RemoveFromUserStore(string name)
|
||||
{
|
||||
System.Environment.SetEnvironmentVariable(name, null, EnvironmentVariableTarget.User);
|
||||
using var key = Registry.CurrentUser.OpenSubKey(EnvironmentKeyPath, writable: true);
|
||||
key?.DeleteValue(name, throwOnMissingValue: false);
|
||||
System.Environment.SetEnvironmentVariable(name, null, EnvironmentVariableTarget.Process);
|
||||
BroadcastEnvironmentChange();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ public interface IEnvironmentVariableStore
|
||||
{
|
||||
string? Get(string name);
|
||||
|
||||
string? GetUserPersistedValue(string name);
|
||||
|
||||
void Set(string name, string value);
|
||||
|
||||
bool Exists(string name);
|
||||
|
||||
@@ -41,10 +41,18 @@
|
||||
Click="OnCloseClick" />
|
||||
</Grid>
|
||||
|
||||
<CheckBox Grid.Row="1"
|
||||
Margin="12,8,12,0"
|
||||
Content="Отображать все переменные"
|
||||
IsChecked="{Binding ShowAllVariables}" />
|
||||
<Grid Grid.Row="1"
|
||||
Margin="12,8,12,0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
ColumnSpacing="8">
|
||||
<CheckBox Content="Отображать все переменные"
|
||||
IsChecked="{Binding ShowAllVariables}"
|
||||
VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1"
|
||||
Content="Обновить"
|
||||
Command="{Binding RefreshCommand}"
|
||||
MinWidth="100" />
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2"
|
||||
Margin="12,8,12,0"
|
||||
@@ -92,13 +100,21 @@
|
||||
<DataGridTextColumn Header="Поле"
|
||||
Binding="{Binding Field}"
|
||||
IsReadOnly="True"
|
||||
Width="2*" />
|
||||
<DataGridTextColumn Header="Значение"
|
||||
Binding="{Binding Value, Mode=TwoWay}"
|
||||
Width="3*" />
|
||||
Width="210"
|
||||
MinWidth="150" />
|
||||
<DataGridTextColumn Header="Требуемое значение"
|
||||
Binding="{Binding RequiredValue, Mode=TwoWay}"
|
||||
Width="2*"
|
||||
MinWidth="140" />
|
||||
<DataGridTextColumn Header="Актуальное значение"
|
||||
Binding="{Binding ActualValueDisplay}"
|
||||
IsReadOnly="True"
|
||||
Width="2*"
|
||||
MinWidth="140" />
|
||||
<DataGridTextColumn Header="Комментарий"
|
||||
Binding="{Binding Comment, Mode=TwoWay}"
|
||||
Width="3*" />
|
||||
Width="240"
|
||||
MinWidth="180" />
|
||||
<DataGridTemplateColumn Header=""
|
||||
Width="80">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
|
||||
@@ -49,7 +49,7 @@ public sealed class EnvironmentVariablesService
|
||||
continue;
|
||||
}
|
||||
|
||||
var value = ResolveValue(name);
|
||||
var value = ResolveRequiredValue(name);
|
||||
_store.Set(name, value);
|
||||
_log.WriteLine(
|
||||
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [INFO] Created configured variable: {name}={value}");
|
||||
@@ -64,7 +64,7 @@ public sealed class EnvironmentVariablesService
|
||||
|
||||
foreach (var name in _options.Names)
|
||||
{
|
||||
rows.Add(CreateRow(name, ResolveValue(name)));
|
||||
rows.Add(CreateRow(name, ResolveRequiredValue(name)));
|
||||
knownNames.Add(name);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public sealed class EnvironmentVariablesService
|
||||
{
|
||||
if (knownNames.Add(name))
|
||||
{
|
||||
rows.Add(CreateRow(name, ResolveValue(name)));
|
||||
rows.Add(CreateRow(name, ResolveRequiredValue(name)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ public sealed class EnvironmentVariablesService
|
||||
continue;
|
||||
}
|
||||
|
||||
rows.Add(CreateRow(pair.Key, pair.Value));
|
||||
rows.Add(CreateRow(pair.Key, ResolveRequiredValue(pair.Key)));
|
||||
}
|
||||
|
||||
return rows;
|
||||
@@ -137,14 +137,17 @@ public sealed class EnvironmentVariablesService
|
||||
public EnvironmentVariableRow GetRowSnapshot(string name)
|
||||
{
|
||||
ReloadMetadata();
|
||||
return CreateRow(name, ResolveValue(name));
|
||||
return CreateRow(name, ResolveRequiredValue(name));
|
||||
}
|
||||
|
||||
public string GetDisplayValue(string name) => ResolveValue(name);
|
||||
public string GetDisplayValue(string name) => ResolveRequiredValue(name);
|
||||
|
||||
public string? GetProcessValue(string name) =>
|
||||
_store.GetProcessEnvironment().TryGetValue(name, out var value) ? value : null;
|
||||
|
||||
public void SaveValue(string name, string value)
|
||||
{
|
||||
var previous = _store.Get(name);
|
||||
var previous = _store.GetUserPersistedValue(name);
|
||||
_store.Set(name, value);
|
||||
_log.WriteLine(
|
||||
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [INFO] Changed value: {name}={value} (previous: {previous ?? "<none>"})");
|
||||
@@ -183,7 +186,7 @@ public sealed class EnvironmentVariablesService
|
||||
return;
|
||||
}
|
||||
|
||||
var previous = _store.Get(name);
|
||||
var previous = _store.GetUserPersistedValue(name);
|
||||
_store.RemoveFromUserStore(name);
|
||||
_log.WriteLine(
|
||||
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [INFO] Removed from user store: {name} (previous: {previous ?? "<none>"})");
|
||||
@@ -215,17 +218,21 @@ public sealed class EnvironmentVariablesService
|
||||
string.Equals(name, _options.CommentsVariableName, StringComparison.Ordinal)
|
||||
|| string.Equals(name, _options.CustomVariablesVariableName, StringComparison.Ordinal);
|
||||
|
||||
private string ResolveValue(string name)
|
||||
private string ResolveRequiredValue(string name)
|
||||
{
|
||||
var existing = _store.Get(name);
|
||||
if (existing is not null)
|
||||
if (_store.GetUserPersistedValue(name) is { } persisted)
|
||||
{
|
||||
return existing;
|
||||
return persisted;
|
||||
}
|
||||
|
||||
if (_options.Defaults.TryGetValue(name, out var defaultValue))
|
||||
if (_configuredNames.Contains(name) || _customNames.Contains(name))
|
||||
{
|
||||
return defaultValue;
|
||||
if (_options.Defaults.TryGetValue(name, out var defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
||||
@@ -17,6 +17,7 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
IsCustom = row.IsCustom;
|
||||
_service = service;
|
||||
ApplySnapshot(row, suppressSave: true);
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
public string Field { get; }
|
||||
@@ -28,10 +29,16 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
[ObservableProperty]
|
||||
private bool _isPersistedInUserStore;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _actualValue = string.Empty;
|
||||
|
||||
public string ActualValueDisplay =>
|
||||
string.IsNullOrEmpty(ActualValue) ? "<нет>" : ActualValue;
|
||||
|
||||
public string UserStoreBadge => IsPersistedInUserStore ? "USER" : string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _value = string.Empty;
|
||||
private string _requiredValue = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _comment = string.Empty;
|
||||
@@ -43,30 +50,9 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
RowAppearanceChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler? RowAppearanceChanged;
|
||||
partial void OnActualValueChanged(string value) => OnPropertyChanged(nameof(ActualValueDisplay));
|
||||
|
||||
public void ApplySnapshot(EnvironmentVariableRow row, bool suppressSave = false)
|
||||
{
|
||||
if (suppressSave)
|
||||
{
|
||||
BeginLoad();
|
||||
}
|
||||
|
||||
Value = row.Value;
|
||||
Comment = row.Comment;
|
||||
IsPersistedInUserStore = row.IsPersistedInUserStore;
|
||||
|
||||
if (suppressSave)
|
||||
{
|
||||
EndLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginLoad() => _isLoading = true;
|
||||
|
||||
public void EndLoad() => _isLoading = false;
|
||||
|
||||
partial void OnValueChanged(string value)
|
||||
partial void OnRequiredValueChanged(string value)
|
||||
{
|
||||
if (_isLoading)
|
||||
{
|
||||
@@ -78,8 +64,38 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
{
|
||||
IsPersistedInUserStore = true;
|
||||
}
|
||||
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
public event EventHandler? RowAppearanceChanged;
|
||||
|
||||
public void ApplySnapshot(EnvironmentVariableRow row, bool suppressSave = false)
|
||||
{
|
||||
if (suppressSave)
|
||||
{
|
||||
BeginLoad();
|
||||
}
|
||||
|
||||
RequiredValue = row.Value;
|
||||
Comment = row.Comment;
|
||||
IsPersistedInUserStore = row.IsPersistedInUserStore;
|
||||
|
||||
if (suppressSave)
|
||||
{
|
||||
EndLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshActualValue(string? processValue)
|
||||
{
|
||||
ActualValue = processValue ?? string.Empty;
|
||||
}
|
||||
|
||||
public void BeginLoad() => _isLoading = true;
|
||||
|
||||
public void EndLoad() => _isLoading = false;
|
||||
|
||||
partial void OnCommentChanged(string value)
|
||||
{
|
||||
if (_isLoading)
|
||||
@@ -103,8 +119,9 @@ public sealed partial class EnvironmentVariableRowViewModel : ObservableObject
|
||||
_service.DeleteFromUserStore(Field);
|
||||
BeginLoad();
|
||||
IsPersistedInUserStore = false;
|
||||
Value = _service.GetDisplayValue(Field);
|
||||
RequiredValue = _service.GetDisplayValue(Field);
|
||||
EndLoad();
|
||||
RefreshActualValue(_service.GetProcessValue(Field));
|
||||
}
|
||||
|
||||
public event EventHandler? Removed;
|
||||
|
||||
@@ -35,6 +35,13 @@ public sealed partial class MainWindowViewModel : ObservableObject
|
||||
|
||||
partial void OnNewVariableNameChanged(string value) => AddVariableCommand.NotifyCanExecuteChanged();
|
||||
|
||||
[RelayCommand]
|
||||
private void Refresh()
|
||||
{
|
||||
SyncRowsFromService();
|
||||
RefreshProcessStates();
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanAddVariable))]
|
||||
private void AddVariable()
|
||||
{
|
||||
@@ -121,6 +128,16 @@ public sealed partial class MainWindowViewModel : ObservableObject
|
||||
MoveItem(Rows, currentIndex, targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
RefreshProcessStates();
|
||||
}
|
||||
|
||||
private void RefreshProcessStates()
|
||||
{
|
||||
foreach (var row in Rows)
|
||||
{
|
||||
row.RefreshActualValue(_service.GetProcessValue(row.Field));
|
||||
}
|
||||
}
|
||||
|
||||
private static void MoveItem(
|
||||
|
||||
Reference in New Issue
Block a user