edit
This commit is contained in:
566
XLAB2/EkzDirectoryWindowViewModel.cs
Normal file
566
XLAB2/EkzDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,566 @@
|
||||
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,
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user