Files
XLAB/XLAB2/EkzDirectoryWindowViewModel.cs
Курнат Андрей 74d793948e edit
2026-03-23 21:24:09 +03:00

569 lines
18 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
namespace XLAB2
{
internal sealed class EkzDirectoryWindowViewModel : ObservableObject
{
private readonly IEkzDirectoryDialogService _dialogService;
private readonly EkzDirectoryService _service;
private List<EkzDirectoryItem> _ekzCache;
private bool _isApplyingFilter;
private bool _isBusy;
private string _searchText;
private EkzDirectoryItem _selectedEkz;
private int _selectedOwnerFilterId;
private string _statusText;
public EkzDirectoryWindowViewModel(EkzDirectoryService service, IEkzDirectoryDialogService dialogService)
{
_service = service;
_dialogService = dialogService;
_ekzCache = new List<EkzDirectoryItem>();
EkzItems = new ObservableCollection<EkzDirectoryItem>();
EkzMkItems = new ObservableCollection<EkzMkDirectoryItem>();
OwnerFilterItems = new ObservableCollection<DirectoryLookupItem>();
OwnerFilterItems.Add(new DirectoryLookupItem { Id = 0, Name = "Все организации" });
AddEkzCommand = new RelayCommand(delegate { AddEkzAsync(); }, delegate { return !IsBusy; });
EditEkzCommand = new RelayCommand(delegate { EditEkzAsync(); }, delegate { return !IsBusy && SelectedEkz != null; });
DeleteEkzCommand = new RelayCommand(delegate { DeleteEkzWithPreviewAsync(); }, delegate { return !IsBusy && SelectedEkz != null; });
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
UpdateStatus();
}
public ICommand AddEkzCommand { get; private set; }
public ICommand DeleteEkzCommand { get; private set; }
public ICommand EditEkzCommand { get; private set; }
public ObservableCollection<EkzDirectoryItem> EkzItems { get; private set; }
public ObservableCollection<EkzMkDirectoryItem> EkzMkItems { get; private set; }
public bool IsBusy
{
get { return _isBusy; }
private set
{
if (SetProperty(ref _isBusy, value))
{
RaiseCommandStates();
}
}
}
public ObservableCollection<DirectoryLookupItem> OwnerFilterItems { get; private set; }
public ICommand RefreshCommand { get; private set; }
public string SearchText
{
get { return _searchText; }
set
{
if (SetProperty(ref _searchText, value))
{
ApplyFilter(SelectedEkz == null ? (int?)null : SelectedEkz.Id);
}
}
}
public EkzDirectoryItem SelectedEkz
{
get { return _selectedEkz; }
set
{
if (SetProperty(ref _selectedEkz, value))
{
RaiseCommandStates();
if (!_isApplyingFilter)
{
LoadEkzMkForSelection();
}
UpdateStatus();
}
}
}
public int SelectedOwnerFilterId
{
get { return _selectedOwnerFilterId; }
set
{
if (SetProperty(ref _selectedOwnerFilterId, value))
{
ApplyFilter(SelectedEkz == null ? (int?)null : SelectedEkz.Id);
}
}
}
public string StatusText
{
get { return _statusText; }
private set { SetProperty(ref _statusText, value); }
}
public async Task InitializeAsync()
{
await ExecuteBusyOperationAsync(delegate { return RefreshCoreAsync(null); });
}
private void AddEkzAsync()
{
var result = _dialogService.ShowEkzEditDialog(new EkzDirectoryItem(), true, _ekzCache.ToList(), _service);
if (result == null)
{
return;
}
RunMutationOperation(async delegate
{
var createdId = await Task.Run(delegate { return _service.AddEkzItem(result); });
await RefreshCoreAsync(createdId);
_dialogService.ShowInfo("Запись EKZ добавлена.");
});
}
private void ApplyFilter(int? preferredId)
{
var filteredItems = _ekzCache.Where(delegate(EkzDirectoryItem item)
{
return MatchesOwnerFilter(item) && MatchesSearch(item);
}).ToList();
_isApplyingFilter = true;
try
{
EkzItems.Clear();
foreach (var item in filteredItems)
{
EkzItems.Add(item);
}
SelectedEkz = preferredId.HasValue
? EkzItems.FirstOrDefault(delegate(EkzDirectoryItem item) { return item.Id == preferredId.Value; })
: EkzItems.FirstOrDefault();
}
finally
{
_isApplyingFilter = false;
}
if (!IsBusy)
{
LoadEkzMkForSelection();
}
UpdateStatus();
}
private static EkzDirectoryItem CloneEkz(EkzDirectoryItem source)
{
return new EkzDirectoryItem
{
Id = source.Id,
TypeSizeId = source.TypeSizeId,
MeasurementAreaName = source.MeasurementAreaName,
InstrumentName = source.InstrumentName,
TypeName = source.TypeName,
RangeText = source.RangeText,
AccuracyText = source.AccuracyText,
RegistryNumber = source.RegistryNumber,
OwnerOrganizationId = source.OwnerOrganizationId,
OwnerOrganizationName = source.OwnerOrganizationName,
SerialNumber = source.SerialNumber,
InventoryNumber = source.InventoryNumber,
StickerNumbers = source.StickerNumbers,
Notes = source.Notes
};
}
private async void DeleteEkzWithPreviewAsync()
{
if (SelectedEkz == null)
{
return;
}
var selected = SelectedEkz;
EkzDeletePreview preview;
try
{
IsBusy = true;
preview = await Task.Run(delegate { return _service.GetEkzDeletePreview(selected.Id); });
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
return;
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
return;
}
finally
{
IsBusy = false;
}
if (preview == null)
{
return;
}
if (!preview.CanDelete)
{
_dialogService.ShowWarning(preview.WarningMessage);
return;
}
if (!_dialogService.Confirm(BuildDeleteConfirmationMessage(selected, preview)))
{
return;
}
RunMutationOperation(async delegate
{
var result = await Task.Run(delegate { return _service.DeleteEkzItem(selected.Id); });
if (!result.IsDeleted)
{
_dialogService.ShowWarning(result.WarningMessage);
return;
}
await RefreshCoreAsync(null);
_dialogService.ShowInfo(BuildDeleteResultMessage(result));
});
}
private async void DeleteEkzAsync()
{
if (SelectedEkz == null)
{
return;
}
var selected = SelectedEkz;
EkzDeletePreview preview;
try
{
IsBusy = true;
preview = await Task.Run(delegate { return _service.GetEkzDeletePreview(selected.Id); });
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
return;
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
return;
}
finally
{
IsBusy = false;
}
if (preview == null)
{
return;
}
if (!preview.CanDelete)
{
_dialogService.ShowWarning(preview.WarningMessage);
return;
}
if (!_dialogService.Confirm(string.Format("Удалить экземпляр \"{0}\"?", selected.SerialNumber)))
{
return;
}
RunMutationOperation(async delegate
{
var result = await Task.Run(delegate { return _service.DeleteEkzItem(selected.Id); });
if (!result.IsDeleted)
{
_dialogService.ShowWarning(result.WarningMessage);
return;
}
await RefreshCoreAsync(null);
_dialogService.ShowInfo("Запись EKZ удалена.");
});
}
private void EditEkzAsync()
{
if (SelectedEkz == null)
{
return;
}
var result = _dialogService.ShowEkzEditDialog(CloneEkz(SelectedEkz), false, _ekzCache.ToList(), _service);
if (result == null)
{
return;
}
RunMutationOperation(async delegate
{
await Task.Run(delegate { _service.UpdateEkzItem(result); });
await RefreshCoreAsync(result.Id);
_dialogService.ShowInfo("Запись EKZ обновлена.");
});
}
private async Task ExecuteBusyOperationAsync(Func<Task> operation)
{
try
{
IsBusy = true;
await operation();
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
}
finally
{
IsBusy = false;
}
}
private async Task ExecuteMutationOperationAsync(Func<Task> operation)
{
try
{
IsBusy = true;
await operation();
}
catch (InvalidOperationException ex)
{
_dialogService.ShowWarning(ex.Message);
}
catch (Exception ex)
{
_dialogService.ShowError(ex.Message);
}
finally
{
IsBusy = false;
}
}
private string[] GetSearchTokens()
{
return (SearchText ?? string.Empty)
.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select(delegate(string token) { return token.Trim().ToUpperInvariant(); })
.Where(delegate(string token) { return token.Length > 0; })
.ToArray();
}
private void LoadEkzMkForSelection()
{
if (IsBusy)
{
return;
}
RunBusyOperation(async delegate
{
if (SelectedEkz == null)
{
EkzMkItems.Clear();
UpdateStatus();
return;
}
await RefreshEkzMkCoreAsync(SelectedEkz.Id);
});
}
private bool MatchesOwnerFilter(EkzDirectoryItem item)
{
return SelectedOwnerFilterId <= 0
|| (item != null && item.OwnerOrganizationId == SelectedOwnerFilterId);
}
private bool MatchesSearch(EkzDirectoryItem item)
{
var tokens = GetSearchTokens();
if (tokens.Length == 0)
{
return true;
}
var haystack = string.Join(
" ",
new[]
{
item == null ? null : item.Id.ToString(),
item == null ? null : item.OwnerOrganizationName,
item == null ? null : item.MeasurementAreaName,
item == null ? null : item.InstrumentName,
item == null ? null : item.TypeName,
item == null ? null : item.RangeText,
item == null ? null : item.AccuracyText,
item == null ? null : item.RegistryNumber,
item == null ? null : item.SerialNumber,
item == null ? null : item.InventoryNumber,
item == null ? null : item.StickerNumbers,
item == null ? null : item.Notes
}.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); }))
.ToUpperInvariant();
return tokens.All(delegate(string token) { return haystack.IndexOf(token, StringComparison.Ordinal) >= 0; });
}
private async Task RefreshCoreAsync(int? idToSelect)
{
var currentSelectedId = idToSelect ?? (SelectedEkz == null ? (int?)null : SelectedEkz.Id);
var currentOwnerFilterId = SelectedOwnerFilterId;
var ekzTask = Task.Run(delegate { return _service.LoadEkzItems(); });
var ownerTask = Task.Run(delegate { return _service.LoadFrpdReferences(); });
await Task.WhenAll(ekzTask, ownerTask);
_ekzCache = ekzTask.Result.ToList();
RebuildOwnerFilters(ownerTask.Result, currentOwnerFilterId);
ApplyFilter(currentSelectedId);
if (SelectedEkz == null)
{
EkzMkItems.Clear();
UpdateStatus();
return;
}
await RefreshEkzMkCoreAsync(SelectedEkz.Id);
UpdateStatus();
}
private async Task RefreshEkzMkCoreAsync(int instrumentId)
{
var items = await Task.Run(delegate { return _service.LoadEkzMkItems(instrumentId); });
EkzMkItems.Clear();
foreach (var item in items)
{
EkzMkItems.Add(item);
}
}
private void RebuildOwnerFilters(IReadOnlyList<DirectoryLookupItem> owners, int selectedId)
{
OwnerFilterItems.Clear();
OwnerFilterItems.Add(new DirectoryLookupItem { Id = 0, Name = "Все организации" });
foreach (var owner in owners ?? Array.Empty<DirectoryLookupItem>())
{
OwnerFilterItems.Add(owner);
}
_selectedOwnerFilterId = OwnerFilterItems.Any(delegate(DirectoryLookupItem item) { return item.Id == selectedId; })
? selectedId
: 0;
OnPropertyChanged("SelectedOwnerFilterId");
}
private void RefreshAsync()
{
RunBusyOperation(delegate { return RefreshCoreAsync(SelectedEkz == null ? (int?)null : SelectedEkz.Id); });
}
private void RaiseCommandStates()
{
((RelayCommand)AddEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)EditEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteEkzCommand).RaiseCanExecuteChanged();
((RelayCommand)RefreshCommand).RaiseCanExecuteChanged();
}
private async void RunBusyOperation(Func<Task> operation)
{
try
{
await ExecuteBusyOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private async void RunMutationOperation(Func<Task> operation)
{
try
{
await ExecuteMutationOperationAsync(operation);
}
catch (Exception ex)
{
IsBusy = false;
_dialogService.ShowError(ex.Message);
}
}
private static string BuildDeleteConfirmationMessage(EkzDirectoryItem selected, EkzDeletePreview preview)
{
return string.Format(
"Удалить экземпляр \"{0}\"?{1}{1}{2}",
selected == null || string.IsNullOrWhiteSpace(selected.SerialNumber) ? "(без номера)" : selected.SerialNumber,
Environment.NewLine,
preview == null ? string.Empty : preview.ConfirmationMessage ?? string.Empty);
}
private static string BuildDeleteResultMessage(EkzDeleteResult result)
{
var impacts = result == null || result.ImpactItems == null
? new List<EkzDeleteImpactItem>()
: result.ImpactItems.Where(delegate(EkzDeleteImpactItem item) { return item != null && item.RowCount > 0; }).ToList();
if (impacts.Count == 0)
{
return "Запись EKZ удалена.";
}
return "Удалены записи: " + string.Join(", ", impacts.Select(delegate(EkzDeleteImpactItem item)
{
return string.Format("{0}: {1}", item.TableName, item.RowCount);
})) + ".";
}
private void UpdateStatus()
{
var searchPrefix = string.IsNullOrWhiteSpace(SearchText)
? string.Empty
: string.Format("Поиск: \"{0}\". ", SearchText.Trim());
var ownerName = OwnerFilterItems.FirstOrDefault(delegate(DirectoryLookupItem item) { return item.Id == SelectedOwnerFilterId; });
var ownerPrefix = SelectedOwnerFilterId <= 0 || ownerName == null
? string.Empty
: string.Format("Владелец: \"{0}\". ", ownerName.Name);
StatusText = string.Format(
"{0}{1}EKZ: {2}/{3}. EKZMK: {4}.",
searchPrefix,
ownerPrefix,
EkzItems.Count,
_ekzCache.Count,
EkzMkItems.Count);
}
}
}