edit
This commit is contained in:
@@ -13,6 +13,8 @@ namespace XLAB
|
||||
|
||||
IReadOnlyList<string> ShowCloneVerificationDialog(CloneVerificationSeed seed);
|
||||
|
||||
SpoiDirectoryItem ShowSpoiEditDialog(SpoiDirectoryItem seed, bool isNew, IReadOnlyList<SpoiDirectoryItem> existingItems);
|
||||
|
||||
SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems);
|
||||
|
||||
VerificationEditResult ShowVerificationDialog(
|
||||
@@ -78,6 +80,16 @@ namespace XLAB
|
||||
return result.HasValue && result.Value ? viewModel.GetSerialNumbers() : null;
|
||||
}
|
||||
|
||||
public SpoiDirectoryItem ShowSpoiEditDialog(SpoiDirectoryItem seed, bool isNew, IReadOnlyList<SpoiDirectoryItem> existingItems)
|
||||
{
|
||||
var viewModel = new SpoiEditWindowViewModel(seed, isNew, existingItems);
|
||||
var window = new SpoiEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList<SpnmtpDirectoryItem> existingItems)
|
||||
{
|
||||
var viewModel = new SpnmtpEditWindowViewModel(seed, isNew, existingItems);
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
<Menu Grid.Row="0"
|
||||
Margin="0,0,0,12">
|
||||
<MenuItem Header="Справочники">
|
||||
<MenuItem Header="Типоразмеры СИ"
|
||||
Click="TypeSizeDirectoryMenuItem_Click" />
|
||||
<MenuItem Header="Области измерений"
|
||||
Click="SpoiDirectoryMenuItem_Click" />
|
||||
<MenuItem Header="Наименования типов СИ"
|
||||
Click="SpnmtpDirectoryMenuItem_Click" />
|
||||
</MenuItem>
|
||||
|
||||
@@ -52,6 +52,20 @@ namespace XLAB
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void TypeSizeDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = new TypeSizeDirectoryWindow();
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private void SpoiDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var window = new SpoiDirectoryWindow();
|
||||
window.Owner = this;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
|
||||
@@ -146,6 +146,184 @@ ORDER BY fr.NMFRD, v.IDVDODVDD;";
|
||||
return forms;
|
||||
}
|
||||
|
||||
public IReadOnlyList<SpoiDirectoryItem> LoadSpoiItems()
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT
|
||||
s.IDSPOI AS Id,
|
||||
s.KDOI AS Code,
|
||||
s.NMOI AS Name
|
||||
FROM dbo.SPOI s
|
||||
ORDER BY s.NMOI, s.KDOI, s.IDSPOI;";
|
||||
|
||||
var items = new List<SpoiDirectoryItem>();
|
||||
|
||||
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 SpoiDirectoryItem
|
||||
{
|
||||
Id = GetInt32(reader, "Id"),
|
||||
Code = GetString(reader, "Code"),
|
||||
Name = GetString(reader, "Name")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public int AddSpoiItem(SpoiDirectoryItem item)
|
||||
{
|
||||
var normalizedItem = NormalizeSpoiItem(item);
|
||||
|
||||
const string sql = @"
|
||||
INSERT INTO dbo.SPOI
|
||||
(
|
||||
KDOI,
|
||||
NMOI
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@Code,
|
||||
@Name
|
||||
);
|
||||
|
||||
SELECT CAST(SCOPE_IDENTITY() AS int);";
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
EnsureSpoiCodeIsUnique(connection, normalizedItem.Code, null);
|
||||
EnsureSpoiNameIsUnique(connection, normalizedItem.Name, null);
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = normalizedItem.Code;
|
||||
command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
|
||||
|
||||
try
|
||||
{
|
||||
return Convert.ToInt32(command.ExecuteScalar());
|
||||
}
|
||||
catch (SqlException ex) when (IsSpoiDuplicateCodeViolation(ex))
|
||||
{
|
||||
throw CreateSpoiDuplicateCodeException(normalizedItem.Code, ex);
|
||||
}
|
||||
catch (SqlException ex) when (IsSpoiDuplicateNameViolation(ex))
|
||||
{
|
||||
throw CreateSpoiDuplicateNameException(normalizedItem.Name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSpoiItem(SpoiDirectoryItem item)
|
||||
{
|
||||
var normalizedItem = NormalizeSpoiItem(item);
|
||||
if (normalizedItem.Id <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Не выбрана запись SPOI для изменения.");
|
||||
}
|
||||
|
||||
const string sql = @"
|
||||
UPDATE dbo.SPOI
|
||||
SET KDOI = @Code,
|
||||
NMOI = @Name
|
||||
WHERE IDSPOI = @Id;
|
||||
|
||||
SELECT @@ROWCOUNT;";
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
EnsureSpoiCodeIsUnique(connection, normalizedItem.Code, normalizedItem.Id);
|
||||
EnsureSpoiNameIsUnique(connection, normalizedItem.Name, normalizedItem.Id);
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id;
|
||||
command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = normalizedItem.Code;
|
||||
command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.NameMaxLength).Value = normalizedItem.Name;
|
||||
|
||||
try
|
||||
{
|
||||
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Запись SPOI для изменения не найдена.");
|
||||
}
|
||||
}
|
||||
catch (SqlException ex) when (IsSpoiDuplicateCodeViolation(ex))
|
||||
{
|
||||
throw CreateSpoiDuplicateCodeException(normalizedItem.Code, ex);
|
||||
}
|
||||
catch (SqlException ex) when (IsSpoiDuplicateNameViolation(ex))
|
||||
{
|
||||
throw CreateSpoiDuplicateNameException(normalizedItem.Name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SpoiDeleteResult DeleteSpoiItem(int id)
|
||||
{
|
||||
if (id <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Не выбрана запись SPOI для удаления.");
|
||||
}
|
||||
|
||||
const string sql = @"
|
||||
DELETE FROM dbo.SPOI
|
||||
WHERE IDSPOI = @Id;
|
||||
|
||||
SELECT @@ROWCOUNT;";
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
connection.Open();
|
||||
var blockers = LoadSpoiDeleteBlockers(connection, id);
|
||||
if (blockers.Count > 0)
|
||||
{
|
||||
return new SpoiDeleteResult
|
||||
{
|
||||
IsDeleted = false,
|
||||
WarningMessage = CreateSpoiDeleteBlockedMessage(blockers)
|
||||
};
|
||||
}
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
|
||||
|
||||
if (Convert.ToInt32(command.ExecuteScalar()) == 0)
|
||||
{
|
||||
throw new InvalidOperationException("Запись SPOI для удаления не найдена.");
|
||||
}
|
||||
}
|
||||
|
||||
return new SpoiDeleteResult
|
||||
{
|
||||
IsDeleted = true
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (SqlException ex) when (ex.Number == 547)
|
||||
{
|
||||
return new SpoiDeleteResult
|
||||
{
|
||||
IsDeleted = false,
|
||||
WarningMessage = CreateSpoiDeleteBlockedMessage(ex)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<SpnmtpDirectoryItem> LoadSpnmtpItems()
|
||||
{
|
||||
const string sql = @"
|
||||
@@ -2304,6 +2482,216 @@ WHERE z.IDEKZ = @InstrumentId
|
||||
return value.Trim();
|
||||
}
|
||||
|
||||
private static SpoiDirectoryItem NormalizeSpoiItem(SpoiDirectoryItem item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException("item");
|
||||
}
|
||||
|
||||
var code = NormalizeRequiredSpoiValue(
|
||||
item.Code,
|
||||
"Код ОИ не заполнен.",
|
||||
SpoiDirectoryRules.CodeMaxLength,
|
||||
"Код ОИ превышает допустимую длину.");
|
||||
var name = NormalizeRequiredSpoiValue(
|
||||
item.Name,
|
||||
"Область измерений не заполнена.",
|
||||
SpoiDirectoryRules.NameMaxLength,
|
||||
"Область измерений превышает допустимую длину.");
|
||||
|
||||
return new SpoiDirectoryItem
|
||||
{
|
||||
Id = item.Id,
|
||||
Code = code,
|
||||
Name = name
|
||||
};
|
||||
}
|
||||
|
||||
private static void EnsureSpoiCodeIsUnique(SqlConnection connection, string code, int? excludeId)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT TOP (1) IDSPOI
|
||||
FROM dbo.SPOI
|
||||
WHERE KDOI = @Code
|
||||
AND (@ExcludeId IS NULL OR IDSPOI <> @ExcludeId);";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = code;
|
||||
command.Parameters.Add("@ExcludeId", SqlDbType.Int).Value = (object)excludeId ?? DBNull.Value;
|
||||
|
||||
var existingId = command.ExecuteScalar();
|
||||
if (existingId != null && existingId != DBNull.Value)
|
||||
{
|
||||
throw CreateSpoiDuplicateCodeException(code, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureSpoiNameIsUnique(SqlConnection connection, string name, int? excludeId)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT TOP (1) IDSPOI
|
||||
FROM dbo.SPOI
|
||||
WHERE NMOI = @Name
|
||||
AND (@ExcludeId IS NULL OR IDSPOI <> @ExcludeId);";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.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 CreateSpoiDuplicateNameException(name, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static InvalidOperationException CreateSpoiDuplicateCodeException(string code, Exception innerException)
|
||||
{
|
||||
return new InvalidOperationException(
|
||||
string.Format("Код ОИ \"{0}\" уже существует в справочнике.", code),
|
||||
innerException);
|
||||
}
|
||||
|
||||
private static InvalidOperationException CreateSpoiDuplicateNameException(string name, Exception innerException)
|
||||
{
|
||||
return new InvalidOperationException(
|
||||
string.Format("Область измерений \"{0}\" уже существует в справочнике.", name),
|
||||
innerException);
|
||||
}
|
||||
|
||||
private static List<DeleteBlockerInfo> LoadSpoiDeleteBlockers(SqlConnection connection, int id)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT blocker.TableName, blocker.LinkCount
|
||||
FROM
|
||||
(
|
||||
SELECT N'FRATGR' AS TableName, COUNT(*) AS LinkCount
|
||||
FROM dbo.FRATGR
|
||||
WHERE IDSPOI = @Id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT N'PRATGR', COUNT(*)
|
||||
FROM dbo.PRATGR
|
||||
WHERE IDSPOI = @Id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT N'PRSTOI', COUNT(*)
|
||||
FROM dbo.PRSTOI
|
||||
WHERE IDSPOI = @Id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT N'TIPS', COUNT(*)
|
||||
FROM dbo.TIPS
|
||||
WHERE IDSPOI = @Id
|
||||
) blocker
|
||||
WHERE blocker.LinkCount > 0
|
||||
ORDER BY blocker.TableName;";
|
||||
|
||||
var blockers = new List<DeleteBlockerInfo>();
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
blockers.Add(new DeleteBlockerInfo
|
||||
{
|
||||
TableName = GetString(reader, "TableName"),
|
||||
RowCount = GetInt32(reader, "LinkCount")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return blockers;
|
||||
}
|
||||
|
||||
private static string CreateSpoiDeleteBlockedMessage(IEnumerable<DeleteBlockerInfo> blockers)
|
||||
{
|
||||
var blockerList = blockers == null
|
||||
? new List<DeleteBlockerInfo>()
|
||||
: blockers.Where(delegate(DeleteBlockerInfo blocker) { return blocker != null; }).ToList();
|
||||
var details = blockerList.Count == 0
|
||||
? "FRATGR, PRATGR, PRSTOI, TIPS"
|
||||
: string.Join(", ", blockerList.Select(delegate(DeleteBlockerInfo blocker)
|
||||
{
|
||||
return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount);
|
||||
}));
|
||||
|
||||
return string.Format(
|
||||
"Запись SPOI не может быть удалена, потому что на неё есть ссылки в таблицах: {0}. Подтверждённые ограничения БД: FK_FRATGR_SPOI, FK_PRATGR_SPOI, FK_PRSTOI_SPOI, FK_TIPS_SPOI.",
|
||||
details);
|
||||
}
|
||||
|
||||
private static string CreateSpoiDeleteBlockedMessage(SqlException ex)
|
||||
{
|
||||
if (ex != null && ex.Message.IndexOf("FK_FRATGR_SPOI", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return "Запись SPOI не может быть удалена, потому что на неё есть ссылки в таблице FRATGR. Ограничение БД: FK_FRATGR_SPOI (dbo.FRATGR.IDSPOI -> dbo.SPOI.IDSPOI).";
|
||||
}
|
||||
|
||||
if (ex != null && ex.Message.IndexOf("FK_PRATGR_SPOI", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return "Запись SPOI не может быть удалена, потому что на неё есть ссылки в таблице PRATGR. Ограничение БД: FK_PRATGR_SPOI (dbo.PRATGR.IDSPOI -> dbo.SPOI.IDSPOI).";
|
||||
}
|
||||
|
||||
if (ex != null && ex.Message.IndexOf("FK_PRSTOI_SPOI", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return "Запись SPOI не может быть удалена, потому что на неё есть ссылки в таблице PRSTOI. Ограничение БД: FK_PRSTOI_SPOI (dbo.PRSTOI.IDSPOI -> dbo.SPOI.IDSPOI).";
|
||||
}
|
||||
|
||||
if (ex != null && ex.Message.IndexOf("FK_TIPS_SPOI", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return "Запись SPOI не может быть удалена, потому что на неё есть ссылки в таблице TIPS. Ограничение БД: FK_TIPS_SPOI (dbo.TIPS.IDSPOI -> dbo.SPOI.IDSPOI).";
|
||||
}
|
||||
|
||||
return "Запись SPOI не может быть удалена из-за ограничения ссылочной целостности в БД.";
|
||||
}
|
||||
|
||||
private static bool IsSpoiDuplicateCodeViolation(SqlException ex)
|
||||
{
|
||||
return ex != null
|
||||
&& (ex.Number == 2601 || ex.Number == 2627)
|
||||
&& ex.Message.IndexOf("XAK2SPOI", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static bool IsSpoiDuplicateNameViolation(SqlException ex)
|
||||
{
|
||||
return ex != null
|
||||
&& (ex.Number == 2601 || ex.Number == 2627)
|
||||
&& ex.Message.IndexOf("XAK1SPOI", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private static string NormalizeRequiredSpoiValue(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 SpnmtpDirectoryItem NormalizeSpnmtpItem(SpnmtpDirectoryItem item)
|
||||
{
|
||||
if (item == null)
|
||||
|
||||
@@ -360,6 +360,29 @@ namespace XLAB
|
||||
public string WarningMessage { get; set; }
|
||||
}
|
||||
|
||||
public sealed class SpoiDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class SpoiDeleteResult
|
||||
{
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public string WarningMessage { get; set; }
|
||||
}
|
||||
|
||||
internal static class SpoiDirectoryRules
|
||||
{
|
||||
public const int CodeMaxLength = 3;
|
||||
|
||||
public const int NameMaxLength = 80;
|
||||
}
|
||||
|
||||
internal static class SpnmtpDirectoryRules
|
||||
{
|
||||
public const int NameMaxLength = 150;
|
||||
|
||||
86
XLAB/SpoiDirectoryWindow.xaml
Normal file
86
XLAB/SpoiDirectoryWindow.xaml
Normal file
@@ -0,0 +1,86 @@
|
||||
<Window x:Class="XLAB.SpoiDirectoryWindow"
|
||||
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="120"
|
||||
Binding="{Binding Code}" />
|
||||
<DataGridTextColumn Header="Область измерений"
|
||||
Width="*"
|
||||
Binding="{Binding Name}" />
|
||||
</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/SpoiDirectoryWindow.xaml.cs
Normal file
21
XLAB/SpoiDirectoryWindow.xaml.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class SpoiDirectoryWindow : Window
|
||||
{
|
||||
private readonly SpoiDirectoryWindowViewModel _viewModel;
|
||||
|
||||
public SpoiDirectoryWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = new SpoiDirectoryWindowViewModel(new PsvDataService(), new DialogService(this));
|
||||
DataContext = _viewModel;
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
294
XLAB/SpoiDirectoryWindowViewModel.cs
Normal file
294
XLAB/SpoiDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,294 @@
|
||||
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 SpoiDirectoryWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly PsvDataService _service;
|
||||
private bool _isBusy;
|
||||
private string _searchText;
|
||||
private SpoiDirectoryItem _selectedItem;
|
||||
private string _statusText;
|
||||
|
||||
public SpoiDirectoryWindowViewModel(PsvDataService service, IDialogService dialogService)
|
||||
{
|
||||
_service = service;
|
||||
_dialogService = dialogService;
|
||||
|
||||
Items = new ObservableCollection<SpoiDirectoryItem>();
|
||||
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<SpoiDirectoryItem> 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 SpoiDirectoryItem 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.ShowSpoiEditDialog(new SpoiDirectoryItem(), true, Items.ToList());
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddSpoiItem(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
|
||||
{
|
||||
var deleteResult = await Task.Run(delegate { return _service.DeleteSpoiItem(selectedItem.Id); });
|
||||
if (!deleteResult.IsDeleted)
|
||||
{
|
||||
_dialogService.ShowWarning(deleteResult.WarningMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
await RefreshCoreAsync(null);
|
||||
_dialogService.ShowInfo("Запись справочника удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditSelectedItemAsync()
|
||||
{
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var seed = new SpoiDirectoryItem
|
||||
{
|
||||
Id = SelectedItem.Id,
|
||||
Code = SelectedItem.Code,
|
||||
Name = SelectedItem.Name
|
||||
};
|
||||
|
||||
var result = _dialogService.ShowSpoiEditDialog(seed, false, Items.ToList());
|
||||
if (result == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateSpoiItem(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 SpoiDirectoryItem;
|
||||
if (directoryItem == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(SearchText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Contains(directoryItem.Code, SearchText)
|
||||
|| Contains(directoryItem.Name, SearchText)
|
||||
|| directoryItem.Id.ToString().IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private async Task RefreshCoreAsync(int? idToSelect)
|
||||
{
|
||||
var items = await Task.Run(delegate { return _service.LoadSpoiItems(); });
|
||||
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(SpoiDirectoryItem 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)
|
||||
{
|
||||
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 void UpdateStatus()
|
||||
{
|
||||
var visibleCount = ItemsView.Cast<object>().Count();
|
||||
StatusText = string.Format("Всего записей: {0}. По фильтру: {1}.", Items.Count, visibleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
XLAB/SpoiEditWindow.xaml
Normal file
65
XLAB/SpoiEditWindow.xaml
Normal file
@@ -0,0 +1,65 @@
|
||||
<Window x:Class="XLAB.SpoiEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="230"
|
||||
Width="540"
|
||||
MinHeight="220"
|
||||
MinWidth="500"
|
||||
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="180" />
|
||||
<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"
|
||||
MaxLength="3"
|
||||
Text="{Binding Code, 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 Name, 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/SpoiEditWindow.xaml.cs
Normal file
20
XLAB/SpoiEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class SpoiEditWindow : Window
|
||||
{
|
||||
internal SpoiEditWindow(SpoiEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
148
XLAB/SpoiEditWindowViewModel.cs
Normal file
148
XLAB/SpoiEditWindowViewModel.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class SpoiEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<SpoiDirectoryItem> _existingItems;
|
||||
private string _code;
|
||||
private string _name;
|
||||
private string _validationMessage;
|
||||
|
||||
public SpoiEditWindowViewModel(SpoiDirectoryItem seed, bool isNew, IReadOnlyList<SpoiDirectoryItem> existingItems)
|
||||
{
|
||||
var source = seed ?? new SpoiDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<SpoiDirectoryItem>();
|
||||
Id = source.Id;
|
||||
IsNew = isNew;
|
||||
Code = source.Code ?? string.Empty;
|
||||
Name = source.Name ?? string.Empty;
|
||||
|
||||
ConfirmCommand = new RelayCommand(Confirm);
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public event EventHandler<bool?> CloseRequested;
|
||||
|
||||
public ICommand CancelCommand { get; private set; }
|
||||
|
||||
public string Code
|
||||
{
|
||||
get { return _code; }
|
||||
set { SetProperty(ref _code, value); }
|
||||
}
|
||||
|
||||
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 Title
|
||||
{
|
||||
get { return IsNew ? "Новая область измерений" : "Редактирование области измерений"; }
|
||||
}
|
||||
|
||||
public string ValidationMessage
|
||||
{
|
||||
get { return _validationMessage; }
|
||||
private set { SetProperty(ref _validationMessage, value); }
|
||||
}
|
||||
|
||||
public SpoiDirectoryItem ToResult()
|
||||
{
|
||||
return new SpoiDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
Code = string.IsNullOrWhiteSpace(Code) ? string.Empty : Code.Trim(),
|
||||
Name = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim()
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter)
|
||||
{
|
||||
RaiseCloseRequested(false);
|
||||
}
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
var normalizedCode = string.IsNullOrWhiteSpace(Code) ? string.Empty : Code.Trim();
|
||||
var normalizedName = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim();
|
||||
|
||||
if (normalizedCode.Length == 0)
|
||||
{
|
||||
ValidationMessage = "Укажите код ОИ.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedCode.Length > SpoiDirectoryRules.CodeMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Код ОИ не должен превышать {0} символов.", SpoiDirectoryRules.CodeMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedName.Length == 0)
|
||||
{
|
||||
ValidationMessage = "Укажите область измерений.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedName.Length > SpoiDirectoryRules.NameMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Область измерений не должна превышать {0} символов.", SpoiDirectoryRules.NameMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicateCode = _existingItems.FirstOrDefault(delegate(SpoiDirectoryItem item)
|
||||
{
|
||||
return item != null
|
||||
&& item.Id != Id
|
||||
&& string.Equals(
|
||||
string.IsNullOrWhiteSpace(item.Code) ? string.Empty : item.Code.Trim(),
|
||||
normalizedCode,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
if (duplicateCode != null)
|
||||
{
|
||||
ValidationMessage = string.Format("Код ОИ \"{0}\" уже существует в справочнике.", normalizedCode);
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicateName = _existingItems.FirstOrDefault(delegate(SpoiDirectoryItem item)
|
||||
{
|
||||
return item != null
|
||||
&& item.Id != Id
|
||||
&& string.Equals(
|
||||
string.IsNullOrWhiteSpace(item.Name) ? string.Empty : item.Name.Trim(),
|
||||
normalizedName,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
if (duplicateName != 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
87
XLAB/TipsEditWindow.xaml
Normal file
87
XLAB/TipsEditWindow.xaml
Normal file
@@ -0,0 +1,87 @@
|
||||
<Window x:Class="XLAB.TipsEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="620"
|
||||
Width="760"
|
||||
MinHeight="580"
|
||||
MinWidth="700"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="220" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Область измерений" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding MeasurementAreas}" SelectedValue="{Binding MeasurementAreaId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Наименование типа СИ" />
|
||||
<ComboBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding InstrumentNames}" SelectedValue="{Binding InstrumentNameId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Тип СИ" />
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" Text="{Binding TypeName, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Категория СИ" />
|
||||
<ComboBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Categories}" SelectedValue="{Binding CategoryId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Конструктивное исполнение" />
|
||||
<ComboBox Grid.Row="4" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Designs}" SelectedValue="{Binding DesignId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Срок службы, лет" />
|
||||
<TextBox Grid.Row="5" Grid.Column="1" Margin="0,0,0,8" Text="{Binding ServiceLifeYearsText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="МПИ по Госреестру, мес." />
|
||||
<TextBox Grid.Row="6" Grid.Column="1" Margin="0,0,0,8" Text="{Binding RegistryPeriodMonthsText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="№ по Госреестру" />
|
||||
<TextBox Grid.Row="7" Grid.Column="1" Margin="0,0,0,8" Text="{Binding RegistryTypeNumber, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Top" Text="Дополнительные сведения" />
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Margin="0,0,0,8" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Text="{Binding Notes, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<StackPanel Grid.Row="9" Grid.ColumnSpan="2" Orientation="Horizontal">
|
||||
<StackPanel Width="360" Orientation="Horizontal">
|
||||
<TextBlock Width="220" VerticalAlignment="Center" Text="Код ВНИИМС" />
|
||||
<TextBox Width="120" Text="{Binding VniimsTypeCodeText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
<StackPanel Width="220" Margin="12,0,0,0" Orientation="Horizontal">
|
||||
<TextBlock Width="90" VerticalAlignment="Center" Text="Код МК" />
|
||||
<TextBox Width="120" Text="{Binding MetrControlCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="0,12,0,0" Orientation="Horizontal">
|
||||
<CheckBox Margin="0,0,24,0" IsThreeState="True" IsChecked="{Binding IsSpecialPurpose}" Content="Специальное назначение" />
|
||||
<CheckBox IsThreeState="True" IsChecked="{Binding IsMkPrimaryOnly}" Content="МК только первичный" />
|
||||
</StackPanel>
|
||||
|
||||
<DockPanel Grid.Row="2" Margin="0,12,0,0">
|
||||
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/TipsEditWindow.xaml.cs
Normal file
20
XLAB/TipsEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TipsEditWindow : Window
|
||||
{
|
||||
internal TipsEditWindow(TipsEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
239
XLAB/TipsEditWindowViewModel.cs
Normal file
239
XLAB/TipsEditWindowViewModel.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TipsEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<TipsDirectoryItem> _existingItems;
|
||||
private int _categoryId;
|
||||
private int _designId;
|
||||
private int _instrumentNameId;
|
||||
private bool? _isMkPrimaryOnly;
|
||||
private bool? _isSpecialPurpose;
|
||||
private int _measurementAreaId;
|
||||
private string _metrControlCode;
|
||||
private string _notes;
|
||||
private string _registryPeriodMonthsText;
|
||||
private string _registryTypeNumber;
|
||||
private string _serviceLifeYearsText;
|
||||
private string _typeName;
|
||||
private string _validationMessage;
|
||||
private string _vniimsTypeCodeText;
|
||||
|
||||
public TipsEditWindowViewModel(TipsDirectoryItem seed, bool isNew, IReadOnlyList<TipsDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var source = seed ?? new TipsDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<TipsDirectoryItem>();
|
||||
Id = source.Id;
|
||||
IsNew = isNew;
|
||||
|
||||
MeasurementAreas = service.LoadSpoiReferences();
|
||||
InstrumentNames = service.LoadSpnmtpReferences();
|
||||
Categories = WithEmpty(service.LoadSpktReferences());
|
||||
Designs = WithEmpty(service.LoadSpkiReferences());
|
||||
|
||||
MeasurementAreaId = source.MeasurementAreaId;
|
||||
InstrumentNameId = source.InstrumentNameId;
|
||||
CategoryId = source.CategoryId ?? 0;
|
||||
DesignId = source.DesignId ?? 0;
|
||||
TypeName = source.TypeName ?? string.Empty;
|
||||
ServiceLifeYearsText = source.ServiceLifeYears.HasValue ? source.ServiceLifeYears.Value.ToString() : string.Empty;
|
||||
RegistryPeriodMonthsText = source.RegistryPeriodMonths.HasValue ? source.RegistryPeriodMonths.Value.ToString() : string.Empty;
|
||||
RegistryTypeNumber = source.RegistryTypeNumber ?? string.Empty;
|
||||
VniimsTypeCodeText = source.VniimsTypeCode.HasValue ? source.VniimsTypeCode.Value.ToString() : string.Empty;
|
||||
MetrControlCode = source.MetrControlCode ?? string.Empty;
|
||||
Notes = source.Notes ?? string.Empty;
|
||||
IsSpecialPurpose = source.IsSpecialPurpose;
|
||||
IsMkPrimaryOnly = source.IsMkPrimaryOnly;
|
||||
|
||||
ConfirmCommand = new RelayCommand(Confirm);
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public event EventHandler<bool?> CloseRequested;
|
||||
|
||||
public ICommand CancelCommand { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Categories { get; private set; }
|
||||
public ICommand ConfirmCommand { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Designs { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> InstrumentNames { get; private set; }
|
||||
public bool IsNew { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> MeasurementAreas { get; private set; }
|
||||
|
||||
public int MeasurementAreaId { get { return _measurementAreaId; } set { SetProperty(ref _measurementAreaId, value); } }
|
||||
public int InstrumentNameId { get { return _instrumentNameId; } set { SetProperty(ref _instrumentNameId, value); } }
|
||||
public int CategoryId { get { return _categoryId; } set { SetProperty(ref _categoryId, value); } }
|
||||
public int DesignId { get { return _designId; } set { SetProperty(ref _designId, value); } }
|
||||
public string TypeName { get { return _typeName; } set { SetProperty(ref _typeName, value); } }
|
||||
public string ServiceLifeYearsText { get { return _serviceLifeYearsText; } set { SetProperty(ref _serviceLifeYearsText, value); } }
|
||||
public string RegistryPeriodMonthsText { get { return _registryPeriodMonthsText; } set { SetProperty(ref _registryPeriodMonthsText, value); } }
|
||||
public string RegistryTypeNumber { get { return _registryTypeNumber; } set { SetProperty(ref _registryTypeNumber, value); } }
|
||||
public string VniimsTypeCodeText { get { return _vniimsTypeCodeText; } set { SetProperty(ref _vniimsTypeCodeText, value); } }
|
||||
public string MetrControlCode { get { return _metrControlCode; } set { SetProperty(ref _metrControlCode, value); } }
|
||||
public string Notes { get { return _notes; } set { SetProperty(ref _notes, value); } }
|
||||
public bool? IsSpecialPurpose { get { return _isSpecialPurpose; } set { SetProperty(ref _isSpecialPurpose, value); } }
|
||||
public bool? IsMkPrimaryOnly { get { return _isMkPrimaryOnly; } set { SetProperty(ref _isMkPrimaryOnly, value); } }
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return IsNew ? "Новый тип СИ" : "Редактирование типа СИ"; }
|
||||
}
|
||||
|
||||
public string ValidationMessage
|
||||
{
|
||||
get { return _validationMessage; }
|
||||
private set { SetProperty(ref _validationMessage, value); }
|
||||
}
|
||||
|
||||
public TipsDirectoryItem ToResult()
|
||||
{
|
||||
return new TipsDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
MeasurementAreaId = MeasurementAreaId,
|
||||
InstrumentNameId = InstrumentNameId,
|
||||
CategoryId = CategoryId > 0 ? (int?)CategoryId : null,
|
||||
DesignId = DesignId > 0 ? (int?)DesignId : null,
|
||||
TypeName = Normalize(TypeName),
|
||||
ServiceLifeYears = ParseNullableInt(ServiceLifeYearsText),
|
||||
RegistryPeriodMonths = ParseNullableInt(RegistryPeriodMonthsText),
|
||||
RegistryTypeNumber = Normalize(RegistryTypeNumber),
|
||||
VniimsTypeCode = ParseNullableInt(VniimsTypeCodeText),
|
||||
MetrControlCode = Normalize(MetrControlCode),
|
||||
Notes = Normalize(Notes),
|
||||
IsSpecialPurpose = IsSpecialPurpose,
|
||||
IsMkPrimaryOnly = IsMkPrimaryOnly
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter)
|
||||
{
|
||||
RaiseCloseRequested(false);
|
||||
}
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
if (MeasurementAreaId <= 0)
|
||||
{
|
||||
ValidationMessage = "Укажите область измерений.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (InstrumentNameId <= 0)
|
||||
{
|
||||
ValidationMessage = "Укажите наименование типа СИ.";
|
||||
return;
|
||||
}
|
||||
|
||||
var normalizedTypeName = Normalize(TypeName);
|
||||
if (string.IsNullOrWhiteSpace(normalizedTypeName))
|
||||
{
|
||||
ValidationMessage = "Укажите тип СИ.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (normalizedTypeName.Length > TipsDirectoryRules.TypeNameMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Тип СИ не должен превышать {0} символов.", TipsDirectoryRules.TypeNameMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
int? parsedValue;
|
||||
if (!TryParseNullableInt(ServiceLifeYearsText, out parsedValue))
|
||||
{
|
||||
ValidationMessage = "Срок службы должен быть целым числом.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryParseNullableInt(RegistryPeriodMonthsText, out parsedValue))
|
||||
{
|
||||
ValidationMessage = "МПИ по Госреестру должен быть целым числом.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryParseNullableInt(VniimsTypeCodeText, out parsedValue))
|
||||
{
|
||||
ValidationMessage = "Код ВНИИМС должен быть целым числом.";
|
||||
return;
|
||||
}
|
||||
|
||||
var normalizedRegistryNumber = Normalize(RegistryTypeNumber);
|
||||
if (!string.IsNullOrWhiteSpace(normalizedRegistryNumber) && normalizedRegistryNumber.Length > TipsDirectoryRules.RegistryTypeNumberMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Номер по Госреестру не должен превышать {0} символов.", TipsDirectoryRules.RegistryTypeNumberMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
var normalizedMetrControlCode = Normalize(MetrControlCode);
|
||||
if (!string.IsNullOrWhiteSpace(normalizedMetrControlCode) && normalizedMetrControlCode.Length > TipsDirectoryRules.MetrControlCodeMaxLength)
|
||||
{
|
||||
ValidationMessage = string.Format("Код АИС \"Метрконтроль\" не должен превышать {0} символов.", TipsDirectoryRules.MetrControlCodeMaxLength);
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(TipsDirectoryItem item)
|
||||
{
|
||||
return item != null
|
||||
&& item.Id != Id
|
||||
&& item.InstrumentNameId == InstrumentNameId
|
||||
&& string.Equals(Normalize(item.TypeName), normalizedTypeName, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
if (duplicate != null)
|
||||
{
|
||||
ValidationMessage = string.Format("Тип СИ \"{0}\" уже существует для выбранного наименования типа СИ.", normalizedTypeName);
|
||||
return;
|
||||
}
|
||||
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<DirectoryLookupItem> WithEmpty(IReadOnlyList<DirectoryLookupItem> source)
|
||||
{
|
||||
return new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(source ?? Array.Empty<DirectoryLookupItem>()).ToList();
|
||||
}
|
||||
|
||||
private static string Normalize(string value)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
|
||||
}
|
||||
|
||||
private static int? ParseNullableInt(string value)
|
||||
{
|
||||
int? parsedValue;
|
||||
return TryParseNullableInt(value, out parsedValue) ? parsedValue : (int?)null;
|
||||
}
|
||||
|
||||
private static bool TryParseNullableInt(string value, out int? result)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
result = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
int parsed;
|
||||
if (int.TryParse(value.Trim(), out parsed))
|
||||
{
|
||||
result = parsed;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
XLAB/TprmcpEditWindow.xaml
Normal file
48
XLAB/TprmcpEditWindow.xaml
Normal file
@@ -0,0 +1,48 @@
|
||||
<Window x:Class="XLAB.TprmcpEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="320"
|
||||
Width="620"
|
||||
MinHeight="300"
|
||||
MinWidth="580"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Цикл МК" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding CycleItems}" SelectedValue="{Binding CycleId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Группа СИ" />
|
||||
<ComboBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding GroupItems}" SelectedValue="{Binding GroupId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Период МК, мес." />
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" Text="{Binding PeriodMonthsText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Top" Text="Комментарий" />
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Text="{Binding Comment, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Row="1" Margin="0,12,0,0">
|
||||
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/TprmcpEditWindow.xaml.cs
Normal file
20
XLAB/TprmcpEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TprmcpEditWindow : Window
|
||||
{
|
||||
internal TprmcpEditWindow(TprmcpEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
99
XLAB/TprmcpEditWindowViewModel.cs
Normal file
99
XLAB/TprmcpEditWindowViewModel.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TprmcpEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<TprmcpDirectoryItem> _existingItems;
|
||||
private int _cycleId;
|
||||
private string _comment;
|
||||
private int _groupId;
|
||||
private string _periodMonthsText;
|
||||
private string _validationMessage;
|
||||
|
||||
public TprmcpEditWindowViewModel(TprmcpDirectoryItem seed, bool isNew, IReadOnlyList<TprmcpDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var source = seed ?? new TprmcpDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<TprmcpDirectoryItem>();
|
||||
Id = source.Id;
|
||||
TypeSizeId = source.TypeSizeId;
|
||||
IsNew = isNew;
|
||||
CycleItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(service.LoadSpvdmcReferences()).ToList();
|
||||
GroupItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(service.LoadGrsiReferences()).ToList();
|
||||
CycleId = source.CycleId ?? 0;
|
||||
GroupId = source.GroupId ?? 0;
|
||||
PeriodMonthsText = source.PeriodMonths.ToString();
|
||||
Comment = source.Comment ?? 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 IReadOnlyList<DirectoryLookupItem> CycleItems { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> GroupItems { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public bool IsNew { get; private set; }
|
||||
public int TypeSizeId { get; private set; }
|
||||
public int CycleId { get { return _cycleId; } set { SetProperty(ref _cycleId, value); } }
|
||||
public int GroupId { get { return _groupId; } set { SetProperty(ref _groupId, value); } }
|
||||
public string PeriodMonthsText { get { return _periodMonthsText; } set { SetProperty(ref _periodMonthsText, value); } }
|
||||
public string Comment { get { return _comment; } set { SetProperty(ref _comment, value); } }
|
||||
public string Title { get { return IsNew ? "Новый период МК" : "Редактирование периода МК"; } }
|
||||
public string ValidationMessage { get { return _validationMessage; } private set { SetProperty(ref _validationMessage, value); } }
|
||||
|
||||
public TprmcpDirectoryItem ToResult()
|
||||
{
|
||||
return new TprmcpDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
TypeSizeId = TypeSizeId,
|
||||
CycleId = CycleId > 0 ? (int?)CycleId : null,
|
||||
GroupId = GroupId > 0 ? (int?)GroupId : null,
|
||||
PeriodMonths = int.Parse(PeriodMonthsText.Trim()),
|
||||
Comment = Normalize(Comment)
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter) { RaiseCloseRequested(false); }
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
int periodMonths;
|
||||
if (!int.TryParse((PeriodMonthsText ?? string.Empty).Trim(), out periodMonths))
|
||||
{
|
||||
ValidationMessage = "Период МК должен быть целым числом.";
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(TprmcpDirectoryItem item)
|
||||
{
|
||||
return item != null
|
||||
&& item.Id != Id
|
||||
&& item.CycleId == (CycleId > 0 ? (int?)CycleId : null)
|
||||
&& item.GroupId == (GroupId > 0 ? (int?)GroupId : null)
|
||||
&& item.PeriodMonths == periodMonths;
|
||||
});
|
||||
if (duplicate != null)
|
||||
{
|
||||
ValidationMessage = "Такой цикл и период МК уже существуют для выбранного типоразмера.";
|
||||
return;
|
||||
}
|
||||
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private static string Normalize(string value) { return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); }
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null) handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
XLAB/TprmkEditWindow.xaml
Normal file
78
XLAB/TprmkEditWindow.xaml
Normal file
@@ -0,0 +1,78 @@
|
||||
<Window x:Class="XLAB.TprmkEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="620"
|
||||
Width="760"
|
||||
MinHeight="580"
|
||||
MinWidth="700"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="220" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид МК" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding VerificationTypes}" SelectedValue="{Binding VerificationTypeId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Организация / подразделение" />
|
||||
<ComboBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Organizations}" SelectedValue="{Binding OrganizationId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Квалификация" />
|
||||
<ComboBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Qualifications}" SelectedValue="{Binding QualificationId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Группа СИ" />
|
||||
<ComboBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Groups}" SelectedValue="{Binding GroupId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Место МК" />
|
||||
<ComboBox Grid.Row="4" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding Places}" SelectedValue="{Binding PlaceId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Стоимость / доп. / срочность" />
|
||||
<StackPanel Grid.Row="5" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBox Width="110" Margin="0,0,8,8" Text="{Binding CostText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Width="110" Margin="0,0,8,8" Text="{Binding ExtraCostText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Width="110" Margin="0,0,0,8" Text="{Binding RushMarkupText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Норма времени / НД" />
|
||||
<StackPanel Grid.Row="6" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBox Width="110" Margin="0,0,8,8" Text="{Binding TimeNormHoursText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Width="110" Margin="0,0,0,8" Text="{Binding NormDocHoursText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Код нормы / код поверки" />
|
||||
<StackPanel Grid.Row="7" Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBox Width="140" Margin="0,0,8,8" Text="{Binding TimeNormCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBox Width="180" Margin="0,0,0,8" Text="{Binding VerificationCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Количество поверителей" />
|
||||
<TextBox Grid.Row="8" Grid.Column="1" Margin="0,0,0,8" Text="{Binding VerifierCountText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Row="1" Margin="0,12,0,0">
|
||||
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/TprmkEditWindow.xaml.cs
Normal file
20
XLAB/TprmkEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TprmkEditWindow : Window
|
||||
{
|
||||
internal TprmkEditWindow(TprmkEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
153
XLAB/TprmkEditWindowViewModel.cs
Normal file
153
XLAB/TprmkEditWindowViewModel.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TprmkEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<TprmkDirectoryItem> _existingItems;
|
||||
private string _costText;
|
||||
private string _extraCostText;
|
||||
private int _groupId;
|
||||
private int _organizationId;
|
||||
private int _placeId;
|
||||
private int _qualificationId;
|
||||
private string _rushMarkupText;
|
||||
private string _timeNormCode;
|
||||
private string _timeNormHoursText;
|
||||
private string _normDocHoursText;
|
||||
private string _validationMessage;
|
||||
private string _verificationCode;
|
||||
private int _verificationTypeId;
|
||||
private string _verifierCountText;
|
||||
|
||||
public TprmkEditWindowViewModel(TprmkDirectoryItem seed, bool isNew, IReadOnlyList<TprmkDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var source = seed ?? new TprmkDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<TprmkDirectoryItem>();
|
||||
Id = source.Id;
|
||||
TypeSizeId = source.TypeSizeId;
|
||||
IsNew = isNew;
|
||||
VerificationTypes = service.LoadSpvdmkReferences();
|
||||
Organizations = service.LoadFrpdReferences();
|
||||
Qualifications = WithEmpty(service.LoadSpkvReferences());
|
||||
Groups = WithEmpty(service.LoadGrsiReferences());
|
||||
Places = WithEmpty(service.LoadSpmpobReferences());
|
||||
VerificationTypeId = source.VerificationTypeId;
|
||||
OrganizationId = source.OrganizationId;
|
||||
QualificationId = source.QualificationId ?? 0;
|
||||
GroupId = source.GroupId ?? 0;
|
||||
PlaceId = source.PlaceId ?? 0;
|
||||
CostText = ToString(source.Cost);
|
||||
ExtraCostText = ToString(source.ExtraCost);
|
||||
RushMarkupText = ToString(source.RushMarkup);
|
||||
TimeNormHoursText = ToString(source.TimeNormHours);
|
||||
NormDocHoursText = ToString(source.NormDocHours);
|
||||
TimeNormCode = source.TimeNormCode ?? string.Empty;
|
||||
VerificationCode = source.VerificationCode ?? string.Empty;
|
||||
VerifierCountText = source.VerifierCount.ToString();
|
||||
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 IReadOnlyList<DirectoryLookupItem> VerificationTypes { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Organizations { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Qualifications { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Groups { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> Places { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public bool IsNew { get; private set; }
|
||||
public int TypeSizeId { get; private set; }
|
||||
public int VerificationTypeId { get { return _verificationTypeId; } set { SetProperty(ref _verificationTypeId, value); } }
|
||||
public int OrganizationId { get { return _organizationId; } set { SetProperty(ref _organizationId, value); } }
|
||||
public int QualificationId { get { return _qualificationId; } set { SetProperty(ref _qualificationId, value); } }
|
||||
public int GroupId { get { return _groupId; } set { SetProperty(ref _groupId, value); } }
|
||||
public int PlaceId { get { return _placeId; } set { SetProperty(ref _placeId, value); } }
|
||||
public string CostText { get { return _costText; } set { SetProperty(ref _costText, value); } }
|
||||
public string ExtraCostText { get { return _extraCostText; } set { SetProperty(ref _extraCostText, value); } }
|
||||
public string RushMarkupText { get { return _rushMarkupText; } set { SetProperty(ref _rushMarkupText, value); } }
|
||||
public string TimeNormHoursText { get { return _timeNormHoursText; } set { SetProperty(ref _timeNormHoursText, value); } }
|
||||
public string NormDocHoursText { get { return _normDocHoursText; } set { SetProperty(ref _normDocHoursText, value); } }
|
||||
public string TimeNormCode { get { return _timeNormCode; } set { SetProperty(ref _timeNormCode, value); } }
|
||||
public string VerificationCode { get { return _verificationCode; } set { SetProperty(ref _verificationCode, value); } }
|
||||
public string VerifierCountText { get { return _verifierCountText; } set { SetProperty(ref _verifierCountText, value); } }
|
||||
public string Title { get { return IsNew ? "Новый регламент МК" : "Редактирование регламента МК"; } }
|
||||
public string ValidationMessage { get { return _validationMessage; } private set { SetProperty(ref _validationMessage, value); } }
|
||||
|
||||
public TprmkDirectoryItem ToResult()
|
||||
{
|
||||
return new TprmkDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
TypeSizeId = TypeSizeId,
|
||||
VerificationTypeId = VerificationTypeId,
|
||||
OrganizationId = OrganizationId,
|
||||
QualificationId = QualificationId > 0 ? (int?)QualificationId : null,
|
||||
GroupId = GroupId > 0 ? (int?)GroupId : null,
|
||||
PlaceId = PlaceId > 0 ? (int?)PlaceId : null,
|
||||
Cost = ParseNullableDecimal(CostText),
|
||||
ExtraCost = ParseNullableDecimal(ExtraCostText),
|
||||
RushMarkup = ParseNullableDecimal(RushMarkupText),
|
||||
TimeNormHours = ParseNullableDecimal(TimeNormHoursText),
|
||||
NormDocHours = ParseNullableDecimal(NormDocHoursText),
|
||||
TimeNormCode = Normalize(TimeNormCode),
|
||||
VerificationCode = Normalize(VerificationCode),
|
||||
VerifierCount = int.Parse(VerifierCountText.Trim())
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter) { RaiseCloseRequested(false); }
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
if (VerificationTypeId <= 0) { ValidationMessage = "Укажите вид МК."; return; }
|
||||
if (OrganizationId <= 0) { ValidationMessage = "Укажите организацию/подразделение."; return; }
|
||||
int verifierCount;
|
||||
if (!int.TryParse((VerifierCountText ?? string.Empty).Trim(), out verifierCount)) { ValidationMessage = "Количество поверителей должно быть целым числом."; return; }
|
||||
decimal? value;
|
||||
if (!TryParseNullableDecimal(CostText, out value)) { ValidationMessage = "Стоимость должна быть числом."; return; }
|
||||
if (!TryParseNullableDecimal(ExtraCostText, out value)) { ValidationMessage = "Дополнительная стоимость должна быть числом."; return; }
|
||||
if (!TryParseNullableDecimal(RushMarkupText, out value)) { ValidationMessage = "Наценка за срочность должна быть числом."; return; }
|
||||
if (!TryParseNullableDecimal(TimeNormHoursText, out value)) { ValidationMessage = "Норма времени должна быть числом."; return; }
|
||||
if (!TryParseNullableDecimal(NormDocHoursText, out value)) { ValidationMessage = "Норма времени по НД должна быть числом."; return; }
|
||||
var timeNormCode = Normalize(TimeNormCode);
|
||||
if (!string.IsNullOrWhiteSpace(timeNormCode) && timeNormCode.Length > TprmkDirectoryRules.TimeNormCodeMaxLength) { ValidationMessage = string.Format("Код нормы не должен превышать {0} символов.", TprmkDirectoryRules.TimeNormCodeMaxLength); return; }
|
||||
var verificationCode = Normalize(VerificationCode);
|
||||
if (!string.IsNullOrWhiteSpace(verificationCode) && verificationCode.Length > TprmkDirectoryRules.VerificationCodeMaxLength) { ValidationMessage = string.Format("Код поверки не должен превышать {0} символов.", TprmkDirectoryRules.VerificationCodeMaxLength); return; }
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(TprmkDirectoryItem item)
|
||||
{
|
||||
return item != null && item.Id != Id && item.VerificationTypeId == VerificationTypeId && item.OrganizationId == OrganizationId && item.GroupId == (GroupId > 0 ? (int?)GroupId : null) && item.PlaceId == (PlaceId > 0 ? (int?)PlaceId : null);
|
||||
});
|
||||
if (duplicate != null) { ValidationMessage = "Такой регламент МК уже существует для выбранного типоразмера."; return; }
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<DirectoryLookupItem> WithEmpty(IReadOnlyList<DirectoryLookupItem> source)
|
||||
{
|
||||
return new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(source ?? Array.Empty<DirectoryLookupItem>()).ToList();
|
||||
}
|
||||
|
||||
private static string Normalize(string value) { return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); }
|
||||
private static string ToString(decimal? value) { return value.HasValue ? value.Value.ToString("0.##") : string.Empty; }
|
||||
private static decimal? ParseNullableDecimal(string value) { decimal? parsed; return TryParseNullableDecimal(value, out parsed) ? parsed : (decimal?)null; }
|
||||
private static bool TryParseNullableDecimal(string value, out decimal? result)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) { result = null; return true; }
|
||||
decimal parsed;
|
||||
if (decimal.TryParse(value.Trim(), out parsed)) { result = parsed; return true; }
|
||||
result = null; return false;
|
||||
}
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null) handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
XLAB/TprzEditWindow.xaml
Normal file
52
XLAB/TprzEditWindow.xaml
Normal file
@@ -0,0 +1,52 @@
|
||||
<Window x:Class="XLAB.TprzEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="340"
|
||||
Width="620"
|
||||
MinHeight="320"
|
||||
MinWidth="580"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<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 RangeText, 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 AccuracyText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Комплектность МК" />
|
||||
<ComboBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding CompletenessItems}" SelectedValue="{Binding CompletenessId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="№ типоразмера по Госреестру" />
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" Text="{Binding RegistryTypeSizeNumber, UpdateSourceTrigger=PropertyChanged}" />
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Служебный код" />
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Margin="0,0,0,8" Text="{Binding ServiceCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Row="1" Margin="0,12,0,0">
|
||||
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/TprzEditWindow.xaml.cs
Normal file
20
XLAB/TprzEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TprzEditWindow : Window
|
||||
{
|
||||
internal TprzEditWindow(TprzEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
92
XLAB/TprzEditWindowViewModel.cs
Normal file
92
XLAB/TprzEditWindowViewModel.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TprzEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<TprzDirectoryItem> _existingItems;
|
||||
private string _accuracyText;
|
||||
private int _completenessId;
|
||||
private string _rangeText;
|
||||
private string _registryTypeSizeNumber;
|
||||
private string _serviceCode;
|
||||
private string _validationMessage;
|
||||
|
||||
public TprzEditWindowViewModel(TprzDirectoryItem seed, bool isNew, IReadOnlyList<TprzDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var source = seed ?? new TprzDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<TprzDirectoryItem>();
|
||||
Id = source.Id;
|
||||
TipsId = source.TipsId;
|
||||
IsNew = isNew;
|
||||
CompletenessItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }.Concat(service.LoadSpkmmkReferences()).ToList();
|
||||
RangeText = source.RangeText ?? string.Empty;
|
||||
AccuracyText = source.AccuracyText ?? string.Empty;
|
||||
CompletenessId = source.CompletenessId ?? 0;
|
||||
RegistryTypeSizeNumber = source.RegistryTypeSizeNumber ?? string.Empty;
|
||||
ServiceCode = source.ServiceCode ?? string.Empty;
|
||||
ConfirmCommand = new RelayCommand(Confirm);
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
}
|
||||
|
||||
public event EventHandler<bool?> CloseRequested;
|
||||
public ICommand CancelCommand { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> CompletenessItems { get; private set; }
|
||||
public ICommand ConfirmCommand { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
public bool IsNew { get; private set; }
|
||||
public int TipsId { get; private set; }
|
||||
public int CompletenessId { get { return _completenessId; } set { SetProperty(ref _completenessId, value); } }
|
||||
public string RangeText { get { return _rangeText; } set { SetProperty(ref _rangeText, value); } }
|
||||
public string AccuracyText { get { return _accuracyText; } set { SetProperty(ref _accuracyText, value); } }
|
||||
public string RegistryTypeSizeNumber { get { return _registryTypeSizeNumber; } set { SetProperty(ref _registryTypeSizeNumber, value); } }
|
||||
public string ServiceCode { get { return _serviceCode; } set { SetProperty(ref _serviceCode, value); } }
|
||||
public string Title { get { return IsNew ? "Новый типоразмер" : "Редактирование типоразмера"; } }
|
||||
public string ValidationMessage { get { return _validationMessage; } private set { SetProperty(ref _validationMessage, value); } }
|
||||
|
||||
public TprzDirectoryItem ToResult()
|
||||
{
|
||||
return new TprzDirectoryItem
|
||||
{
|
||||
Id = Id,
|
||||
TipsId = TipsId,
|
||||
CompletenessId = CompletenessId > 0 ? (int?)CompletenessId : null,
|
||||
RangeText = Normalize(RangeText),
|
||||
AccuracyText = Normalize(AccuracyText),
|
||||
RegistryTypeSizeNumber = Normalize(RegistryTypeSizeNumber),
|
||||
ServiceCode = Normalize(ServiceCode)
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter) { RaiseCloseRequested(false); }
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
var range = Normalize(RangeText);
|
||||
var accuracy = Normalize(AccuracyText);
|
||||
if (string.IsNullOrWhiteSpace(range)) { ValidationMessage = "Укажите диапазон."; return; }
|
||||
if (range.Length > TprzDirectoryRules.RangeTextMaxLength) { ValidationMessage = string.Format("Диапазон не должен превышать {0} символов.", TprzDirectoryRules.RangeTextMaxLength); return; }
|
||||
if (string.IsNullOrWhiteSpace(accuracy)) { ValidationMessage = "Укажите характеристику точности."; return; }
|
||||
if (accuracy.Length > TprzDirectoryRules.AccuracyTextMaxLength) { ValidationMessage = string.Format("Характеристика точности не должна превышать {0} символов.", TprzDirectoryRules.AccuracyTextMaxLength); return; }
|
||||
var registry = Normalize(RegistryTypeSizeNumber);
|
||||
if (!string.IsNullOrWhiteSpace(registry) && registry.Length > TprzDirectoryRules.RegistryTypeSizeNumberMaxLength) { ValidationMessage = string.Format("Номер по Госреестру не должен превышать {0} символов.", TprzDirectoryRules.RegistryTypeSizeNumberMaxLength); return; }
|
||||
var serviceCode = Normalize(ServiceCode);
|
||||
if (!string.IsNullOrWhiteSpace(serviceCode) && serviceCode.Length > TprzDirectoryRules.ServiceCodeMaxLength) { ValidationMessage = string.Format("Служебный код не должен превышать {0} символов.", TprzDirectoryRules.ServiceCodeMaxLength); return; }
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(TprzDirectoryItem item) { return item != null && item.Id != Id && string.Equals(Normalize(item.RangeText), range, StringComparison.OrdinalIgnoreCase) && string.Equals(Normalize(item.AccuracyText), accuracy, StringComparison.OrdinalIgnoreCase); });
|
||||
if (duplicate != null) { ValidationMessage = string.Format("Типоразмер с диапазоном \"{0}\" и характеристикой точности \"{1}\" уже существует.", range, accuracy); return; }
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private static string Normalize(string value) { return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); }
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null) handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
40
XLAB/TpvdklEditWindow.xaml
Normal file
40
XLAB/TpvdklEditWindow.xaml
Normal file
@@ -0,0 +1,40 @@
|
||||
<Window x:Class="XLAB.TpvdklEditWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="{Binding Title}"
|
||||
Height="220"
|
||||
Width="520"
|
||||
MinHeight="210"
|
||||
MinWidth="500"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид МК" />
|
||||
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding VerificationTypes}" SelectedValue="{Binding VerificationTypeId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид клейма" />
|
||||
<ComboBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding StampKinds}" SelectedValue="{Binding StampKindId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Row="1" Margin="0,12,0,0">
|
||||
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/TpvdklEditWindow.xaml.cs
Normal file
20
XLAB/TpvdklEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TpvdklEditWindow : Window
|
||||
{
|
||||
internal TpvdklEditWindow(TpvdklEditWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
XLAB/TpvdklEditWindowViewModel.cs
Normal file
66
XLAB/TpvdklEditWindowViewModel.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TpvdklEditWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly IReadOnlyList<TpvdklDirectoryItem> _existingItems;
|
||||
private int _stampKindId;
|
||||
private string _validationMessage;
|
||||
private int _verificationTypeId;
|
||||
|
||||
public TpvdklEditWindowViewModel(TpvdklDirectoryItem seed, bool isNew, IReadOnlyList<TpvdklDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var source = seed ?? new TpvdklDirectoryItem();
|
||||
_existingItems = existingItems ?? Array.Empty<TpvdklDirectoryItem>();
|
||||
Id = source.Id;
|
||||
TipsId = source.TipsId;
|
||||
IsNew = isNew;
|
||||
VerificationTypes = service.LoadSpvdmkReferences();
|
||||
StampKinds = service.LoadSpvdklReferences();
|
||||
VerificationTypeId = source.VerificationTypeId;
|
||||
StampKindId = source.StampKindId;
|
||||
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 IReadOnlyList<DirectoryLookupItem> VerificationTypes { get; private set; }
|
||||
public IReadOnlyList<DirectoryLookupItem> StampKinds { get; private set; }
|
||||
public int TipsId { get; private set; }
|
||||
public int VerificationTypeId { get { return _verificationTypeId; } set { SetProperty(ref _verificationTypeId, value); } }
|
||||
public int StampKindId { get { return _stampKindId; } set { SetProperty(ref _stampKindId, value); } }
|
||||
public string Title { get { return IsNew ? "Новый вид клейма" : "Редактирование вида клейма"; } }
|
||||
public string ValidationMessage { get { return _validationMessage; } private set { SetProperty(ref _validationMessage, value); } }
|
||||
|
||||
public TpvdklDirectoryItem ToResult()
|
||||
{
|
||||
return new TpvdklDirectoryItem { Id = Id, TipsId = TipsId, VerificationTypeId = VerificationTypeId, StampKindId = StampKindId };
|
||||
}
|
||||
|
||||
private void Cancel(object parameter) { RaiseCloseRequested(false); }
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
if (VerificationTypeId <= 0) { ValidationMessage = "Укажите вид МК."; return; }
|
||||
if (StampKindId <= 0) { ValidationMessage = "Укажите вид клейма."; return; }
|
||||
var duplicate = _existingItems.FirstOrDefault(delegate(TpvdklDirectoryItem item) { return item != null && item.Id != Id && item.VerificationTypeId == VerificationTypeId && item.StampKindId == StampKindId; });
|
||||
if (duplicate != null) { ValidationMessage = "Такая комбинация вида МК и вида клейма уже существует."; return; }
|
||||
ValidationMessage = string.Empty;
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private void RaiseCloseRequested(bool? dialogResult)
|
||||
{
|
||||
var handler = CloseRequested;
|
||||
if (handler != null) handler(this, dialogResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
XLAB/TpvdklWindow.xaml
Normal file
68
XLAB/TpvdklWindow.xaml
Normal file
@@ -0,0 +1,68 @@
|
||||
<Window x:Class="XLAB.TpvdklWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Виды клейм"
|
||||
Height="420"
|
||||
Width="720"
|
||||
MinHeight="380"
|
||||
MinWidth="660"
|
||||
Loaded="Window_Loaded"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0"
|
||||
Margin="0,0,0,8"
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding Caption}" />
|
||||
|
||||
<DataGrid Grid.Row="1"
|
||||
ItemsSource="{Binding Items}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить"
|
||||
Command="{Binding AddCommand}" />
|
||||
<MenuItem Header="Изменить"
|
||||
Command="{Binding EditCommand}" />
|
||||
<MenuItem Header="Удалить"
|
||||
Command="{Binding DeleteCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID"
|
||||
Width="70"
|
||||
Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Вид МК"
|
||||
Width="220"
|
||||
Binding="{Binding VerificationTypeName}" />
|
||||
<DataGridTextColumn Header="Вид клейма"
|
||||
Width="*"
|
||||
Binding="{Binding StampKindName}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Row="2"
|
||||
Margin="0,12,0,0"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="90"
|
||||
IsCancel="True"
|
||||
Content="Закрыть" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
33
XLAB/TpvdklWindow.xaml.cs
Normal file
33
XLAB/TpvdklWindow.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TpvdklWindow : Window
|
||||
{
|
||||
private readonly TpvdklWindowViewModel _viewModel;
|
||||
|
||||
internal TpvdklWindow(TipsDirectoryItem tipsItem, TypeSizeDirectoryService service)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = new TpvdklWindowViewModel(tipsItem, service, new TypeSizeDialogService(this));
|
||||
DataContext = _viewModel;
|
||||
}
|
||||
|
||||
private void DataGridRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var row = sender as DataGridRow;
|
||||
if (row != null)
|
||||
{
|
||||
row.IsSelected = true;
|
||||
row.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
145
XLAB/TpvdklWindowViewModel.cs
Normal file
145
XLAB/TpvdklWindowViewModel.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TpvdklWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly ITypeSizeDialogService _dialogService;
|
||||
private readonly TypeSizeDirectoryService _service;
|
||||
private bool _isBusy;
|
||||
private TpvdklDirectoryItem _selectedItem;
|
||||
|
||||
public TpvdklWindowViewModel(TipsDirectoryItem tipsItem, TypeSizeDirectoryService service, ITypeSizeDialogService dialogService)
|
||||
{
|
||||
TipsItem = tipsItem;
|
||||
_service = service;
|
||||
_dialogService = dialogService;
|
||||
Items = new ObservableCollection<TpvdklDirectoryItem>();
|
||||
AddCommand = new RelayCommand(delegate { AddAsync(); }, delegate { return !IsBusy; });
|
||||
EditCommand = new RelayCommand(delegate { EditAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
|
||||
DeleteCommand = new RelayCommand(delegate { DeleteAsync(); }, delegate { return !IsBusy && SelectedItem != null; });
|
||||
}
|
||||
|
||||
public ICommand AddCommand { get; private set; }
|
||||
public string Caption { get { return string.Format("Виды клейм для типа СИ: {0}", TipsItem == null ? string.Empty : TipsItem.TypeName); } }
|
||||
public ICommand DeleteCommand { get; private set; }
|
||||
public ICommand EditCommand { get; private set; }
|
||||
public ObservableCollection<TpvdklDirectoryItem> Items { get; private set; }
|
||||
public TipsDirectoryItem TipsItem { get; private set; }
|
||||
|
||||
public bool IsBusy
|
||||
{
|
||||
get { return _isBusy; }
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _isBusy, value))
|
||||
{
|
||||
((RelayCommand)AddCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)EditCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)DeleteCommand).RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TpvdklDirectoryItem SelectedItem
|
||||
{
|
||||
get { return _selectedItem; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedItem, value))
|
||||
{
|
||||
((RelayCommand)EditCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)DeleteCommand).RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
await RefreshCoreAsync(null);
|
||||
}
|
||||
|
||||
private void AddAsync()
|
||||
{
|
||||
var result = _dialogService.ShowTpvdklEditDialog(new TpvdklDirectoryItem { TipsId = TipsItem.Id }, true, Items.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutation(async delegate
|
||||
{
|
||||
var id = await Task.Run(delegate { return _service.AddTpvdklItem(result); });
|
||||
await RefreshCoreAsync(id);
|
||||
_dialogService.ShowInfo("Вид клейма добавлен.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditAsync()
|
||||
{
|
||||
if (SelectedItem == null) return;
|
||||
var result = _dialogService.ShowTpvdklEditDialog(new TpvdklDirectoryItem { Id = SelectedItem.Id, TipsId = SelectedItem.TipsId, VerificationTypeId = SelectedItem.VerificationTypeId, StampKindId = SelectedItem.StampKindId }, false, Items.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateTpvdklItem(result); });
|
||||
await RefreshCoreAsync(result.Id);
|
||||
_dialogService.ShowInfo("Вид клейма обновлён.");
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteAsync()
|
||||
{
|
||||
if (SelectedItem == null) return;
|
||||
var selected = SelectedItem;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить связь \"{0} / {1}\"?", selected.VerificationTypeName, selected.StampKindName))) return;
|
||||
RunMutation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.DeleteTpvdklItem(selected.Id); });
|
||||
await RefreshCoreAsync(null);
|
||||
_dialogService.ShowInfo("Вид клейма удалён.");
|
||||
});
|
||||
}
|
||||
|
||||
private async Task RefreshCoreAsync(int? idToSelect)
|
||||
{
|
||||
try
|
||||
{
|
||||
IsBusy = true;
|
||||
var items = await Task.Run(delegate { return _service.LoadTpvdklItems(TipsItem.Id); });
|
||||
Items.Clear();
|
||||
foreach (var item in items) Items.Add(item);
|
||||
SelectedItem = idToSelect.HasValue ? Items.FirstOrDefault(delegate(TpvdklDirectoryItem item) { return item.Id == idToSelect.Value; }) : Items.FirstOrDefault();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.ShowError(ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void RunMutation(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
115
XLAB/TypeSizeDialogService.cs
Normal file
115
XLAB/TypeSizeDialogService.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal interface ITypeSizeDialogService
|
||||
{
|
||||
TipsDirectoryItem ShowTipsEditDialog(TipsDirectoryItem seed, bool isNew, IReadOnlyList<TipsDirectoryItem> existingItems, TypeSizeDirectoryService service);
|
||||
|
||||
TprzDirectoryItem ShowTprzEditDialog(TprzDirectoryItem seed, bool isNew, IReadOnlyList<TprzDirectoryItem> existingItems, TypeSizeDirectoryService service);
|
||||
|
||||
TprmcpDirectoryItem ShowTprmcpEditDialog(TprmcpDirectoryItem seed, bool isNew, IReadOnlyList<TprmcpDirectoryItem> existingItems, TypeSizeDirectoryService service);
|
||||
|
||||
TprmkDirectoryItem ShowTprmkEditDialog(TprmkDirectoryItem seed, bool isNew, IReadOnlyList<TprmkDirectoryItem> existingItems, TypeSizeDirectoryService service);
|
||||
|
||||
TpvdklDirectoryItem ShowTpvdklEditDialog(TpvdklDirectoryItem seed, bool isNew, IReadOnlyList<TpvdklDirectoryItem> existingItems, TypeSizeDirectoryService service);
|
||||
|
||||
void ShowTpvdklManagerDialog(TipsDirectoryItem tipsItem, TypeSizeDirectoryService service);
|
||||
|
||||
bool Confirm(string message);
|
||||
|
||||
void ShowError(string message);
|
||||
|
||||
void ShowInfo(string message);
|
||||
|
||||
void ShowWarning(string message);
|
||||
}
|
||||
|
||||
internal sealed class TypeSizeDialogService : ITypeSizeDialogService
|
||||
{
|
||||
private readonly Window _owner;
|
||||
|
||||
public TypeSizeDialogService(Window owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
|
||||
public TipsDirectoryItem ShowTipsEditDialog(TipsDirectoryItem seed, bool isNew, IReadOnlyList<TipsDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var viewModel = new TipsEditWindowViewModel(seed, isNew, existingItems, service);
|
||||
var window = new TipsEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public TprzDirectoryItem ShowTprzEditDialog(TprzDirectoryItem seed, bool isNew, IReadOnlyList<TprzDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var viewModel = new TprzEditWindowViewModel(seed, isNew, existingItems, service);
|
||||
var window = new TprzEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public TprmcpDirectoryItem ShowTprmcpEditDialog(TprmcpDirectoryItem seed, bool isNew, IReadOnlyList<TprmcpDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var viewModel = new TprmcpEditWindowViewModel(seed, isNew, existingItems, service);
|
||||
var window = new TprmcpEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public TprmkDirectoryItem ShowTprmkEditDialog(TprmkDirectoryItem seed, bool isNew, IReadOnlyList<TprmkDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var viewModel = new TprmkEditWindowViewModel(seed, isNew, existingItems, service);
|
||||
var window = new TprmkEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public TpvdklDirectoryItem ShowTpvdklEditDialog(TpvdklDirectoryItem seed, bool isNew, IReadOnlyList<TpvdklDirectoryItem> existingItems, TypeSizeDirectoryService service)
|
||||
{
|
||||
var viewModel = new TpvdklEditWindowViewModel(seed, isNew, existingItems, service);
|
||||
var window = new TpvdklEditWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||
}
|
||||
|
||||
public void ShowTpvdklManagerDialog(TipsDirectoryItem tipsItem, TypeSizeDirectoryService service)
|
||||
{
|
||||
var window = new TpvdklWindow(tipsItem, service);
|
||||
window.Owner = _owner;
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
public bool Confirm(string message)
|
||||
{
|
||||
return MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;
|
||||
}
|
||||
|
||||
public void ShowError(string message)
|
||||
{
|
||||
MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
|
||||
public void ShowInfo(string message)
|
||||
{
|
||||
MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
public void ShowWarning(string message)
|
||||
{
|
||||
MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
191
XLAB/TypeSizeDirectoryModels.cs
Normal file
191
XLAB/TypeSizeDirectoryModels.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public sealed class DirectoryLookupItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TipsDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int MeasurementAreaId { get; set; }
|
||||
|
||||
public string MeasurementAreaName { get; set; }
|
||||
|
||||
public int InstrumentNameId { get; set; }
|
||||
|
||||
public string InstrumentName { get; set; }
|
||||
|
||||
public int? CategoryId { get; set; }
|
||||
|
||||
public string CategoryName { get; set; }
|
||||
|
||||
public int? DesignId { get; set; }
|
||||
|
||||
public string DesignName { get; set; }
|
||||
|
||||
public string TypeName { get; set; }
|
||||
|
||||
public int? ServiceLifeYears { get; set; }
|
||||
|
||||
public int? RegistryPeriodMonths { get; set; }
|
||||
|
||||
public string RegistryTypeNumber { get; set; }
|
||||
|
||||
public int? VniimsTypeCode { get; set; }
|
||||
|
||||
public string MetrControlCode { get; set; }
|
||||
|
||||
public string Notes { get; set; }
|
||||
|
||||
public bool? IsSpecialPurpose { get; set; }
|
||||
|
||||
public bool? IsMkPrimaryOnly { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TprzDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int TipsId { get; set; }
|
||||
|
||||
public int? CompletenessId { get; set; }
|
||||
|
||||
public string CompletenessName { get; set; }
|
||||
|
||||
public string RangeText { get; set; }
|
||||
|
||||
public string AccuracyText { get; set; }
|
||||
|
||||
public int? VniimsTypeSizeCode { get; set; }
|
||||
|
||||
public string RegistryTypeSizeNumber { get; set; }
|
||||
|
||||
public string ServiceCode { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TprmcpDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int TypeSizeId { get; set; }
|
||||
|
||||
public int? CycleId { get; set; }
|
||||
|
||||
public string CycleName { get; set; }
|
||||
|
||||
public int? GroupId { get; set; }
|
||||
|
||||
public string GroupName { get; set; }
|
||||
|
||||
public int PeriodMonths { get; set; }
|
||||
|
||||
public string Comment { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TprmkDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int TypeSizeId { get; set; }
|
||||
|
||||
public int VerificationTypeId { get; set; }
|
||||
|
||||
public string VerificationTypeName { get; set; }
|
||||
|
||||
public int OrganizationId { get; set; }
|
||||
|
||||
public string OrganizationName { get; set; }
|
||||
|
||||
public int? QualificationId { get; set; }
|
||||
|
||||
public string QualificationName { get; set; }
|
||||
|
||||
public int? GroupId { get; set; }
|
||||
|
||||
public string GroupName { get; set; }
|
||||
|
||||
public int? PlaceId { get; set; }
|
||||
|
||||
public string PlaceName { get; set; }
|
||||
|
||||
public decimal? Cost { get; set; }
|
||||
|
||||
public decimal? ExtraCost { get; set; }
|
||||
|
||||
public decimal? RushMarkup { get; set; }
|
||||
|
||||
public decimal? TimeNormHours { get; set; }
|
||||
|
||||
public string TimeNormCode { get; set; }
|
||||
|
||||
public int VerifierCount { get; set; }
|
||||
|
||||
public string VerificationCode { get; set; }
|
||||
|
||||
public decimal? NormDocHours { get; set; }
|
||||
}
|
||||
|
||||
public sealed class TpvdklDirectoryItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int TipsId { get; set; }
|
||||
|
||||
public int VerificationTypeId { get; set; }
|
||||
|
||||
public string VerificationTypeName { get; set; }
|
||||
|
||||
public int StampKindId { get; set; }
|
||||
|
||||
public string StampKindName { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class DirectoryDeleteResult
|
||||
{
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public string WarningMessage { get; set; }
|
||||
}
|
||||
|
||||
internal static class TipsDirectoryRules
|
||||
{
|
||||
public const int TypeNameMaxLength = 160;
|
||||
|
||||
public const int RegistryTypeNumberMaxLength = 8;
|
||||
|
||||
public const int MetrControlCodeMaxLength = 11;
|
||||
}
|
||||
|
||||
internal static class TprzDirectoryRules
|
||||
{
|
||||
public const int RangeTextMaxLength = 160;
|
||||
|
||||
public const int AccuracyTextMaxLength = 140;
|
||||
|
||||
public const int RegistryTypeSizeNumberMaxLength = 8;
|
||||
|
||||
public const int ServiceCodeMaxLength = 10;
|
||||
}
|
||||
|
||||
internal static class TprmcpDirectoryRules
|
||||
{
|
||||
}
|
||||
|
||||
internal static class TprmkDirectoryRules
|
||||
{
|
||||
public const int TimeNormCodeMaxLength = 7;
|
||||
|
||||
public const int VerificationCodeMaxLength = 15;
|
||||
}
|
||||
}
|
||||
1889
XLAB/TypeSizeDirectoryService.cs
Normal file
1889
XLAB/TypeSizeDirectoryService.cs
Normal file
File diff suppressed because it is too large
Load Diff
199
XLAB/TypeSizeDirectoryWindow.xaml
Normal file
199
XLAB/TypeSizeDirectoryWindow.xaml
Normal file
@@ -0,0 +1,199 @@
|
||||
<Window x:Class="XLAB.TypeSizeDirectoryWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Типоразмеры СИ"
|
||||
Height="900"
|
||||
Width="1500"
|
||||
MinHeight="760"
|
||||
MinWidth="1220"
|
||||
Loaded="Window_Loaded"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="2.1*" />
|
||||
<RowDefinition Height="2*" />
|
||||
<RowDefinition Height="2.1*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0"
|
||||
Margin="0,0,0,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<DockPanel Grid.Row="0">
|
||||
<Button DockPanel.Dock="Right"
|
||||
Width="110"
|
||||
Margin="12,0,0,0"
|
||||
Command="{Binding RefreshCommand}"
|
||||
Content="Обновить" />
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Поиск по TIPS и TPRZ:" />
|
||||
<TextBox Width="360"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Margin="0,8,0,0"
|
||||
Foreground="DimGray"
|
||||
Text="{Binding StatusText}" />
|
||||
</Grid>
|
||||
|
||||
<GroupBox Grid.Row="1"
|
||||
Header="Типы СИ (TIPS)">
|
||||
<DataGrid ItemsSource="{Binding TipsItems}"
|
||||
SelectedItem="{Binding SelectedTips, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить"
|
||||
Command="{Binding AddTipsCommand}" />
|
||||
<MenuItem Header="Изменить"
|
||||
Command="{Binding EditTipsCommand}" />
|
||||
<MenuItem Header="Удалить"
|
||||
Command="{Binding DeleteTipsCommand}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Виды клейм..."
|
||||
Command="{Binding ManageTpvdklCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Width="70" Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Область измерений" Width="260" Binding="{Binding MeasurementAreaName}" />
|
||||
<DataGridTextColumn Header="Наименование типа СИ" Width="260" Binding="{Binding InstrumentName}" />
|
||||
<DataGridTextColumn Header="Тип СИ" Width="*" Binding="{Binding TypeName}" />
|
||||
<DataGridTextColumn Header="Категория" Width="180" Binding="{Binding CategoryName}" />
|
||||
<DataGridTextColumn Header="Исполнение" Width="160" Binding="{Binding DesignName}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="2"
|
||||
Margin="0,12,0,0"
|
||||
Header="Типоразмеры СИ (TPRZ)">
|
||||
<DataGrid ItemsSource="{Binding TprzItems}"
|
||||
SelectedItem="{Binding SelectedTprz, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить" Command="{Binding AddTprzCommand}" />
|
||||
<MenuItem Header="Изменить" Command="{Binding EditTprzCommand}" />
|
||||
<MenuItem Header="Удалить" Command="{Binding DeleteTprzCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Width="70" Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Диапазон" Width="*" Binding="{Binding RangeText}" />
|
||||
<DataGridTextColumn Header="Х-ка точности" Width="260" Binding="{Binding AccuracyText}" />
|
||||
<DataGridTextColumn Header="Комплектность МК" Width="220" Binding="{Binding CompletenessName}" />
|
||||
<DataGridTextColumn Header="№ Госреестра" Width="130" Binding="{Binding RegistryTypeSizeNumber}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="3"
|
||||
Margin="0,12,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="12" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<GroupBox Grid.Column="0"
|
||||
Header="Регламент МК для типоразмера СИ (TPRMK)">
|
||||
<DataGrid ItemsSource="{Binding TprmkItems}"
|
||||
SelectedItem="{Binding SelectedTprmk, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить" Command="{Binding AddTprmkCommand}" />
|
||||
<MenuItem Header="Изменить" Command="{Binding EditTprmkCommand}" />
|
||||
<MenuItem Header="Удалить" Command="{Binding DeleteTprmkCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Width="70" Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Вид МК" Width="130" Binding="{Binding VerificationTypeName}" />
|
||||
<DataGridTextColumn Header="Организация" Width="*" Binding="{Binding OrganizationName}" />
|
||||
<DataGridTextColumn Header="Место МК" Width="170" Binding="{Binding PlaceName}" />
|
||||
<DataGridTextColumn Header="Группа СИ" Width="220" Binding="{Binding GroupName}" />
|
||||
<DataGridTextColumn Header="Кол-во повер." Width="110" Binding="{Binding VerifierCount}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Column="2"
|
||||
Header="Циклы и периоды МК (TPRMCP)">
|
||||
<DataGrid ItemsSource="{Binding TprmcpItems}"
|
||||
SelectedItem="{Binding SelectedTprmcp, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.ContextMenu>
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить" Command="{Binding AddTprmcpCommand}" />
|
||||
<MenuItem Header="Изменить" Command="{Binding EditTprmcpCommand}" />
|
||||
<MenuItem Header="Удалить" Command="{Binding DeleteTprmcpCommand}" />
|
||||
</ContextMenu>
|
||||
</DataGrid.ContextMenu>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Width="70" Binding="{Binding Id}" />
|
||||
<DataGridTextColumn Header="Цикл МК" Width="180" Binding="{Binding CycleName}" />
|
||||
<DataGridTextColumn Header="Группа СИ" Width="*" Binding="{Binding GroupName}" />
|
||||
<DataGridTextColumn Header="Период, мес." Width="110" Binding="{Binding PeriodMonths}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="4"
|
||||
Margin="0,12,0,0"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="90"
|
||||
IsCancel="True"
|
||||
Content="Закрыть" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
33
XLAB/TypeSizeDirectoryWindow.xaml.cs
Normal file
33
XLAB/TypeSizeDirectoryWindow.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class TypeSizeDirectoryWindow : Window
|
||||
{
|
||||
private readonly TypeSizeDirectoryWindowViewModel _viewModel;
|
||||
|
||||
public TypeSizeDirectoryWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = new TypeSizeDirectoryWindowViewModel(new TypeSizeDirectoryService(), new TypeSizeDialogService(this));
|
||||
DataContext = _viewModel;
|
||||
}
|
||||
|
||||
private void DataGridRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
var row = sender as DataGridRow;
|
||||
if (row != null)
|
||||
{
|
||||
row.IsSelected = true;
|
||||
row.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.InitializeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
664
XLAB/TypeSizeDirectoryWindowViewModel.cs
Normal file
664
XLAB/TypeSizeDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,664 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class TypeSizeDirectoryWindowViewModel : ObservableObject
|
||||
{
|
||||
private readonly ITypeSizeDialogService _dialogService;
|
||||
private readonly TypeSizeDirectoryService _service;
|
||||
private readonly Dictionary<int, List<TprzDirectoryItem>> _tprzSearchIndex;
|
||||
private List<TipsDirectoryItem> _tipsCache;
|
||||
private List<TprzDirectoryItem> _currentTprzCache;
|
||||
private bool _isBusy;
|
||||
private string _searchText;
|
||||
private TipsDirectoryItem _selectedTips;
|
||||
private TprmcpDirectoryItem _selectedTprmcp;
|
||||
private TprmkDirectoryItem _selectedTprmk;
|
||||
private TprzDirectoryItem _selectedTprz;
|
||||
private string _statusText;
|
||||
|
||||
public TypeSizeDirectoryWindowViewModel(TypeSizeDirectoryService service, ITypeSizeDialogService dialogService)
|
||||
{
|
||||
_service = service;
|
||||
_dialogService = dialogService;
|
||||
_tipsCache = new List<TipsDirectoryItem>();
|
||||
_currentTprzCache = new List<TprzDirectoryItem>();
|
||||
_tprzSearchIndex = new Dictionary<int, List<TprzDirectoryItem>>();
|
||||
|
||||
TipsItems = new ObservableCollection<TipsDirectoryItem>();
|
||||
TprzItems = new ObservableCollection<TprzDirectoryItem>();
|
||||
TprmcpItems = new ObservableCollection<TprmcpDirectoryItem>();
|
||||
TprmkItems = new ObservableCollection<TprmkDirectoryItem>();
|
||||
|
||||
AddTipsCommand = new RelayCommand(delegate { AddTipsAsync(); }, delegate { return !IsBusy; });
|
||||
EditTipsCommand = new RelayCommand(delegate { EditTipsAsync(); }, delegate { return !IsBusy && SelectedTips != null; });
|
||||
DeleteTipsCommand = new RelayCommand(delegate { DeleteTipsAsync(); }, delegate { return !IsBusy && SelectedTips != null; });
|
||||
ManageTpvdklCommand = new RelayCommand(delegate { ManageTpvdkl(); }, delegate { return !IsBusy && SelectedTips != null; });
|
||||
AddTprzCommand = new RelayCommand(delegate { AddTprzAsync(); }, delegate { return !IsBusy && SelectedTips != null; });
|
||||
EditTprzCommand = new RelayCommand(delegate { EditTprzAsync(); }, delegate { return !IsBusy && SelectedTprz != null; });
|
||||
DeleteTprzCommand = new RelayCommand(delegate { DeleteTprzAsync(); }, delegate { return !IsBusy && SelectedTprz != null; });
|
||||
AddTprmcpCommand = new RelayCommand(delegate { AddTprmcpAsync(); }, delegate { return !IsBusy && SelectedTprz != null; });
|
||||
EditTprmcpCommand = new RelayCommand(delegate { EditTprmcpAsync(); }, delegate { return !IsBusy && SelectedTprmcp != null; });
|
||||
DeleteTprmcpCommand = new RelayCommand(delegate { DeleteTprmcpAsync(); }, delegate { return !IsBusy && SelectedTprmcp != null; });
|
||||
AddTprmkCommand = new RelayCommand(delegate { AddTprmkAsync(); }, delegate { return !IsBusy && SelectedTprz != null; });
|
||||
EditTprmkCommand = new RelayCommand(delegate { EditTprmkAsync(); }, delegate { return !IsBusy && SelectedTprmk != null; });
|
||||
DeleteTprmkCommand = new RelayCommand(delegate { DeleteTprmkAsync(); }, delegate { return !IsBusy && SelectedTprmk != null; });
|
||||
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
|
||||
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
public ObservableCollection<TipsDirectoryItem> TipsItems { get; private set; }
|
||||
public ObservableCollection<TprzDirectoryItem> TprzItems { get; private set; }
|
||||
public ObservableCollection<TprmcpDirectoryItem> TprmcpItems { get; private set; }
|
||||
public ObservableCollection<TprmkDirectoryItem> TprmkItems { get; private set; }
|
||||
public ICommand AddTipsCommand { get; private set; }
|
||||
public ICommand EditTipsCommand { get; private set; }
|
||||
public ICommand DeleteTipsCommand { get; private set; }
|
||||
public ICommand ManageTpvdklCommand { get; private set; }
|
||||
public ICommand AddTprzCommand { get; private set; }
|
||||
public ICommand EditTprzCommand { get; private set; }
|
||||
public ICommand DeleteTprzCommand { get; private set; }
|
||||
public ICommand AddTprmcpCommand { get; private set; }
|
||||
public ICommand EditTprmcpCommand { get; private set; }
|
||||
public ICommand DeleteTprmcpCommand { get; private set; }
|
||||
public ICommand AddTprmkCommand { get; private set; }
|
||||
public ICommand EditTprmkCommand { get; private set; }
|
||||
public ICommand DeleteTprmkCommand { get; private set; }
|
||||
public ICommand RefreshCommand { get; private set; }
|
||||
|
||||
public bool IsBusy
|
||||
{
|
||||
get { return _isBusy; }
|
||||
private set
|
||||
{
|
||||
if (SetProperty(ref _isBusy, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TipsDirectoryItem SelectedTips
|
||||
{
|
||||
get { return _selectedTips; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedTips, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
LoadTprzForSelection();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TprzDirectoryItem SelectedTprz
|
||||
{
|
||||
get { return _selectedTprz; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedTprz, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
LoadLeafTablesForSelection();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TprmcpDirectoryItem SelectedTprmcp
|
||||
{
|
||||
get { return _selectedTprmcp; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedTprmcp, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TprmkDirectoryItem SelectedTprmk
|
||||
{
|
||||
get { return _selectedTprmk; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedTprmk, value))
|
||||
{
|
||||
RaiseCommandStates();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string StatusText
|
||||
{
|
||||
get { return _statusText; }
|
||||
private set { SetProperty(ref _statusText, value); }
|
||||
}
|
||||
|
||||
public string SearchText
|
||||
{
|
||||
get { return _searchText; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchText, value))
|
||||
{
|
||||
ApplySearchFilter();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
await ExecuteBusyOperationAsync(async delegate { await RefreshTipsCoreAsync(null); });
|
||||
}
|
||||
|
||||
private void AddTipsAsync()
|
||||
{
|
||||
var result = _dialogService.ShowTipsEditDialog(new TipsDirectoryItem(), true, _tipsCache.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddTipsItem(result); });
|
||||
await RefreshTipsCoreAsync(createdId);
|
||||
_dialogService.ShowInfo("Запись TIPS добавлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditTipsAsync()
|
||||
{
|
||||
if (SelectedTips == null) return;
|
||||
var result = _dialogService.ShowTipsEditDialog(CloneTips(SelectedTips), false, _tipsCache.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateTipsItem(result); });
|
||||
await RefreshTipsCoreAsync(result.Id);
|
||||
_dialogService.ShowInfo("Запись TIPS обновлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteTipsAsync()
|
||||
{
|
||||
if (SelectedTips == null) return;
|
||||
var selected = SelectedTips;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить тип СИ \"{0}\"?", selected.TypeName))) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var result = await Task.Run(delegate { return _service.DeleteTipsItem(selected.Id); });
|
||||
if (!result.IsDeleted) { _dialogService.ShowWarning(result.WarningMessage); return; }
|
||||
await RefreshTipsCoreAsync(null);
|
||||
_dialogService.ShowInfo("Запись TIPS удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void ManageTpvdkl()
|
||||
{
|
||||
if (SelectedTips != null)
|
||||
{
|
||||
_dialogService.ShowTpvdklManagerDialog(CloneTips(SelectedTips), _service);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddTprzAsync()
|
||||
{
|
||||
if (SelectedTips == null) return;
|
||||
var result = _dialogService.ShowTprzEditDialog(new TprzDirectoryItem { TipsId = SelectedTips.Id }, true, _currentTprzCache.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddTprzItem(result); });
|
||||
await RefreshTipsCoreAsync(result.TipsId);
|
||||
if (SelectedTips != null && SelectedTips.Id == result.TipsId && SelectedTprz != null && SelectedTprz.Id != createdId)
|
||||
{
|
||||
await RefreshTprzCoreAsync(result.TipsId, createdId);
|
||||
}
|
||||
_dialogService.ShowInfo("Запись TPRZ добавлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditTprzAsync()
|
||||
{
|
||||
if (SelectedTprz == null) return;
|
||||
var result = _dialogService.ShowTprzEditDialog(CloneTprz(SelectedTprz), false, _currentTprzCache.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateTprzItem(result); });
|
||||
await RefreshTipsCoreAsync(result.TipsId);
|
||||
if (SelectedTips != null && SelectedTips.Id == result.TipsId && SelectedTprz != null && SelectedTprz.Id != result.Id)
|
||||
{
|
||||
await RefreshTprzCoreAsync(result.TipsId, result.Id);
|
||||
}
|
||||
_dialogService.ShowInfo("Запись TPRZ обновлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteTprzAsync()
|
||||
{
|
||||
if (SelectedTprz == null) return;
|
||||
var selected = SelectedTprz;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить типоразмер \"{0}\"?", selected.RangeText))) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var result = await Task.Run(delegate { return _service.DeleteTprzItem(selected.Id); });
|
||||
if (!result.IsDeleted) { _dialogService.ShowWarning(result.WarningMessage); return; }
|
||||
await RefreshTipsCoreAsync(selected.TipsId);
|
||||
_dialogService.ShowInfo("Запись TPRZ удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void AddTprmcpAsync()
|
||||
{
|
||||
if (SelectedTprz == null) return;
|
||||
if (TprmkItems.Count == 0)
|
||||
{
|
||||
_dialogService.ShowWarning("Сначала заполните таблицу TPRMK для выбранного типоразмера, затем добавляйте цикл и период в TPRMCP.");
|
||||
return;
|
||||
}
|
||||
|
||||
var result = _dialogService.ShowTprmcpEditDialog(new TprmcpDirectoryItem { TypeSizeId = SelectedTprz.Id }, true, TprmcpItems.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddTprmcpItem(result); });
|
||||
await RefreshLeafTablesCoreAsync(SelectedTprz.Id, createdId, null);
|
||||
_dialogService.ShowInfo("Запись TPRMCP добавлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditTprmcpAsync()
|
||||
{
|
||||
if (SelectedTprmcp == null) return;
|
||||
var result = _dialogService.ShowTprmcpEditDialog(CloneTprmcp(SelectedTprmcp), false, TprmcpItems.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateTprmcpItem(result); });
|
||||
await RefreshLeafTablesCoreAsync(result.TypeSizeId, result.Id, null);
|
||||
_dialogService.ShowInfo("Запись TPRMCP обновлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteTprmcpAsync()
|
||||
{
|
||||
if (SelectedTprmcp == null) return;
|
||||
var selected = SelectedTprmcp;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить период МК \"{0}\" мес.?", selected.PeriodMonths))) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var result = await Task.Run(delegate { return _service.DeleteTprmcpItem(selected.Id); });
|
||||
if (!result.IsDeleted) { _dialogService.ShowWarning(result.WarningMessage); return; }
|
||||
await RefreshLeafTablesCoreAsync(selected.TypeSizeId, null, null);
|
||||
_dialogService.ShowInfo("Запись TPRMCP удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void AddTprmkAsync()
|
||||
{
|
||||
if (SelectedTprz == null) return;
|
||||
var result = _dialogService.ShowTprmkEditDialog(new TprmkDirectoryItem { TypeSizeId = SelectedTprz.Id }, true, TprmkItems.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var createdId = await Task.Run(delegate { return _service.AddTprmkItem(result); });
|
||||
await RefreshLeafTablesCoreAsync(SelectedTprz.Id, null, createdId);
|
||||
_dialogService.ShowInfo("Запись TPRMK добавлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void EditTprmkAsync()
|
||||
{
|
||||
if (SelectedTprmk == null) return;
|
||||
var result = _dialogService.ShowTprmkEditDialog(CloneTprmk(SelectedTprmk), false, TprmkItems.ToList(), _service);
|
||||
if (result == null) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
await Task.Run(delegate { _service.UpdateTprmkItem(result); });
|
||||
await RefreshLeafTablesCoreAsync(result.TypeSizeId, null, result.Id);
|
||||
_dialogService.ShowInfo("Запись TPRMK обновлена.");
|
||||
});
|
||||
}
|
||||
|
||||
private void DeleteTprmkAsync()
|
||||
{
|
||||
if (SelectedTprmk == null) return;
|
||||
var selected = SelectedTprmk;
|
||||
if (!_dialogService.Confirm(string.Format("Удалить регламент МК \"{0}\"?", selected.VerificationTypeName))) return;
|
||||
RunMutationOperation(async delegate
|
||||
{
|
||||
var result = await Task.Run(delegate { return _service.DeleteTprmkItem(selected.Id); });
|
||||
if (!result.IsDeleted) { _dialogService.ShowWarning(result.WarningMessage); return; }
|
||||
await RefreshLeafTablesCoreAsync(selected.TypeSizeId, null, null);
|
||||
_dialogService.ShowInfo("Запись TPRMK удалена.");
|
||||
});
|
||||
}
|
||||
|
||||
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 async Task RefreshTipsCoreAsync(int? tipsIdToSelect)
|
||||
{
|
||||
var currentTipsId = SelectedTips == null ? (int?)null : SelectedTips.Id;
|
||||
var currentTprzId = SelectedTprz == null ? (int?)null : SelectedTprz.Id;
|
||||
var tipsTask = Task.Run(delegate { return _service.LoadTipsItems(); });
|
||||
var tprzSearchTask = Task.Run(delegate { return _service.LoadTprzSearchItems(); });
|
||||
await Task.WhenAll(tipsTask, tprzSearchTask);
|
||||
|
||||
_tipsCache = tipsTask.Result.ToList();
|
||||
_tprzSearchIndex.Clear();
|
||||
foreach (var group in tprzSearchTask.Result.GroupBy(delegate(TprzDirectoryItem item) { return item.TipsId; }))
|
||||
{
|
||||
_tprzSearchIndex[group.Key] = group.ToList();
|
||||
}
|
||||
|
||||
ApplyTipsFilter(tipsIdToSelect.HasValue ? tipsIdToSelect : currentTipsId);
|
||||
if (SelectedTips == null)
|
||||
{
|
||||
_currentTprzCache = new List<TprzDirectoryItem>();
|
||||
TprzItems.Clear();
|
||||
TprmcpItems.Clear();
|
||||
TprmkItems.Clear();
|
||||
SelectedTprz = null;
|
||||
SelectedTprmcp = null;
|
||||
SelectedTprmk = null;
|
||||
UpdateStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
var tprzIdToSelect = currentTipsId.HasValue && currentTipsId.Value == SelectedTips.Id ? currentTprzId : null;
|
||||
await RefreshTprzCoreAsync(SelectedTips.Id, tprzIdToSelect);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async Task RefreshTprzCoreAsync(int tipsId, int? tprzIdToSelect)
|
||||
{
|
||||
var currentTprzId = SelectedTprz == null ? (int?)null : SelectedTprz.Id;
|
||||
var currentTprmcpId = SelectedTprmcp == null ? (int?)null : SelectedTprmcp.Id;
|
||||
var currentTprmkId = SelectedTprmk == null ? (int?)null : SelectedTprmk.Id;
|
||||
var rows = await Task.Run(delegate { return _service.LoadTprzItems(tipsId); });
|
||||
_currentTprzCache = rows.ToList();
|
||||
_tprzSearchIndex[tipsId] = _currentTprzCache.ToList();
|
||||
ApplyTprzFilter(tprzIdToSelect.HasValue ? tprzIdToSelect : currentTprzId);
|
||||
if (SelectedTprz == null)
|
||||
{
|
||||
TprmcpItems.Clear();
|
||||
TprmkItems.Clear();
|
||||
SelectedTprmcp = null;
|
||||
SelectedTprmk = null;
|
||||
UpdateStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
var tprmcpIdToSelect = currentTprzId.HasValue && currentTprzId.Value == SelectedTprz.Id ? currentTprmcpId : null;
|
||||
var tprmkIdToSelect = currentTprzId.HasValue && currentTprzId.Value == SelectedTprz.Id ? currentTprmkId : null;
|
||||
await RefreshLeafTablesCoreAsync(SelectedTprz.Id, tprmcpIdToSelect, tprmkIdToSelect);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private async Task RefreshLeafTablesCoreAsync(int typeSizeId, int? tprmcpIdToSelect, int? tprmkIdToSelect)
|
||||
{
|
||||
var tprmkTask = Task.Run(delegate { return _service.LoadTprmkItems(typeSizeId); });
|
||||
var tprmcpTask = Task.Run(delegate { return _service.LoadTprmcpItems(typeSizeId); });
|
||||
await Task.WhenAll(tprmcpTask, tprmkTask);
|
||||
TprmkItems.Clear();
|
||||
foreach (var item in tprmkTask.Result) TprmkItems.Add(item);
|
||||
SelectedTprmk = tprmkIdToSelect.HasValue ? TprmkItems.FirstOrDefault(delegate(TprmkDirectoryItem item) { return item.Id == tprmkIdToSelect.Value; }) : TprmkItems.FirstOrDefault();
|
||||
TprmcpItems.Clear();
|
||||
foreach (var item in tprmcpTask.Result) TprmcpItems.Add(item);
|
||||
SelectedTprmcp = tprmcpIdToSelect.HasValue ? TprmcpItems.FirstOrDefault(delegate(TprmcpDirectoryItem item) { return item.Id == tprmcpIdToSelect.Value; }) : TprmcpItems.FirstOrDefault();
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void ApplySearchFilter()
|
||||
{
|
||||
if (IsBusy)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var previousTipsId = SelectedTips == null ? (int?)null : SelectedTips.Id;
|
||||
var previousTprzId = SelectedTprz == null ? (int?)null : SelectedTprz.Id;
|
||||
ApplyTipsFilter(previousTipsId);
|
||||
|
||||
if (SelectedTips == null)
|
||||
{
|
||||
_currentTprzCache = new List<TprzDirectoryItem>();
|
||||
TprzItems.Clear();
|
||||
TprmcpItems.Clear();
|
||||
TprmkItems.Clear();
|
||||
SelectedTprz = null;
|
||||
SelectedTprmcp = null;
|
||||
SelectedTprmk = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousTipsId.HasValue && previousTipsId.Value == SelectedTips.Id)
|
||||
{
|
||||
ApplyTprzFilter(previousTprzId);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyTipsFilter(int? preferredTipsId)
|
||||
{
|
||||
var filteredItems = _tipsCache
|
||||
.Where(delegate(TipsDirectoryItem item) { return MatchesTipsSearch(item); })
|
||||
.ToList();
|
||||
|
||||
TipsItems.Clear();
|
||||
foreach (var item in filteredItems)
|
||||
{
|
||||
TipsItems.Add(item);
|
||||
}
|
||||
|
||||
SelectedTips = preferredTipsId.HasValue
|
||||
? TipsItems.FirstOrDefault(delegate(TipsDirectoryItem item) { return item.Id == preferredTipsId.Value; })
|
||||
: TipsItems.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void ApplyTprzFilter(int? preferredTprzId)
|
||||
{
|
||||
var selectedTips = SelectedTips;
|
||||
var showAllTypeSizes = selectedTips != null && MatchesTipsOwnFields(selectedTips);
|
||||
var filteredItems = _currentTprzCache
|
||||
.Where(delegate(TprzDirectoryItem item) { return showAllTypeSizes || MatchesTprzOwnFields(item); })
|
||||
.ToList();
|
||||
|
||||
TprzItems.Clear();
|
||||
foreach (var item in filteredItems)
|
||||
{
|
||||
TprzItems.Add(item);
|
||||
}
|
||||
|
||||
SelectedTprz = preferredTprzId.HasValue
|
||||
? TprzItems.FirstOrDefault(delegate(TprzDirectoryItem item) { return item.Id == preferredTprzId.Value; })
|
||||
: TprzItems.FirstOrDefault();
|
||||
}
|
||||
|
||||
private bool MatchesTipsSearch(TipsDirectoryItem item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsSearchEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (MatchesTipsOwnFields(item))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
List<TprzDirectoryItem> typeSizes;
|
||||
return _tprzSearchIndex.TryGetValue(item.Id, out typeSizes)
|
||||
&& typeSizes.Any(delegate(TprzDirectoryItem typeSize) { return MatchesTprzOwnFields(typeSize); });
|
||||
}
|
||||
|
||||
private bool MatchesTipsOwnFields(TipsDirectoryItem item)
|
||||
{
|
||||
return MatchesSearchTokens(
|
||||
item == null ? null : item.Id.ToString(),
|
||||
item == null ? null : item.MeasurementAreaName,
|
||||
item == null ? null : item.InstrumentName,
|
||||
item == null ? null : item.TypeName,
|
||||
item == null ? null : item.CategoryName,
|
||||
item == null ? null : item.DesignName,
|
||||
item == null ? null : item.RegistryTypeNumber,
|
||||
item == null ? null : item.VniimsTypeCode.ToString(),
|
||||
item == null ? null : item.MetrControlCode,
|
||||
item == null ? null : item.Notes);
|
||||
}
|
||||
|
||||
private bool MatchesTprzOwnFields(TprzDirectoryItem item)
|
||||
{
|
||||
return MatchesSearchTokens(
|
||||
item == null ? null : item.Id.ToString(),
|
||||
item == null ? null : item.RangeText,
|
||||
item == null ? null : item.AccuracyText,
|
||||
item == null ? null : item.CompletenessName,
|
||||
item == null ? null : item.RegistryTypeSizeNumber,
|
||||
item == null ? null : item.ServiceCode,
|
||||
item == null ? null : item.VniimsTypeSizeCode.ToString());
|
||||
}
|
||||
|
||||
private bool IsSearchEmpty()
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(SearchText);
|
||||
}
|
||||
|
||||
private bool MatchesSearchTokens(params string[] values)
|
||||
{
|
||||
var tokens = GetSearchTokens();
|
||||
if (tokens.Length == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var haystack = string.Join(" ", values.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })).ToUpperInvariant();
|
||||
return tokens.All(delegate(string token) { return haystack.IndexOf(token, StringComparison.Ordinal) >= 0; });
|
||||
}
|
||||
|
||||
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 RefreshAsync()
|
||||
{
|
||||
RunBusyOperation(async delegate { await RefreshTipsCoreAsync(SelectedTips == null ? (int?)null : SelectedTips.Id); });
|
||||
}
|
||||
|
||||
private void LoadTprzForSelection()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
RunBusyOperation(async delegate
|
||||
{
|
||||
if (SelectedTips == null)
|
||||
{
|
||||
_currentTprzCache = new List<TprzDirectoryItem>();
|
||||
TprzItems.Clear(); TprmcpItems.Clear(); TprmkItems.Clear();
|
||||
SelectedTprz = null; SelectedTprmcp = null; SelectedTprmk = null;
|
||||
UpdateStatus();
|
||||
return;
|
||||
}
|
||||
await RefreshTprzCoreAsync(SelectedTips.Id, null);
|
||||
});
|
||||
}
|
||||
|
||||
private void LoadLeafTablesForSelection()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
RunBusyOperation(async delegate
|
||||
{
|
||||
if (SelectedTprz == null)
|
||||
{
|
||||
TprmcpItems.Clear(); TprmkItems.Clear(); SelectedTprmcp = null; SelectedTprmk = null; UpdateStatus(); return;
|
||||
}
|
||||
await RefreshLeafTablesCoreAsync(SelectedTprz.Id, null, null);
|
||||
});
|
||||
}
|
||||
|
||||
private void RaiseCommandStates()
|
||||
{
|
||||
((RelayCommand)AddTipsCommand).RaiseCanExecuteChanged(); ((RelayCommand)EditTipsCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteTipsCommand).RaiseCanExecuteChanged(); ((RelayCommand)ManageTpvdklCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)AddTprzCommand).RaiseCanExecuteChanged(); ((RelayCommand)EditTprzCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteTprzCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)AddTprmcpCommand).RaiseCanExecuteChanged(); ((RelayCommand)EditTprmcpCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteTprmcpCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)AddTprmkCommand).RaiseCanExecuteChanged(); ((RelayCommand)EditTprmkCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteTprmkCommand).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 void UpdateStatus()
|
||||
{
|
||||
var searchText = string.IsNullOrWhiteSpace(SearchText) ? null : SearchText.Trim();
|
||||
StatusText = string.Format(
|
||||
"{0}TIPS: {1}/{2}. TPRZ: {3}/{4}. TPRMK: {5}. TPRMCP: {6}.",
|
||||
string.IsNullOrWhiteSpace(searchText) ? string.Empty : string.Format("Поиск: \"{0}\". ", searchText),
|
||||
TipsItems.Count,
|
||||
_tipsCache.Count,
|
||||
TprzItems.Count,
|
||||
_currentTprzCache.Count,
|
||||
TprmkItems.Count,
|
||||
TprmcpItems.Count);
|
||||
}
|
||||
|
||||
private static TipsDirectoryItem CloneTips(TipsDirectoryItem source)
|
||||
{
|
||||
return new TipsDirectoryItem { Id = source.Id, MeasurementAreaId = source.MeasurementAreaId, MeasurementAreaName = source.MeasurementAreaName, InstrumentNameId = source.InstrumentNameId, InstrumentName = source.InstrumentName, CategoryId = source.CategoryId, CategoryName = source.CategoryName, DesignId = source.DesignId, DesignName = source.DesignName, TypeName = source.TypeName, ServiceLifeYears = source.ServiceLifeYears, RegistryPeriodMonths = source.RegistryPeriodMonths, RegistryTypeNumber = source.RegistryTypeNumber, VniimsTypeCode = source.VniimsTypeCode, MetrControlCode = source.MetrControlCode, Notes = source.Notes, IsSpecialPurpose = source.IsSpecialPurpose, IsMkPrimaryOnly = source.IsMkPrimaryOnly };
|
||||
}
|
||||
|
||||
private static TprzDirectoryItem CloneTprz(TprzDirectoryItem source)
|
||||
{
|
||||
return new TprzDirectoryItem { Id = source.Id, TipsId = source.TipsId, CompletenessId = source.CompletenessId, CompletenessName = source.CompletenessName, RangeText = source.RangeText, AccuracyText = source.AccuracyText, VniimsTypeSizeCode = source.VniimsTypeSizeCode, RegistryTypeSizeNumber = source.RegistryTypeSizeNumber, ServiceCode = source.ServiceCode };
|
||||
}
|
||||
|
||||
private static TprmcpDirectoryItem CloneTprmcp(TprmcpDirectoryItem source)
|
||||
{
|
||||
return new TprmcpDirectoryItem { Id = source.Id, TypeSizeId = source.TypeSizeId, CycleId = source.CycleId, CycleName = source.CycleName, GroupId = source.GroupId, GroupName = source.GroupName, PeriodMonths = source.PeriodMonths, Comment = source.Comment };
|
||||
}
|
||||
|
||||
private static TprmkDirectoryItem CloneTprmk(TprmkDirectoryItem source)
|
||||
{
|
||||
return new TprmkDirectoryItem { Id = source.Id, TypeSizeId = source.TypeSizeId, VerificationTypeId = source.VerificationTypeId, VerificationTypeName = source.VerificationTypeName, OrganizationId = source.OrganizationId, OrganizationName = source.OrganizationName, QualificationId = source.QualificationId, QualificationName = source.QualificationName, GroupId = source.GroupId, GroupName = source.GroupName, PlaceId = source.PlaceId, PlaceName = source.PlaceName, Cost = source.Cost, ExtraCost = source.ExtraCost, RushMarkup = source.RushMarkup, TimeNormHours = source.TimeNormHours, TimeNormCode = source.TimeNormCode, VerifierCount = source.VerifierCount, VerificationCode = source.VerificationCode, NormDocHours = source.NormDocHours };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,63 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SelectInstrumentTypeWindowViewModel.cs" />
|
||||
<Page Include="TipsEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TipsEditWindow.xaml.cs">
|
||||
<DependentUpon>TipsEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TipsEditWindowViewModel.cs" />
|
||||
<Page Include="SpoiDirectoryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="SpoiDirectoryWindow.xaml.cs">
|
||||
<DependentUpon>SpoiDirectoryWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpoiDirectoryWindowViewModel.cs" />
|
||||
<Page Include="SpoiEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="SpoiEditWindow.xaml.cs">
|
||||
<DependentUpon>SpoiEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpoiEditWindowViewModel.cs" />
|
||||
<Page Include="TpvdklEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TpvdklEditWindow.xaml.cs">
|
||||
<DependentUpon>TpvdklEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TpvdklEditWindowViewModel.cs" />
|
||||
<Page Include="TpvdklWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TpvdklWindow.xaml.cs">
|
||||
<DependentUpon>TpvdklWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TpvdklWindowViewModel.cs" />
|
||||
<Compile Include="TypeSizeDialogService.cs" />
|
||||
<Page Include="TypeSizeDirectoryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TypeSizeDirectoryWindow.xaml.cs">
|
||||
<DependentUpon>TypeSizeDirectoryWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TypeSizeDirectoryWindowViewModel.cs" />
|
||||
<Compile Include="TypeSizeDirectoryModels.cs" />
|
||||
<Compile Include="TypeSizeDirectoryService.cs" />
|
||||
<Page Include="SpnmtpDirectoryWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
@@ -126,6 +183,33 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SpnmtpEditWindowViewModel.cs" />
|
||||
<Page Include="TprmcpEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TprmcpEditWindow.xaml.cs">
|
||||
<DependentUpon>TprmcpEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TprmcpEditWindowViewModel.cs" />
|
||||
<Page Include="TprmkEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TprmkEditWindow.xaml.cs">
|
||||
<DependentUpon>TprmkEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TprmkEditWindowViewModel.cs" />
|
||||
<Page Include="TprzEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="TprzEditWindow.xaml.cs">
|
||||
<DependentUpon>TprzEditWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TprzEditWindowViewModel.cs" />
|
||||
<Page Include="VerificationEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
Reference in New Issue
Block a user