forked from amkovkov/GranuSightSoftware2
feat: add brand calibration view and viewmodel
This commit is contained in:
@@ -0,0 +1,366 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
|
using GSS2.Core.Analysis.AmineContent.Database;
|
||||||
|
|
||||||
|
using GSS2.UI.Core.ViewModels;
|
||||||
|
using GSS2.UI.Core.Services;
|
||||||
|
|
||||||
|
namespace GSS2.ViewModels.AmineContent;
|
||||||
|
|
||||||
|
public partial class BrandCalibrationViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Внутренняя модель элементов меню
|
||||||
|
/// </summary>
|
||||||
|
public partial class MenuItemViewModel : ViewModelBase
|
||||||
|
{
|
||||||
|
[ObservableProperty] public partial int Id { get; set; }
|
||||||
|
[ObservableProperty] public partial string BrandName { get; set; }
|
||||||
|
[ObservableProperty] public partial string MixtureName { get; set; }
|
||||||
|
|
||||||
|
public MenuItemViewModel(int id, string brandName, string mixtureName)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
BrandName = brandName;
|
||||||
|
MixtureName = mixtureName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Логгер
|
||||||
|
/// </summary>
|
||||||
|
private readonly ILogger<BrandCalibrationViewModel> _logger;
|
||||||
|
/// <summary>
|
||||||
|
/// КОнтекст базы данных
|
||||||
|
/// </summary>
|
||||||
|
private readonly Context _context;
|
||||||
|
/// <summary>
|
||||||
|
/// ViewLocator для получения других View по их моделям
|
||||||
|
/// </summary>
|
||||||
|
private readonly DependencyInjectionViewLocator _viewLocator;
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис навигации между экранами
|
||||||
|
/// </summary>
|
||||||
|
private readonly NavigationService _navigation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Меню открыто
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial bool MenuOpened { get; set; } = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Элементы меню
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Текущий выбранный элемент меню. Равен -1 если элемент не выбран
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial int MenuSelectedIndex { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="BrandRecord.Id"/> выбранного элемента
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial int SelectedId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="BrandRecord.SelectedUuid"/> выбранного элемента
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial string SelectedUuid { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="BrandRecord.SelectedBrandName"/> выбранного элемента
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial string SelectedBrandName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="BrandRecord.SelectedMixtureName"/> выбранного элемента
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial string SelectedMixtureName { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="BrandRecord.SelectedMixtureNormalRate"/> выбранного элемента
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial double SelectedMixtureNormalRate { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Можно ли производить перемещение между экранами
|
||||||
|
/// </summary>
|
||||||
|
[ObservableProperty] public partial bool CanScroll { get; set; }
|
||||||
|
|
||||||
|
public BrandCalibrationViewModel(
|
||||||
|
ILogger<BrandCalibrationViewModel> logger,
|
||||||
|
Context context,
|
||||||
|
DependencyInjectionViewLocator viewLocator,
|
||||||
|
NavigationService navigation
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Устанавливаем readonly поля
|
||||||
|
_logger = logger;
|
||||||
|
_context = context;
|
||||||
|
_viewLocator = viewLocator;
|
||||||
|
_navigation = navigation;
|
||||||
|
_logger.LogInformation("Инициализация");
|
||||||
|
|
||||||
|
// Заполняем свойства пустыми значениями
|
||||||
|
MenuOpened = new();
|
||||||
|
MenuItems = new();
|
||||||
|
MenuSelectedIndex = -1;
|
||||||
|
CanScroll = true;
|
||||||
|
SelectedId = 0;
|
||||||
|
SelectedUuid = Guid.NewGuid().ToString();
|
||||||
|
SelectedBrandName = "";
|
||||||
|
SelectedMixtureName = "";
|
||||||
|
SelectedMixtureNormalRate = -1;
|
||||||
|
|
||||||
|
// Получаем записи из базы данных
|
||||||
|
MenuItems = new ObservableCollection<MenuItemViewModel>(_context.BrandRecords.Select(r => new MenuItemViewModel(r.Id, r.BrandName, r.MixtureName)));
|
||||||
|
if (MenuItems.Count() > 0) // Если записи есть,
|
||||||
|
MenuSelectedIndex = 0; // Выбираем первую запись
|
||||||
|
else // Если записей нет,
|
||||||
|
MenuSelectedIndex = -1; // Устанавливаем, что запись не выбрана
|
||||||
|
|
||||||
|
_logger.LogInformation("Инициализировано");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вызывается при изменении <see cref="MenuSelectedIndex"/>
|
||||||
|
/// </summary>
|
||||||
|
partial void OnMenuSelectedIndexChanged(int value)
|
||||||
|
{
|
||||||
|
// Если значение выходит за верхнюю границу списка элементов меню, то логгируем как ошибку
|
||||||
|
if (value >= MenuItems.Count())
|
||||||
|
_logger.LogError("Значение {}({}) больше количества элементов {}({})", nameof(MenuSelectedIndex), MenuSelectedIndex, nameof(MenuItems), MenuItems.Count());
|
||||||
|
// Если значение больше или равно 0, то значит выбран один из элементов меню
|
||||||
|
if (value >= 0 && value < MenuItems.Count())
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Выбран элемент из списка: {}", value);
|
||||||
|
// Находим запись в базе данных
|
||||||
|
var selectedRecord = _context.BrandRecords.Find(MenuItems[value].Id);
|
||||||
|
// Если запись найдена, то заполняем поля из базы данных
|
||||||
|
if (selectedRecord is not null)
|
||||||
|
{
|
||||||
|
SelectedId = selectedRecord.Id;
|
||||||
|
SelectedUuid = selectedRecord.Uuid;
|
||||||
|
SelectedBrandName = selectedRecord.BrandName;
|
||||||
|
SelectedMixtureName = selectedRecord.MixtureName;
|
||||||
|
SelectedMixtureNormalRate = selectedRecord.MixtureNormalRate;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Если значение не найдено в базе данных
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Логгируем как ошибку
|
||||||
|
_logger.LogError("Не удалось найти элемент с Id({}) в таблице {}", MenuItems[value].Id, nameof(_context.BrandRecords));
|
||||||
|
var nonExistingIndex = MenuSelectedIndex; // Сохраняем несуществующий индекс
|
||||||
|
// Устанавливаем, что запись не выбрана, этот метод вызовется повторно и заполнит поля пустыми значениями
|
||||||
|
MenuSelectedIndex = -1;
|
||||||
|
// Удаляем несуществующий элемент из списка
|
||||||
|
MenuItems.RemoveAt(nonExistingIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если элемент не выбран, заполняем поля пустыми значениями
|
||||||
|
_logger.LogTrace("Выбран новый элемент");
|
||||||
|
SelectedId = 0;
|
||||||
|
SelectedUuid = Guid.NewGuid().ToString();
|
||||||
|
SelectedBrandName = "";
|
||||||
|
SelectedMixtureName = "";
|
||||||
|
SelectedMixtureNormalRate = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вызывается при изменении <see cref="MenuOpened"/>
|
||||||
|
/// </summary>
|
||||||
|
partial void OnMenuOpenedChanged(bool value)
|
||||||
|
{
|
||||||
|
CanScroll = !value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Команды управления меню
|
||||||
|
/// <summary>
|
||||||
|
/// Открыть меню
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand] private void OpenMenu() => MenuOpened = true;
|
||||||
|
/// <summary>
|
||||||
|
/// Закрыть меню
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand] private void CloseMenu() => MenuOpened = false;
|
||||||
|
/// <summary>
|
||||||
|
/// Переключить видимость меню
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand] private void ToggleMenu() => MenuOpened = !MenuOpened;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создать новую запись
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand]
|
||||||
|
private void CreateRecord()
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Создание новой записи");
|
||||||
|
// Если уже создана новая запись, то MenuSelectedIndex может быть равен -1 и
|
||||||
|
// при простом присвоении MenuSelectedIndex = -1 событие OnMenuSelectedIndexChanged не вызовется,
|
||||||
|
// потому что событие срабатывает только при изменении значения, а значение было -1 и привилось ему -1,
|
||||||
|
// поэтому если SelectedRecord != -1, то нужно явно вызвать метод OnMenuSelectedIndexChanged
|
||||||
|
if (MenuSelectedIndex != -1)
|
||||||
|
MenuSelectedIndex = -1;
|
||||||
|
else
|
||||||
|
OnMenuSelectedIndexChanged(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удалить выбранную запись из базы данных или очистить значения, если запись не выбрана
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand]
|
||||||
|
private void DeleteRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Удаление записи: {}={}, {}={}, {}={}", nameof(BrandRecord.Id), SelectedId, nameof(BrandRecord.BrandName), SelectedBrandName, nameof(BrandRecord.MixtureName), SelectedMixtureName);
|
||||||
|
// Если запись не выбрана, то просто создаём новую запись
|
||||||
|
if (MenuSelectedIndex < 0)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Запись не выбрана, создаём новую");
|
||||||
|
CreateRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаём модель для экрана подтверждения
|
||||||
|
var confirmViewModel = new DeleteConfirmViewModel(_navigation)
|
||||||
|
{
|
||||||
|
Question = "Вы уверены, что хотите удалить запись?"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Создаём коллбек который вызовется при экрана подтверждения
|
||||||
|
void OnConfirmCloses(object? sender, bool result)
|
||||||
|
{
|
||||||
|
// Если пользователь отменил удаление, то выходим из коллбека
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Пользователь отменил удаление");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если запись не выбрана, то просто создаём новую запись
|
||||||
|
if (MenuSelectedIndex < 0)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Запись не выбрана, создаём новую");
|
||||||
|
CreateRecord();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем индекс удалённый записи и находим её в базе данных
|
||||||
|
var deletedMenuIndex = MenuSelectedIndex;
|
||||||
|
var deletedRecordId = SelectedId;
|
||||||
|
var deletedRecord = _context.BrandRecords.Find(deletedRecordId);
|
||||||
|
// Создаём новую запись
|
||||||
|
CreateRecord();
|
||||||
|
|
||||||
|
// Удаляем запись из списка
|
||||||
|
MenuItems.RemoveAt(deletedMenuIndex);
|
||||||
|
// Если удалённая запись не найдена в базе данных, то логгируем как ошибку
|
||||||
|
if (deletedRecord is null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Не удалось найти элемент с Id({}) в таблице {}", deletedRecordId, nameof(_context.BrandRecords));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаляем запись из базы данных и сохраняем изменения в базе данных
|
||||||
|
_context.BrandRecords.Remove(deletedRecord);
|
||||||
|
_context.SaveChanges();
|
||||||
|
_logger.LogTrace("Запись удалена");
|
||||||
|
|
||||||
|
confirmViewModel.Closes -= OnConfirmCloses; // Отписываемся от события закрытия экрана подтверждения
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаём View экрана подтверждения
|
||||||
|
var confirmView = _viewLocator.Build(confirmViewModel);
|
||||||
|
// Если View не найден, то логгируем как ошибку
|
||||||
|
if (confirmView is null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Не удалось найти View для экрана подтверждения");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogTrace("Задаём вопрос");
|
||||||
|
// Подписываемся на событие закрытия экрана подтверждения
|
||||||
|
confirmViewModel.Closes += OnConfirmCloses;
|
||||||
|
// Преходим на экран подтверждения, при закрытии он сам вернёт экран обратно на текущий
|
||||||
|
_navigation.NavigateTo(confirmView);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Исключение при удалении записи");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сохранить текущие значения в новую запись или перезаписать значения в выдранной записи
|
||||||
|
/// </summary>
|
||||||
|
[RelayCommand]
|
||||||
|
private void SaveRecord()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Сохранение записи: {}={}, {}={}, {}={}", nameof(BrandRecord.Id), SelectedId, nameof(BrandRecord.BrandName), SelectedBrandName, nameof(BrandRecord.MixtureName), SelectedMixtureName);
|
||||||
|
// Если запись не выбрана
|
||||||
|
if (MenuSelectedIndex < 0)
|
||||||
|
{
|
||||||
|
_logger.LogTrace("Создаём новую запись");
|
||||||
|
// Создаём новую запись
|
||||||
|
var newRecord = new BrandRecord(
|
||||||
|
uuid: SelectedUuid,
|
||||||
|
brandName: SelectedBrandName,
|
||||||
|
mixtureName: SelectedMixtureName,
|
||||||
|
mixtureNormalRate: SelectedMixtureNormalRate
|
||||||
|
);
|
||||||
|
|
||||||
|
// При добавляем запись в базу данных
|
||||||
|
var attachedRecord = _context.BrandRecords.Add(newRecord);
|
||||||
|
|
||||||
|
// Сохраняем изменения в базе данных
|
||||||
|
_context.SaveChanges();
|
||||||
|
_logger.LogTrace("Запись сохранена");
|
||||||
|
|
||||||
|
// Добавляем новый элемент в меню
|
||||||
|
MenuItems.Add(new MenuItemViewModel(attachedRecord.Entity.Id, attachedRecord.Entity.BrandName, attachedRecord.Entity.MixtureName));
|
||||||
|
// Выбираем последний элемент из меню
|
||||||
|
MenuSelectedIndex = MenuItems.Count() - 1;
|
||||||
|
}
|
||||||
|
// Если запись выбрана
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Находим запись в базе данных
|
||||||
|
var attachedRecord = _context.BrandRecords.Find(SelectedId);
|
||||||
|
// Если запись не найдена, то логгируем как ошибку
|
||||||
|
if (attachedRecord is null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Не удалось найти элемент с Id({}) в таблице {}", SelectedId, nameof(_context.BrandRecords));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogTrace("Записываем изменения в базу данных");
|
||||||
|
// Если в данных есть изменения, то записываем их
|
||||||
|
if (attachedRecord.BrandName != SelectedBrandName)
|
||||||
|
attachedRecord.BrandName = SelectedBrandName;
|
||||||
|
if (attachedRecord.MixtureName != SelectedMixtureName)
|
||||||
|
attachedRecord.MixtureName = SelectedMixtureName;
|
||||||
|
if (attachedRecord.MixtureNormalRate != SelectedMixtureNormalRate)
|
||||||
|
attachedRecord.MixtureNormalRate = SelectedMixtureNormalRate;
|
||||||
|
|
||||||
|
// Записываем изменения в меню
|
||||||
|
_logger.LogTrace("Записываем изменения в меню");
|
||||||
|
MenuItems[MenuSelectedIndex].BrandName = SelectedBrandName;
|
||||||
|
MenuItems[MenuSelectedIndex].MixtureName = SelectedMixtureName;
|
||||||
|
|
||||||
|
// Сохраняем изменения в базе данных
|
||||||
|
_context.SaveChanges();
|
||||||
|
_logger.LogTrace("Запись сохранена");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Исключение при сохранении записи");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,329 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="GSS2.Views.AmineContent.BrandCalibrationView"
|
||||||
|
xmlns:controls="using:GSS2.Controls"
|
||||||
|
xmlns:core="using:GSS2.UI.Core"
|
||||||
|
xmlns:i="using:Avalonia.Xaml.Interactivity"
|
||||||
|
xmlns:ia="using:Avalonia.Xaml.Interactions.Custom"
|
||||||
|
xmlns:lvc="using:LiveChartsCore.SkiaSharpView.Avalonia"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:vm="using:GSS2.ViewModels.AmineContent" x:DataType="vm:BrandCalibrationViewModel"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Grid Background="{StaticResource MainBackground}">
|
||||||
|
|
||||||
|
<!-- Основная форма -->
|
||||||
|
<Grid IsEnabled="{Binding !MenuOpened}">
|
||||||
|
|
||||||
|
<Grid.RowSpacing>5</Grid.RowSpacing>
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" /> <!-- Главная панель -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- Кнопки главной панели -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid.ColumnSpacing>5</Grid.ColumnSpacing>
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" /> <!-- Кнопка "Удалить" -->
|
||||||
|
<ColumnDefinition Width="*" /> <!-- Кнопка "Сохранить" -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- Главная панель -->
|
||||||
|
<Grid
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Grid.Row="0"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" /> <!-- Кнопка меню -->
|
||||||
|
<ColumnDefinition Width="*" /> <!-- Информация -->
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Grid.ColumnSpacing>5</Grid.ColumnSpacing>
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" /> <!-- Информация -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid.RowSpacing>5</Grid.RowSpacing>
|
||||||
|
|
||||||
|
<!-- Кнопка меню -->
|
||||||
|
<Button
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Classes="vertical"
|
||||||
|
Command="{Binding ToggleMenuCommand}"
|
||||||
|
>
|
||||||
|
<TextBlock Text="☰" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Информация -->
|
||||||
|
<Grid Grid.Column="1">
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Grid.ColumnSpacing>5</Grid.ColumnSpacing>
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" /> <!-- Id (подпись) | Uuid (подпись) -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- Id (поле ) | Uuid (поле ) -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- BrandName (подпись) | MixtureName (подпись) -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- BrandName (поле ) | MixtureName (поле ) -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- MixtureNormalRate (подпись) -->
|
||||||
|
<RowDefinition Height="Auto" /> <!-- MixtureNormalRate (поле ) -->
|
||||||
|
<RowDefinition Height="*" /> <!-- Пустое пространство -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid.RowSpacing>5</Grid.RowSpacing>
|
||||||
|
|
||||||
|
<!-- Id (подпись) -->
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Text="ИД:"
|
||||||
|
/>
|
||||||
|
<!-- Id (поле) -->
|
||||||
|
<TextBox
|
||||||
|
Classes="singleline"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
IsReadOnly="True"
|
||||||
|
PlaceholderText="ИД"
|
||||||
|
Text="{Binding SelectedId}"
|
||||||
|
/>
|
||||||
|
<!-- Uuid (подпись) -->
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="0"
|
||||||
|
Text="Уникальный ИД:"
|
||||||
|
/>
|
||||||
|
<!-- Uuid (поле) -->
|
||||||
|
<TextBox
|
||||||
|
Classes="singleline"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
IsReadOnly="True"
|
||||||
|
PlaceholderText="Уникальный ИД"
|
||||||
|
Text="{Binding SelectedUuid}"
|
||||||
|
/>
|
||||||
|
<!-- BrandName (подпись) -->
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="2"
|
||||||
|
Text="Марка продукта:"
|
||||||
|
/>
|
||||||
|
<!-- BrandName (поле) -->
|
||||||
|
<controls:TouchTextBox
|
||||||
|
Classes="singleline"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="3"
|
||||||
|
PlaceholderText="Марка продукта"
|
||||||
|
Text="{Binding SelectedBrandName}"
|
||||||
|
/>
|
||||||
|
<!-- MixtureName (подпись) -->
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="2"
|
||||||
|
Text="Марка смеси:"
|
||||||
|
/>
|
||||||
|
<!-- MixtureName (поле) -->
|
||||||
|
<controls:TouchTextBox
|
||||||
|
Classes="singleline"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="3"
|
||||||
|
PlaceholderText="Марка смеси"
|
||||||
|
Text="{Binding SelectedMixtureName}"
|
||||||
|
/>
|
||||||
|
<!-- MixtureNormalRate (подпись) -->
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini" Text="Норма расхода смеси (кг/т | гр/кг):"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Grid.Row="4"
|
||||||
|
/>
|
||||||
|
<!-- MixtureNormalRate (поле) -->
|
||||||
|
<controls:TouchNumericUpDown
|
||||||
|
Classes="singleline"
|
||||||
|
FormatString="0.0000"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Grid.Row="5"
|
||||||
|
Increment="0.0001"
|
||||||
|
PlaceholderText="Норма расхода смеси (кг/т | гр/кг)"
|
||||||
|
Value="{Binding SelectedMixtureNormalRate}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Кнопки главной панели -->
|
||||||
|
<!-- Кнопка "Удалить" -->
|
||||||
|
<Button
|
||||||
|
Classes="danger"
|
||||||
|
Command="{Binding DeleteRecordCommand}"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
>
|
||||||
|
<TextBlock Text="Удалить" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Кнопка "Сохранить" -->
|
||||||
|
<Button
|
||||||
|
Command="{Binding SaveRecordCommand}"
|
||||||
|
Content="Сохранить"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.Row="1"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
>
|
||||||
|
<TextBlock Text="Сохранить" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Полупрозрачный оверлей -->
|
||||||
|
<Border
|
||||||
|
Background="{StaticResource Overlay}"
|
||||||
|
IsEnabled="{Binding MenuOpened}"
|
||||||
|
IsVisible="{Binding MenuOpened}"
|
||||||
|
>
|
||||||
|
<Interaction.Behaviors>
|
||||||
|
<TappedTrigger>
|
||||||
|
<InvokeCommandAction Command="{Binding CloseMenuCommand}" />
|
||||||
|
</TappedTrigger>
|
||||||
|
</Interaction.Behaviors>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Выезжающая боковая панель -->
|
||||||
|
<Border
|
||||||
|
Background="{StaticResource MenuBackground}"
|
||||||
|
BorderBrush="{StaticResource MenuBorder}"
|
||||||
|
BorderThickness="0,0,1,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
IsEnabled="{Binding MenuOpened}"
|
||||||
|
IsVisible="{Binding MenuOpened}"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- Переходы -->
|
||||||
|
<Border.Transitions>
|
||||||
|
<Transitions>
|
||||||
|
<TransformOperationsTransition Duration="0:0:0.25" Property="RenderTransform" />
|
||||||
|
</Transitions>
|
||||||
|
</Border.Transitions>
|
||||||
|
|
||||||
|
<!-- Поведения -->
|
||||||
|
<Interaction.Behaviors>
|
||||||
|
|
||||||
|
<!-- Поведение при открытии меню -->
|
||||||
|
<DataTriggerBehavior
|
||||||
|
Binding="{Binding MenuOpened}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="True"
|
||||||
|
>
|
||||||
|
<ChangePropertyAction PropertyName="RenderTransform" Value="translateX(0px)" />
|
||||||
|
</DataTriggerBehavior>
|
||||||
|
|
||||||
|
<!-- Поведение при закрытии меню -->
|
||||||
|
<DataTriggerBehavior
|
||||||
|
Binding="{Binding MenuOpened}"
|
||||||
|
ComparisonCondition="Equal"
|
||||||
|
Value="False"
|
||||||
|
>
|
||||||
|
<ChangePropertyAction PropertyName="RenderTransform" Value="translateX(-320px)" />
|
||||||
|
</DataTriggerBehavior>
|
||||||
|
|
||||||
|
</Interaction.Behaviors>
|
||||||
|
|
||||||
|
<!-- Содержимое меню -->
|
||||||
|
<Grid Margin="10">
|
||||||
|
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" /> <!-- Кнопка "Новая запись" -->
|
||||||
|
<RowDefinition Height="*" /> <!-- Элементы меню -->
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid.RowSpacing>10</Grid.RowSpacing>
|
||||||
|
|
||||||
|
<!-- Кнопка "Новая запись" -->
|
||||||
|
<Button
|
||||||
|
Command="{Binding CreateRecordCommand}"
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
MinWidth="200"
|
||||||
|
>
|
||||||
|
<TextBlock Text="Новая запись" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<!-- Элементы меню -->
|
||||||
|
<ListBox
|
||||||
|
Background="{StaticResource MenuBackground}"
|
||||||
|
Grid.Row="1"
|
||||||
|
ItemsSource="{Binding MenuItems}"
|
||||||
|
SelectedIndex="{Binding MenuSelectedIndex}"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- Шаблон списка элементов -->
|
||||||
|
<ListBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListBox.ItemsPanel>
|
||||||
|
|
||||||
|
<!-- Стили элементов -->
|
||||||
|
<ListBox.Styles>
|
||||||
|
|
||||||
|
<!-- Общий стиль -->
|
||||||
|
<Style Selector="ListBoxItem">
|
||||||
|
<Setter Property="Background" Value="{StaticResource ButtonBackground}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Стиль выбранного элемента -->
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{StaticResource MainBackground}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Стиль элемента над которым находится указатель -->
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background" Value="{StaticResource MainBackground}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
</ListBox.Styles>
|
||||||
|
|
||||||
|
<!-- Шаблон элемента -->
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border Margin="3" CornerRadius="5">
|
||||||
|
<TextBlock
|
||||||
|
Classes="mini"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
>
|
||||||
|
<Run Text="{Binding Id, StringFormat='[{0}] '}" />
|
||||||
|
<Run Text="{Binding BrandName}" />
|
||||||
|
<Run Text=" - " />
|
||||||
|
<Run Text="{Binding MixtureName}" />
|
||||||
|
</TextBlock>
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
|
||||||
|
</ListBox>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace GSS2.Views.AmineContent;
|
||||||
|
|
||||||
|
public partial class BrandCalibrationView : UserControl
|
||||||
|
{
|
||||||
|
public BrandCalibrationView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user