edit
This commit is contained in:
@@ -13,6 +13,8 @@ namespace XLAB
|
||||
|
||||
IReadOnlyList<string> ShowCloneVerificationDialog(CloneVerificationSeed seed);
|
||||
|
||||
SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems);
|
||||
|
||||
VerificationEditResult ShowVerificationDialog(
|
||||
VerificationEditSeed seed,
|
||||
IReadOnlyList<PersonReference> verifiers,
|
||||
@@ -76,6 +78,16 @@ namespace XLAB
|
||||
return result.HasValue && result.Value ? viewModel.GetSerialNumbers() : null;
|
||||
}
|
||||
|
||||
public SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems)
|
||||
{
|
||||
var viewModel = new SpnmtpEditWindowViewModel(seed, isNew, existingItems);
|
||||
var window = new SpnmtpEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public VerificationEditResult ShowVerificationDialog(
|
||||
VerificationEditSeed seed,
|
||||
IReadOnlyList<PersonReference> verifiers,
|
||||
|
||||
@@ -9,13 +9,27 @@
|
||||
WindowState="Maximized"
|
||||
Loaded="Window_Loaded">
|
||||
<Grid Margin="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="430" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Grid.Column="0" Header="Документы">
|
||||
<Menu Grid.Row="0"
|
||||
Margin="0,0,0,12">
|
||||
<MenuItem Header="Справочники">
|
||||
<MenuItem Header="Наименования типов СИ"
|
||||
Click="SpnmtpDirectoryMenuItem_Click" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="430" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<GroupBox Grid.Column="0" Header="Документы">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -322,4 +336,5 @@
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -45,6 +45,13 @@ namespace XLAB
|
||||
}
|
||||
}
|
||||
|
||||
private void SpnmtpDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = new SpnmtpDirectoryWindow();
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
|
||||
@@ -146,6 +146,153 @@ ORDER BY fr.NMFRD, v.IDVDODVDD;";
|
||||
return forms;
|
||||
}
|
||||
|
||||
public IReadOnlyList<SpnmtpDirectoryItem> LoadSpnmtpItems()
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT
|
||||
s.IDSPNMTP AS Id,
|
||||
s.NMTP AS Name,
|
||||
s.NMTPSP AS SpecialName
|
||||
FROM dbo.SPNMTP s
|
||||
ORDER BY s.NMTP, s.IDSPNMTP;";
|
||||
|
||||
var items = new List<SpnmtpDirectoryItem>();
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
command.CommandTimeout = 60;
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
items.Add(new SpnmtpDirectoryItem
|
||||
{
|
||||
Id = GetInt32(reader, "Id"),
|
||||
Name = GetString(reader, "Name"),
|
||||
SpecialName = GetString(reader, "SpecialName")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public int AddSpnmtpItem(SpnmtpDirectoryItem item)
|
||||
{
|
||||
var normalizedItem = NormalizeSpnmtpItem(item);
|
||||
|
||||
const string sql = @"
|
||||
INSERT INTO dbo.SPNMTP
|
||||
(
|
||||
NMTP,
|
||||
NMTPSP
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@Name,
|
||||
@SpecialName
|
||||
);
|
||||
|
||||
SELECT CAST(SCOPE_IDENTITY() AS int);";
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
EnsureSpnmtpNameIsUnique(connection, normalizedItem.Name, null);
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
|
||||
command.Parameters.Add("@SpecialName", SqlDbType.VarChar, SpnmtpDirectoryRules.SpecialNameMaxLength).Value = (object)normalizedItem.SpecialName ?? DBNull.Value;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(command.ExecuteScalar());
|
||||
}
|
||||
catch (SqlException ex) when (IsSpnmtpDuplicateNameViolation(ex))
|
||||
{
|
||||
throw CreateSpnmtpDuplicateNameException(normalizedItem.Name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSpnmtpItem(SpnmtpDirectoryItem item)
|
||||
{
|
||||
var normalizedItem = NormalizeSpnmtpItem(item);
|
||||
if (normalizedItem.Id <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Не выбрана запись SPNMTP для изменения.");
|
||||
}
|
||||
|
||||
const string sql = @"
|
||||
UPDATE dbo.SPNMTP
|
||||
SET NMTP = @Name,
|
||||
NMTPSP = @SpecialName
|
||||
WHERE IDSPNMTP = @Id;
|
||||
|
||||
SELECT @@ROWCOUNT;";
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
EnsureSpnmtpNameIsUnique(connection, normalizedItem.Name, normalizedItem.Id);
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id;
|
||||
command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
|
||||
command.Parameters.Add("@SpecialName", SqlDbType.VarChar, SpnmtpDirectoryRules.SpecialNameMaxLength).Value = (object)normalizedItem.SpecialName ?? DBNull.Value;
|
||||
|
||||
try
|
||||
{
|
||||
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Запись SPNMTP для изменения не найдена.");
|
||||
}
|
||||
}
|
||||
catch (SqlException ex) when (IsSpnmtpDuplicateNameViolation(ex))
|
||||
{
|
||||
throw CreateSpnmtpDuplicateNameException(normalizedItem.Name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteSpnmtpItem(int id)
|
||||
{
|
||||
if (id <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Не выбрана запись SPNMTP для удаления.");
|
||||
}
|
||||
|
||||
const string sql = @"
|
||||
DELETE FROM dbo.SPNMTP
|
||||
WHERE IDSPNMTP = @Id;
|
||||
|
||||
SELECT @@ROWCOUNT;";
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
|
||||
|
||||
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Запись SPNMTP для удаления не найдена.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SqlException ex) when (ex.Number == 547)
|
||||
{
|
||||
throw new InvalidOperationException("Запись справочника используется в связанных данных и не может быть удалена.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<PsvDocumentSummary> LoadDocuments()
|
||||
{
|
||||
const string sql = @"
|
||||
@@ -2136,6 +2283,99 @@ WHERE z.IDEKZ = @InstrumentId
|
||||
return value.Trim();
|
||||
}
|
||||
|
||||
private static SpnmtpDirectoryItem NormalizeSpnmtpItem(SpnmtpDirectoryItem item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException("item");
|
||||
}
|
||||
|
||||
var name = NormalizeRequiredSpnmtpValue(
|
||||
item.Name,
|
||||
"Наименование типа СИ не заполнено.",
|
||||
SpnmtpDirectoryRules.NameMaxLength,
|
||||
"Наименование типа СИ превышает допустимую длину.");
|
||||
var specialName = NormalizeOptionalSpnmtpValue(
|
||||
item.SpecialName,
|
||||
SpnmtpDirectoryRules.SpecialNameMaxLength,
|
||||
"Специальное наименование типа превышает допустимую длину.");
|
||||
|
||||
return new SpnmtpDirectoryItem
|
||||
{
|
||||
Id = item.Id,
|
||||
Name = name,
|
||||
SpecialName = specialName
|
||||
};
|
||||
}
|
||||
|
||||
private static void EnsureSpnmtpNameIsUnique(SqlConnection connection, string name, int? excludeId)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT TOP (1) IDSPNMTP
|
||||
FROM dbo.SPNMTP
|
||||
WHERE NMTP = @Name
|
||||
AND (@ExcludeId IS NULL OR IDSPNMTP <> @ExcludeId);";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = name;
|
||||
command.Parameters.Add("@ExcludeId", SqlDbType.Int).Value = (object)excludeId ?? DBNull.Value;
|
||||
|
||||
var existingId = command.ExecuteScalar();
|
||||
if (existingId != null && existingId != DBNull.Value)
|
||||
{
|
||||
throw CreateSpnmtpDuplicateNameException(name, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static InvalidOperationException CreateSpnmtpDuplicateNameException(string name, Exception innerException)
|
||||
{
|
||||
return new InvalidOperationException(
|
||||
string.Format("Наименование типа СИ \"{0}\" уже существует в справочнике.", name),
|
||||
innerException);
|
||||
}
|
||||
|
||||
private static bool IsSpnmtpDuplicateNameViolation(SqlException ex)
|
||||
{
|
||||
return ex != null
|
||||
&& (ex.Number == 2601 || ex.Number == 2627)
|
||||
&& ex.Message.IndexOf("XAK1SPNMTP", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static string NormalizeRequiredSpnmtpValue(string value, string emptyErrorMessage, int maxLength, string tooLongErrorMessage)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new InvalidOperationException(emptyErrorMessage);
|
||||
}
|
||||
|
||||
var normalizedValue = value.Trim();
|
||||
if (normalizedValue.Length > maxLength)
|
||||
{
|
||||
throw new InvalidOperationException(tooLongErrorMessage);
|
||||
}
|
||||
|
||||
return normalizedValue;
|
||||
}
|
||||
|
||||
private static string NormalizeOptionalSpnmtpValue(string value, int maxLength, string tooLongErrorMessage)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var normalizedValue = value.Trim();
|
||||
if (normalizedValue.Length > maxLength)
|
||||
{
|
||||
throw new InvalidOperationException(tooLongErrorMessage);
|
||||
}
|
||||
|
||||
return normalizedValue;
|
||||
}
|
||||
|
||||
private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document)
|
||||
{
|
||||
const string sql = @"
|
||||
|
||||
@@ -344,6 +344,22 @@ namespace XLAB
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SpnmtpDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string SpecialName { get; set; }
|
||||
}
|
||||
|
||||
internal static class SpnmtpDirectoryRules
|
||||
{
|
||||
public const int NameMaxLength = 150;
|
||||
|
||||
public const int SpecialNameMaxLength = 150;
|
||||
}
|
||||
|
||||
public sealed class DocumentFormReference
|
||||
{
|
||||
public int DocumentFormId { get; set; }
|
||||
|
||||
86
XLAB/SpnmtpDirectoryWindow.xaml
Normal file
86
XLAB/SpnmtpDirectoryWindow.xaml
Normal file
@@ -0,0 +1,86 @@
|
||||
<Window x:Class="XLAB.SpnmtpDirectoryWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Наименования типов СИ"
|
||||
Height="680"
|
||||
Width="980"
|
||||
MinHeight="520"
|
||||
MinWidth="820"
|
||||
Loaded="Window_Loaded"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<DockPanel Grid.Row="0"
|
||||
Margin="0,0,0,8">
|
||||
<StackPanel DockPanel.Dock="Left"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Width="170"
|
||||
VerticalAlignment="Center"
|
||||
Text="Поиск по справочнику" />
|
||||
<TextBox Width="320"
|
||||
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Right"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="110"
|
||||
Margin="8,0,0,0"
|
||||
Command="{Binding RefreshCommand}"
|
||||
Content="Обновить" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<DataGrid Grid.Row="1"
|
||||
ItemsSource="{Binding ItemsView}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID"
|
||||
Width="90"
|
||||
Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Наименование типа СИ"
|
||||
Width="*"
|
||||
Binding="{Binding Name}" />
|
||||
<DataGridTextColumn Header="Специальное наименование типа"
|
||||
Width="260"
|
||||
Binding="{Binding SpecialName}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TextBlock Grid.Row="2"
|
||||
Margin="0,8,0,0"
|
||||
Foreground="DimGray"
|
||||
Text="{Binding StatusText}" />
|
||||
|
||||
<StackPanel Grid.Row="3"
|
||||
Margin="0,12,0,0"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="110"
|
||||
Margin="0,0,8,0"
|
||||
Command="{Binding AddCommand}"
|
||||
Content="Добавить" />
|
||||
<Button Width="110"
|
||||
Margin="0,0,8,0"
|
||||
Command="{Binding EditCommand}"
|
||||
Content="Изменить" />
|
||||
<Button Width="110"
|
||||
Margin="0,0,8,0"
|
||||
Command="{Binding DeleteCommand}"
|
||||
Content="Удалить" />
|
||||
<Button Width="90"
|
||||
IsCancel="True"
|
||||
Content="Закрыть" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
21
XLAB/SpnmtpDirectoryWindow.xaml.cs
Normal file
21
XLAB/SpnmtpDirectoryWindow.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class SpnmtpDirectoryWindow : Window
|
||||
{
|
||||
private readonly SpnmtpDirectoryWindowViewModel _viewModel;
|
||||
|
||||
public SpnmtpDirectoryWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = new SpnmtpDirectoryWindowViewModel(new PsvDataService(), new DialogService(this));
|
||||
DataContext = _viewModel;
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
272
XLAB/SpnmtpDirectoryWindowViewModel.cs
Normal file
272
XLAB/SpnmtpDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,272 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class SpnmtpDirectoryWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly PsvDataService _service;
|
||||
private bool _isBusy;
|
||||
private string _searchText;
|
||||
private SpnmtpDirectoryItem _selectedItem;
|
||||
private string _statusText;
|
||||
|
||||
public SpnmtpDirectoryWindowViewModel(PsvDataService service, IDialogService dialogService)
|
||||
{
|
||||
_service = service;
|
||||
_dialogService = dialogService;
|
||||
|
||||
Items = new ObservableCollection<SpnmtpDirectoryItem>();
|
||||
ItemsView = CollectionViewSource.GetDefaultView(Items);
|
||||
ItemsView.Filter = FilterItems;
|
||||
|
||||
AddCommand = new RelayCommand(delegate { AddItemAsync(); }, delegate { return !IsBusy; });
|
||||
DeleteCommand = new RelayCommand(delegate { DeleteSelectedItemAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
|
||||
EditCommand = new RelayCommand(delegate { EditSelectedItemAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
|
||||
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
|
||||
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
public ICommand AddCommand { get; private set; }
|
||||
|
||||
public ICommand DeleteCommand { get; private set; }
|
||||
|
||||
public ICommand EditCommand { get; private set; }
|
||||
|
||||
public ObservableCollection<SpnmtpDirectoryItem> Items { get; private set; }
|
||||
|
||||
public ICollectionView ItemsView { get; private set; }
|
||||
|
||||
public bool IsBusy
|
||||
{
|
||||
get { return _isBusy; }
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _isBusy, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand RefreshCommand { get; private set; }
|
||||
|
||||
public string SearchText
|
||||
{
|
||||
get { return _searchText; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchText, value))
|
||||
{
|
||||
ItemsView.Refresh();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SpnmtpDirectoryItem SelectedItem
|
||||
{
|
||||
get { return _selectedItem; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedItem, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string StatusText
|
||||
{
|
||||
get { return _statusText; }
|
||||
private set { SetProperty(ref _statusText, value); }
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
await ExecuteBusyOperationAsync(delegate { return RefreshCoreAsync(null); });
|
||||
}
|
||||
|
||||
private void AddItemAsync()
|
||||
{
|
||||
var result = _dialogService.ShowSpnmtpEditDialog(new SpnmtpDirectoryItem(), true, Items.ToList());
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddSpnmtpItem(result); });
|
||||
await RefreshCoreAsync(createdId);
|
||||
_dialogService.ShowInfo("Запись справочника добавлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private bool Contains(string source, string searchText)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(source)
|
||||
&& source.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private void DeleteSelectedItemAsync()
|
||||
{
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedItem = SelectedItem;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить запись \"{0}\"?", selectedItem.Name)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.DeleteSpnmtpItem(selectedItem.Id); });
|
||||
await RefreshCoreAsync(null);
|
||||
_dialogService.ShowInfo("Запись справочника удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditSelectedItemAsync()
|
||||
{
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var seed = new SpnmtpDirectoryItem
|
||||
{
|
||||
Id = SelectedItem.Id,
|
||||
Name = SelectedItem.Name,
|
||||
SpecialName = SelectedItem.SpecialName
|
||||
};
|
||||
|
||||
var result = _dialogService.ShowSpnmtpEditDialog(seed, false, Items.ToList());
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateSpnmtpItem(result); });
|
||||
await RefreshCoreAsync(result.Id);
|
||||
_dialogService.ShowInfo("Запись справочника обновлена.");
|
||||
});
|
||||
}
|
||||
|
||||
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 bool FilterItems(object item)
|
||||
{
|
||||
var directoryItem = item as SpnmtpDirectoryItem;
|
||||
if (directoryItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(SearchText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Contains(directoryItem.Name, SearchText)
|
||||
|| Contains(directoryItem.SpecialName, SearchText)
|
||||
|| directoryItem.Id.ToString().IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private async Task RefreshCoreAsync(int? idToSelect)
|
||||
{
|
||||
var items = await Task.Run(delegate { return _service.LoadSpnmtpItems(); });
|
||||
var currentId = idToSelect ?? (SelectedItem == null ? (int?)null : SelectedItem.Id);
|
||||
|
||||
Items.Clear();
|
||||
foreach (var item in items)
|
||||
{
|
||||
Items.Add(item);
|
||||
}
|
||||
|
||||
ItemsView.Refresh();
|
||||
SelectedItem = currentId.HasValue
|
||||
? Items.FirstOrDefault(delegate(SpnmtpDirectoryItem item) { return item.Id == currentId.Value; })
|
||||
: Items.FirstOrDefault();
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void RefreshAsync()
|
||||
{
|
||||
RunBusyOperation(delegate { return RefreshCoreAsync(null); });
|
||||
}
|
||||
|
||||
private void RaiseCommandStates()
|
||||
{
|
||||
((RelayCommand)AddCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)DeleteCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)EditCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)RefreshCommand).RaiseCanExecuteChanged();
|
||||
}
|
||||
|
||||
private async void RunBusyOperation(Func<Task> operation)
|
||||
{
|
||||
await ExecuteBusyOperationAsync(operation);
|
||||
}
|
||||
|
||||
private async void RunMutationOperation(Func<Task> operation)
|
||||
{
|
||||
await ExecuteMutationOperationAsync(operation);
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
var visibleCount = ItemsView.Cast<object>().Count();
|
||||
StatusText = string.Format("Всего записей: {0}. По фильтру: {1}.", Items.Count, visibleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
XLAB/SpnmtpEditWindow.xaml
Normal file
64
XLAB/SpnmtpEditWindow.xaml
Normal file
@@ -0,0 +1,64 @@
|
||||
<Window x:Class="XLAB.SpnmtpEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="250"
|
||||
Width="560"
|
||||
MinHeight="230"
|
||||
MinWidth="520"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="220" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="0,0,12,8"
|
||||
VerticalAlignment="Center"
|
||||
Text="Наименование типа СИ" />
|
||||
<TextBox Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,0,8"
|
||||
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="0,0,12,8"
|
||||
VerticalAlignment="Center"
|
||||
Text="Специальное наименование типа" />
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="0,0,0,8"
|
||||
Text="{Binding SpecialName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="2"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,8,0,0"
|
||||
Foreground="Firebrick"
|
||||
Text="{Binding ValidationMessage}" />
|
||||
|
||||
<StackPanel Grid.Row="3"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="0,12,0,0"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="100"
|
||||
Margin="0,0,8,0"
|
||||
IsDefault="True"
|
||||
Command="{Binding ConfirmCommand}"
|
||||
Content="Сохранить" />
|
||||
<Button Width="90"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="Отмена" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/SpnmtpEditWindow.xaml.cs
Normal file
20
XLAB/SpnmtpEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class SpnmtpEditWindow : Window
|
||||
{
|
||||
internal SpnmtpEditWindow(SpnmtpEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
127
XLAB/SpnmtpEditWindowViewModel.cs
Normal file
127
XLAB/SpnmtpEditWindowViewModel.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class SpnmtpEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<SpnmtpDirectoryItem> _existingItems;
|
||||
private string _name;
|
||||
private string _specialName;
|
||||
private string _validationMessage;
|
||||
|
||||
public SpnmtpEditWindowViewModel(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems)
|
||||
{
|
||||
var source = seed ?? new SpnmtpDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<SpnmtpDirectoryItem>();
|
||||
Id = source.Id;
|
||||
IsNew = isNew;
|
||||
Name = source.Name ?? string.Empty;
|
||||
SpecialName = source.SpecialName ?? string.Empty;
|
||||
|
||||
ConfirmCommand = new RelayCommand(Confirm);
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public event EventHandler<bool?> CloseRequested;
|
||||
|
||||
public ICommand CancelCommand { get; private set; }
|
||||
|
||||
public ICommand ConfirmCommand { get; private set; }
|
||||
|
||||
public int Id { get; private set; }
|
||||
|
||||
public bool IsNew { get; private set; }
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetProperty(ref _name, value); }
|
||||
}
|
||||
|
||||
public string SpecialName
|
||||
{
|
||||
get { return _specialName; }
|
||||
set { SetProperty(ref _specialName, value); }
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return IsNew ? "Новое наименование типа СИ" : "Редактирование наименования типа СИ"; }
|
||||
}
|
||||
|
||||
public string ValidationMessage
|
||||
{
|
||||
get { return _validationMessage; }
|
||||
private set { SetProperty(ref _validationMessage, value); }
|
||||
}
|
||||
|
||||
public SpnmtpDirectoryItem ToResult()
|
||||
{
|
||||
return new SpnmtpDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
Name = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim(),
|
||||
SpecialName = string.IsNullOrWhiteSpace(SpecialName) ? string.Empty : SpecialName.Trim()
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter)
|
||||
{
|
||||
RaiseCloseRequested(false);
|
||||
}
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
var normalizedName = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim();
|
||||
var normalizedSpecialName = string.IsNullOrWhiteSpace(SpecialName) ? string.Empty : SpecialName.Trim();
|
||||
|
||||
if (normalizedName.Length == 0)
|
||||
{
|
||||
ValidationMessage = "Укажите наименование типа СИ.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedName.Length > SpnmtpDirectoryRules.NameMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Наименование типа СИ не должно превышать {0} символов.", SpnmtpDirectoryRules.NameMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedSpecialName.Length > SpnmtpDirectoryRules.SpecialNameMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Специальное наименование типа не должно превышать {0} символов.", SpnmtpDirectoryRules.SpecialNameMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(SpnmtpDirectoryItem item)
|
||||
{
|
||||
return item != null
|
||||
&& item.Id != Id
|
||||
&& string.Equals(
|
||||
string.IsNullOrWhiteSpace(item.Name) ? string.Empty : item.Name.Trim(),
|
||||
normalizedName,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
if (duplicate != null)
|
||||
{
|
||||
ValidationMessage = string.Format("Наименование типа СИ \"{0}\" уже существует в справочнике.", normalizedName);
|
||||
return;
|
||||
}
|
||||
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,24 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SelectInstrumentTypeWindowViewModel.cs" />
|
||||
<Page Include="SpnmtpDirectoryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="SpnmtpDirectoryWindow.xaml.cs">
|
||||
<DependentUpon>SpnmtpDirectoryWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpnmtpDirectoryWindowViewModel.cs" />
|
||||
<Page Include="SpnmtpEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="SpnmtpEditWindow.xaml.cs">
|
||||
<DependentUpon>SpnmtpEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpnmtpEditWindowViewModel.cs" />
|
||||
<Page Include="VerificationEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
Reference in New Issue
Block a user