edit
This commit is contained in:
@@ -13,6 +13,8 @@ namespace XLAB
|
|||||||
|
|
||||||
IReadOnlyList<string> ShowCloneVerificationDialog(CloneVerificationSeed seed);
|
IReadOnlyList<string> ShowCloneVerificationDialog(CloneVerificationSeed seed);
|
||||||
|
|
||||||
|
SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems);
|
||||||
|
|
||||||
VerificationEditResult ShowVerificationDialog(
|
VerificationEditResult ShowVerificationDialog(
|
||||||
VerificationEditSeed seed,
|
VerificationEditSeed seed,
|
||||||
IReadOnlyList<PersonReference> verifiers,
|
IReadOnlyList<PersonReference> verifiers,
|
||||||
@@ -76,6 +78,16 @@ namespace XLAB
|
|||||||
return result.HasValue && result.Value ? viewModel.GetSerialNumbers() : null;
|
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(
|
public VerificationEditResult ShowVerificationDialog(
|
||||||
VerificationEditSeed seed,
|
VerificationEditSeed seed,
|
||||||
IReadOnlyList<PersonReference> verifiers,
|
IReadOnlyList<PersonReference> verifiers,
|
||||||
|
|||||||
@@ -9,13 +9,27 @@
|
|||||||
WindowState="Maximized"
|
WindowState="Maximized"
|
||||||
Loaded="Window_Loaded">
|
Loaded="Window_Loaded">
|
||||||
<Grid Margin="12">
|
<Grid Margin="12">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<ColumnDefinition Width="430" />
|
<RowDefinition Height="Auto" />
|
||||||
<ColumnDefinition Width="12" />
|
<RowDefinition Height="*" />
|
||||||
<ColumnDefinition Width="*" />
|
</Grid.RowDefinitions>
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<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 Margin="8">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -322,4 +336,5 @@
|
|||||||
</GroupBox>
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</Window>
|
</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)
|
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
await _viewModel.InitializeAsync();
|
await _viewModel.InitializeAsync();
|
||||||
|
|||||||
@@ -146,6 +146,153 @@ ORDER BY fr.NMFRD, v.IDVDODVDD;";
|
|||||||
return forms;
|
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()
|
public IReadOnlyList<PsvDocumentSummary> LoadDocuments()
|
||||||
{
|
{
|
||||||
const string sql = @"
|
const string sql = @"
|
||||||
@@ -2136,6 +2283,99 @@ WHERE z.IDEKZ = @InstrumentId
|
|||||||
return value.Trim();
|
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)
|
private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document)
|
||||||
{
|
{
|
||||||
const string sql = @"
|
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 sealed class DocumentFormReference
|
||||||
{
|
{
|
||||||
public int DocumentFormId { get; set; }
|
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>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="SelectInstrumentTypeWindowViewModel.cs" />
|
<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">
|
<Page Include="VerificationEditWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|||||||
Reference in New Issue
Block a user