diff --git a/XLAB/CloneVerificationWindow.xaml b/XLAB/CloneVerificationWindow.xaml
new file mode 100644
index 0000000..c558f26
--- /dev/null
+++ b/XLAB/CloneVerificationWindow.xaml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/XLAB/CloneVerificationWindow.xaml.cs b/XLAB/CloneVerificationWindow.xaml.cs
new file mode 100644
index 0000000..6c72a07
--- /dev/null
+++ b/XLAB/CloneVerificationWindow.xaml.cs
@@ -0,0 +1,20 @@
+using System.Windows;
+
+namespace XLAB
+{
+ public partial class CloneVerificationWindow : Window
+ {
+ internal CloneVerificationWindow(CloneVerificationWindowViewModel viewModel)
+ {
+ InitializeComponent();
+ DataContext = viewModel;
+ viewModel.CloseRequested += ViewModelOnCloseRequested;
+ }
+
+ private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
+ {
+ DialogResult = dialogResult;
+ Close();
+ }
+ }
+}
diff --git a/XLAB/CloneVerificationWindowViewModel.cs b/XLAB/CloneVerificationWindowViewModel.cs
new file mode 100644
index 0000000..6b3e251
--- /dev/null
+++ b/XLAB/CloneVerificationWindowViewModel.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Input;
+
+namespace XLAB
+{
+ internal sealed class CloneVerificationWindowViewModel : ObservableObject
+ {
+ private string _serialNumbersText;
+ private string _statusText;
+
+ public CloneVerificationWindowViewModel(CloneVerificationSeed seed)
+ {
+ if (seed == null)
+ {
+ throw new ArgumentNullException("seed");
+ }
+
+ SourceSerialNumber = string.IsNullOrWhiteSpace(seed.SourceSerialNumber) ? string.Empty : seed.SourceSerialNumber.Trim();
+ VerificationSummary = seed.VerificationSummary ?? string.Empty;
+
+ ConfirmCommand = new RelayCommand(Confirm, CanConfirm);
+ CancelCommand = new RelayCommand(Cancel);
+ UpdateStatus();
+ }
+
+ public event EventHandler CloseRequested;
+
+ public ICommand CancelCommand { get; private set; }
+
+ public ICommand ConfirmCommand { get; private set; }
+
+ public string SourceSerialNumber { get; private set; }
+
+ public string SerialNumbersText
+ {
+ get { return _serialNumbersText; }
+ set
+ {
+ if (SetProperty(ref _serialNumbersText, value))
+ {
+ UpdateStatus();
+ ((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
+ }
+ }
+ }
+
+ public string StatusText
+ {
+ get { return _statusText; }
+ private set { SetProperty(ref _statusText, value); }
+ }
+
+ public string VerificationSummary { get; private set; }
+
+ public IReadOnlyList GetSerialNumbers()
+ {
+ return ParseSerialNumbers(SerialNumbersText);
+ }
+
+ private void Cancel(object parameter)
+ {
+ RaiseCloseRequested(false);
+ }
+
+ private bool CanConfirm(object parameter)
+ {
+ return ParseSerialNumbers(SerialNumbersText).Count > 0;
+ }
+
+ private void Confirm(object parameter)
+ {
+ RaiseCloseRequested(true);
+ }
+
+ private static List ParseSerialNumbers(string value)
+ {
+ var serialNumbers = new List();
+ var unique = new HashSet(StringComparer.OrdinalIgnoreCase);
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return serialNumbers;
+ }
+
+ var separators = new[] { '\r', '\n', '\t', ',', ';' };
+ foreach (var token in value.Split(separators, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var serialNumber = token.Trim();
+ if (serialNumber.Length == 0 || !unique.Add(serialNumber))
+ {
+ continue;
+ }
+
+ serialNumbers.Add(serialNumber);
+ }
+
+ return serialNumbers;
+ }
+
+ private void RaiseCloseRequested(bool? dialogResult)
+ {
+ var handler = CloseRequested;
+ if (handler != null)
+ {
+ handler(this, dialogResult);
+ }
+ }
+
+ private void UpdateStatus()
+ {
+ var serialCount = ParseSerialNumbers(SerialNumbersText).Count;
+ StatusText = string.Format("Уникальных заводских номеров: {0}.", serialCount);
+ }
+ }
+}
diff --git a/XLAB/DialogService.cs b/XLAB/DialogService.cs
index 38ba5db..3c94889 100644
--- a/XLAB/DialogService.cs
+++ b/XLAB/DialogService.cs
@@ -11,6 +11,8 @@ namespace XLAB
InstrumentTypeSelectionResult ShowInstrumentTypeDialog(string customerName, IReadOnlyList instrumentTypes);
+ IReadOnlyList ShowCloneVerificationDialog(CloneVerificationSeed seed);
+
VerificationEditResult ShowVerificationDialog(
VerificationEditSeed seed,
IReadOnlyList verifiers,
@@ -64,6 +66,16 @@ namespace XLAB
return result.HasValue && result.Value ? viewModel.GetResult() : null;
}
+ public IReadOnlyList ShowCloneVerificationDialog(CloneVerificationSeed seed)
+ {
+ var viewModel = new CloneVerificationWindowViewModel(seed);
+ var window = new CloneVerificationWindow(viewModel);
+ window.Owner = _owner;
+
+ var result = window.ShowDialog();
+ return result.HasValue && result.Value ? viewModel.GetSerialNumbers() : null;
+ }
+
public VerificationEditResult ShowVerificationDialog(
VerificationEditSeed seed,
IReadOnlyList verifiers,
diff --git a/XLAB/MainWindow.xaml b/XLAB/MainWindow.xaml
index c76974a..b670fc7 100644
--- a/XLAB/MainWindow.xaml
+++ b/XLAB/MainWindow.xaml
@@ -272,6 +272,9 @@
HeadersVisibility="Column">
+
+