/
docNemo
/
clothes-graph
Обзор
Документация
Войти
/
docNemo
/
clothes-graph
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/ClothesGraph.App/ViewModels/MeasurementRowViewModel.cs
156 строк
5 KB
docNemo
Вкладка деталей выкройки, создание документа и пересчёт производных вкладок
09 авг 2026, 14:03
09 авг 2026, 14:03
dd71293
Код
Авторство
О чём код?
using System; using System.Globalization; using ClothesGraph.Geometry; using ClothesGraph.Model; using ClothesGraph.Model.Measurements; using CommunityToolkit.Mvvm.ComponentModel; namespace ClothesGraph.App.ViewModels; /// <summary> /// Строка таблицы мерок для выбранного размера. /// </summary> /// <remarks> /// Ввод принимается текстом и разбирается при подтверждении. Отказ разбора или /// конфликт имени не откатывает остальные правки и не рушит модель — строка /// показывает ошибку и продолжает работать. /// </remarks> public sealed partial class MeasurementRowViewModel : ObservableObject { private readonly PatternDocument _document; private readonly MeasurementsViewModel _owner; private bool _suppressWriteBack; [ObservableProperty] private string _name; [ObservableProperty] private string _value; [ObservableProperty] private string? _error; [ObservableProperty] private bool _isInherited; public MeasurementRowViewModel( PatternDocument document, MeasurementsViewModel owner, Measurement measurement, string size) { _document = document; _owner = owner; Id = measurement.Id; _name = measurement.DisplayName; _value = string.Empty; Refresh(size); } public MeasurementId Id { get; } /// <summary>Обновляет отображаемые имя и значение под выбранный размер.</summary> public void Refresh(string size) { var measurement = _document.Measurements.Get(Id); var unit = _document.DisplayUnit; // Обновление идёт из модели, поэтому обратная запись подавляется: // иначе показ значения тут же переписал бы его в модели. _suppressWriteBack = true; try { Name = measurement.DisplayName; if (_document.Sizes.TryGetValue(size, Id, out var stored)) { IsInherited = false; Value = Format(stored, unit); } else if (string.Equals(size, _document.Sizes.BaseSize, StringComparison.CurrentCultureIgnoreCase)) { IsInherited = true; Value = Format(measurement.Value, unit); } else { IsInherited = false; Value = string.Empty; } } finally { _suppressWriteBack = false; } Error = null; } private static string Format(Length length, LengthUnit unit) => length.To(unit).ToString("0.##", CultureInfo.CurrentCulture); partial void OnNameChanged(string value) { if (_suppressWriteBack) return; var measurement = _document.Measurements.Get(Id); if (string.Equals(measurement.DisplayName, value, StringComparison.Ordinal)) return; try { _document.Measurements.Rename(Id, value); _document.MarkModified(); Error = null; } catch (MeasurementNameConflictException conflict) { Error = conflict.Message; } catch (ArgumentException problem) { Error = problem.Message; } } partial void OnValueChanged(string value) { if (_suppressWriteBack) return; var size = _owner.SelectedSize; if (size is null) return; // Пустая строка означает «значение не задано»: для неосновного размера // это переводит мерку в разряд недостающих, а не обнуляет её. if (string.IsNullOrWhiteSpace(value)) { _document.Sizes.ClearValue(size, Id); _document.MarkModified(); Error = null; _owner.NotifyCompletenessChanged(); return; } if (!Length.TryParse(value, _document.DisplayUnit, CultureInfo.CurrentCulture, out var parsed)) { Error = "Не удалось разобрать значение"; return; } _document.Sizes.SetValue(size, Id, parsed); if (string.Equals(size, _document.Sizes.BaseSize, StringComparison.CurrentCultureIgnoreCase)) _document.Measurements.SetValue(Id, parsed); _document.MarkModified(); IsInherited = false; Error = null; _owner.NotifyCompletenessChanged(); } }