From 0530420bf4bfdda9cfef8e0717b15cc2a626cf01 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Tue, 19 Dec 2017 10:20:51 +0000 Subject: [PATCH] Version 3.9.6: Weitere kleinere Fehlermeldungen, Refresh/Jump aus Error/Violationdialog --- .../ENI2/Controls/ServerStatusControl.xaml | 24 +++ .../ENI2/Controls/ServerStatusControl.xaml.cs | 142 +++++++++++++----- ENI-2/ENI2/ENI2/Controls/StatusWindowBase.cs | 57 +++++++ ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs | 100 +++++++++--- .../PortNotificationDetailControl.xaml | 2 +- ENI-2/ENI2/ENI2/ENI2.csproj | 5 +- .../EditControls/CoreStatusInfoDialog.xaml | 6 +- .../EditControls/CoreStatusInfoDialog.xaml.cs | 2 + .../ENI2/EditControls/EditLADGDialog.xaml.cs | 12 +- .../EditPortOfCallLast30DaysDialog.xaml | 2 +- .../ENI2/EditControls/ErrorListDialog.xaml | 4 +- .../ENI2/EditControls/ErrorListDialog.xaml.cs | 21 ++- .../ENI2/EditControls/NewWithIdDialog.xaml.cs | 2 +- .../EditControls/ViolationListDialog.xaml | 5 +- .../EditControls/ViolationListDialog.xaml.cs | 21 ++- .../ENI2/Properties/Resources.Designer.cs | 27 ++++ ENI-2/ENI2/ENI2/Properties/Resources.resx | 9 ++ ENI-2/ENI2/ENI2/SucheControl.xaml.cs | 4 +- ENI-2/ENI2/ENI2/Themes/Generic.xaml | 22 +++ Stundensheet.xlsx | Bin 35320 -> 35407 bytes .../bsmd.ExcelReadService/ExcelReader.cs | 3 + nsw/Source/bsmd.ExcelReadService/Util.cs | 9 +- nsw/Source/bsmd.database/DBManager.cs | 8 +- nsw/Source/bsmd.database/DatabaseEntity.cs | 3 +- nsw/Source/bsmd.database/INFO.cs | 19 +++ .../bsmd.database/PortOfCallLast30Days.cs | 11 +- .../PortOfCallLast30DaysCrewJoinedShip.cs | 2 +- .../Properties/AssemblyProductInfo.cs | 2 +- .../Properties/AssemblyProjectInfo.cs | 2 +- nsw/Source/bsmd.database/RuleEngine.cs | 10 +- nsw/Source/bsmd.database/STAT.cs | 2 +- .../bsmd.database/ValidationAttribute.cs | 28 +++- nsw/Source/bsmd.database/ValidationRule.cs | 2 +- nsw/Source/bsmd.database/WAS.cs | 7 +- .../WasteDisposalServiceProvider.cs | 10 +- 35 files changed, 463 insertions(+), 122 deletions(-) create mode 100644 ENI-2/ENI2/ENI2/Controls/StatusWindowBase.cs diff --git a/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml b/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml index b803dca1..638b19db 100644 --- a/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml +++ b/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml @@ -34,6 +34,30 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml.cs b/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml.cs index 5bfba771..59be8b2a 100644 --- a/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml.cs +++ b/ENI-2/ENI2/ENI2/Controls/ServerStatusControl.xaml.cs @@ -12,6 +12,7 @@ using System.Globalization; using log4net; using bsmd.database; using System.ServiceProcess; +using System.ComponentModel; namespace ENI2.Controls { @@ -24,12 +25,15 @@ namespace ENI2.Controls private ObservableCollection entries = new ObservableCollection(); private static Regex regex = new Regex(@"BSMD_(\d*)-(.*)-(\w*)"); private static ILog _log = LogManager.GetLogger("ServerStatus"); + private ProgressBar _updateProgressBar; + private TextBlock _updateTextBlock; public ServerStatusControl() { InitializeComponent(); this.dataGridStatus.ItemsSource = this.entries; this.Loaded += ServerStatusControl_Loaded; + } private void ServerStatusControl_Loaded(object sender, System.Windows.RoutedEventArgs e) @@ -39,18 +43,64 @@ namespace ENI2.Controls internal void Update(LockingServiceReference.ServerStatus serverStatus) { + int totalNum = serverStatus.IMPFiles.Length + serverStatus.READYFiles.Length + serverStatus.CORRUPTFiles.Length; + entries.Clear(); + BackgroundWorker bgWorker = new BackgroundWorker(); - System.Windows.Application.Current.Dispatcher.Invoke(delegate { + bgWorker.DoWork += (o, e) => + { + System.Windows.Application.Current.Dispatcher.Invoke(delegate { + this._updateProgressBar.Maximum = totalNum; + this._updateProgressBar.Value = 0; + }); + + int counter = 0; // Die Dateien müssen in die Objekte - entries.Clear(); - foreach (StatusEntry se in StatusEntry.CreateFromList(serverStatus.IMPFiles, "IMP")) - entries.Add(se); + List tmpList = new List(); - foreach (StatusEntry se in StatusEntry.CreateFromList(serverStatus.READYFiles, "READY")) - entries.Add(se); + foreach (string filename in serverStatus.IMPFiles) + { + StatusEntry se = StatusEntry.Create(filename, "IMP"); + tmpList.Add(se); + counter++; + System.Windows.Application.Current.Dispatcher.Invoke(delegate { + this._updateTextBlock.Text = string.Format(Properties.Resources.textUpdatingFile, counter, totalNum); + this._updateProgressBar.Value = counter; + }); + } - foreach (StatusEntry se in StatusEntry.CreateFromList(serverStatus.CORRUPTFiles, "CORRUPT")) + foreach (string filename in serverStatus.READYFiles) + { + StatusEntry se = StatusEntry.Create(filename, "READY"); + tmpList.Add(se); + counter++; + System.Windows.Application.Current.Dispatcher.Invoke(delegate { + this._updateTextBlock.Text = string.Format(Properties.Resources.textUpdatingFile, counter, totalNum); + this._updateProgressBar.Value = counter; + }); + } + + foreach (string filename in serverStatus.CORRUPTFiles) + { + StatusEntry se = StatusEntry.Create(filename, "CORRUPT"); + tmpList.Add(se); + counter++; + System.Windows.Application.Current.Dispatcher.Invoke(delegate { + this._updateTextBlock.Text = string.Format(Properties.Resources.textUpdatingFile, counter, totalNum); + this._updateProgressBar.Value = counter; + }); + } + + tmpList.Sort(); + + System.Windows.Application.Current.Dispatcher.Invoke(delegate { + foreach (StatusEntry se in tmpList) entries.Add(se); + }); + }; + + bgWorker.RunWorkerCompleted += (o, e) => + { // Enumeration parsen und text ausgeben ServiceControllerStatus excel = (ServiceControllerStatus)serverStatus.Excel; @@ -62,10 +112,15 @@ namespace ENI2.Controls ServiceControllerStatus transmitter = (ServiceControllerStatus)serverStatus.Transmitter; this.labelStatusTransmitter.Content = transmitter.ToString(); - entries.BubbleSort(); - }); + this.busyIndicator.IsBusy = false; + }; + + this.busyIndicator.IsBusy = true; + bgWorker.RunWorkerAsync(); + } + public class StatusEntry : IComparable { private static Dictionary guidIdDict = new Dictionary(); @@ -78,47 +133,44 @@ namespace ENI2.Controls public string Status { get; set; } - public static List CreateFromList(string[] aList, string status) + public static StatusEntry Create(string filename, string status) { - List result = new List(); + StatusEntry result = null; - foreach(string listEntry in aList) + if (regex.IsMatch(filename)) { - if (regex.IsMatch(listEntry)) + try { - try + StatusEntry entry = new StatusEntry(); + Match m = regex.Match(filename); + entry.Timestamp = DateTime.ParseExact(m.Groups[1].Value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture); + + string guidString = m.Groups[2].Value; + + if (!guidIdDict.ContainsKey(guidString)) { - StatusEntry entry = new StatusEntry(); - Match m = regex.Match(listEntry); - entry.Timestamp = DateTime.ParseExact(m.Groups[1].Value, "yyyyMMddHHmmss", CultureInfo.InvariantCulture); - - string guidString = m.Groups[2].Value; - - if (!guidIdDict.ContainsKey(guidString)) + string idString = ""; + Guid coreId; + if (Guid.TryParse(m.Groups[2].Value, out coreId)) { - string idString = ""; - Guid coreId; - if (Guid.TryParse(m.Groups[2].Value, out coreId)) + MessageCore aCore = DBManager.Instance.GetMessageCoreById(coreId); + if (aCore != null) { - MessageCore aCore = DBManager.Instance.GetMessageCoreById(coreId); - if (aCore != null) - { - idString = aCore.DisplayId; - } + idString = aCore.DisplayId; } - guidIdDict[guidString] = idString; } - - entry.Id = guidIdDict[guidString]; - entry.Class = m.Groups[3].Value; - entry.Status = status; - - result.Add(entry); - } - catch(Exception ex) - { - _log.WarnFormat("Problem reading status info: {0}", ex.Message); + guidIdDict[guidString] = idString; } + + entry.Id = guidIdDict[guidString]; + entry.Class = m.Groups[3].Value; + entry.Status = status; + + result = entry; + } + catch (Exception ex) + { + _log.WarnFormat("Problem reading status info: {0}", ex.Message); } } @@ -155,6 +207,16 @@ namespace ENI2.Controls } } } + + private void textUpdateProgress_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + if (sender != null) this._updateTextBlock = sender as TextBlock; + } + + private void progressBarUpdate_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + if (sender != null) this._updateProgressBar = sender as ProgressBar; + } } } diff --git a/ENI-2/ENI2/ENI2/Controls/StatusWindowBase.cs b/ENI-2/ENI2/ENI2/Controls/StatusWindowBase.cs new file mode 100644 index 00000000..12ae90e3 --- /dev/null +++ b/ENI-2/ENI2/ENI2/Controls/StatusWindowBase.cs @@ -0,0 +1,57 @@ +// Copyright (c) 2017 schick Informatik +// Description: Dialog Basisklasse analog EditWindowBase. Hier allerdings mit optionalem "Refresh" Knopf und +// "Close" statt "OK" und "Cancel" + + +using System; +using System.Windows; +using System.Windows.Controls; +using System.ComponentModel; +using ENI2.Util; + +namespace ENI2.Controls +{ + + [TemplatePart(Name = "buttonRefresh", Type = typeof(Button))] + [TemplatePart(Name = "buttonClose", Type = typeof(Button))] + public class StatusWindowBase : Window + { + + public event Action CloseClicked; + public event Action RefreshClicked; + + static StatusWindowBase() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StatusWindowBase), new FrameworkPropertyMetadata(typeof(StatusWindowBase))); + } + + public StatusWindowBase() + { + Loaded += (_, __) => + { + var closeButton = (Button)Template.FindName("buttonClose", this); + var refreshButton = (Button)Template.FindName("buttonRefresh", this); + + closeButton.Click += (s, e) => { if (IsModal) DialogResult = true; CloseClicked?.Invoke(); this.Close(); }; + refreshButton.Click += (s, e) => { RefreshClicked?.Invoke(); }; + + }; + this.IsModal = true; // default + } + + public bool IsModal { get; set; } + + public bool RefreshVisible + { + get { var refreshButton = (Button)Template.FindName("buttonRefresh", this); return refreshButton.Visibility == Visibility.Visible; } + set { var refreshButton = (Button)Template.FindName("buttonRefresh", this); refreshButton.Visibility = value ? Visibility.Visible : Visibility.Hidden; } + } + + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + // this.SetPlacement(..) + } + + } +} diff --git a/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs b/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs index cefa1e7c..207e8b7c 100644 --- a/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs +++ b/ENI-2/ENI2/ENI2/DetailRootControl.xaml.cs @@ -34,9 +34,9 @@ namespace ENI2 private object messageListLock = new object(); private HighlightService highlightService = new HighlightService(); - // Validation - protected List _vErrors = new List(); - protected List _vViolations = new List(); + // Referenzen für Fehler/Violation Dialoge (können, müssen aber nicht offen bleiben) + protected ErrorListDialog _errorListDialog = null; + protected ViolationListDialog _violationListDialog = null; #endregion @@ -369,13 +369,16 @@ namespace ENI2 private void DetailControl_RequestSendValidation() { - this.Validate(false); + List violationList = null; + List errorList = null; + + this.Validate(false, out violationList, out errorList); foreach(Message aMessage in this._messages) { if(aMessage.InternalStatus == Message.BSMDStatus.TOSEND) { - foreach(MessageError messageError in this._vErrors) + foreach(MessageError messageError in errorList) { if(messageError.NotificationClass == aMessage.MessageNotificationClassDisplay) { @@ -445,13 +448,16 @@ namespace ENI2 private void DetailControl_RequestValidate() { - this.Validate(true); + List errorList = null; + List violationList = null; + this.Validate(true, out violationList, out errorList); } - private void Validate(bool showMessages) + private void Validate(bool showMessages, out List vViolations, out List vErrors) { - this._vErrors.Clear(); - this._vViolations.Clear(); + vViolations = new List(); + vErrors = new List(); + // TODO: clear highlighting Util.UIHelper.SetBusyState(); @@ -475,15 +481,15 @@ namespace ENI2 mv.MessageGroupName = messageGroup; } - this._vErrors.AddRange(errors); - this._vViolations.AddRange(violations); + vErrors.AddRange(errors); + vViolations.AddRange(violations); } - foreach (MessageError me in this._vErrors) + foreach (MessageError me in vErrors) { this.highlightService.HighlightError(me, this.GetContainerForMessageGroupName(me.MessageGroupName)); } - foreach (MessageViolation mv in this._vViolations) + foreach (MessageViolation mv in vViolations) { this.highlightService.HighlightViolation(mv, this.GetContainerForMessageGroupName(mv.MessageGroupName)); } @@ -519,23 +525,37 @@ namespace ENI2 if (showMessages) { // Show error and violation dialog - if (this._vErrors.Count > 0) + if (vErrors.Count > 0) { - ErrorListDialog eld = new ErrorListDialog(); - eld.IsModal = false; - eld.Errors = this._vErrors; - eld.Show(); + if(this._errorListDialog == null) + { + this._errorListDialog = new ErrorListDialog(); + this._errorListDialog.Closed += (o, e) => { this._errorListDialog = null; }; + this._errorListDialog.Loaded += (o, e) => { this._errorListDialog.RefreshVisible = true; }; + this._errorListDialog.ErrorSelected += _errorListDialog_ErrorSelected; + this._errorListDialog.RefreshClicked += _errorListDialog_RefreshClicked; + this._errorListDialog.IsModal = false; + this._errorListDialog.Show(); + } + this._errorListDialog.Errors = vErrors; } - if (this._vViolations.Count > 0) + if (vViolations.Count > 0) { - ViolationListDialog vld = new ViolationListDialog(); - vld.IsModal = false; - vld.Violations = this._vViolations; - vld.Show(); + if(this._violationListDialog == null) + { + this._violationListDialog = new ViolationListDialog(); + this._violationListDialog.Closed += (o, e) => { this._violationListDialog = null; }; + this._violationListDialog.Loaded += (o, e) => { this._violationListDialog.RefreshVisible = true; }; + this._violationListDialog.ViolationSelected += _errorListDialog_ErrorSelected; + this._violationListDialog.RefreshClicked += _errorListDialog_RefreshClicked; + this._violationListDialog.IsModal = false; + this._violationListDialog.Show(); + } + _violationListDialog.Violations = vViolations; } - if((this._vErrors.Count == 0) && (this._vViolations.Count == 0)) + if((vErrors.Count == 0) && (vViolations.Count == 0)) { MessageBox.Show(Properties.Resources.textValidationOK, Properties.Resources.textValidation, MessageBoxButton.OK, MessageBoxImage.Information); } @@ -543,6 +563,38 @@ namespace ENI2 } } + private void _errorListDialog_RefreshClicked() + { + DetailControl_RequestValidate(); + } + + private void _errorListDialog_ErrorSelected(DatabaseEntity obj) + { + string msgGroupName = null; + if(obj is MessageError) + { + MessageError me = obj as MessageError; + msgGroupName = me.MessageGroupName; + } + else if(obj is MessageViolation) + { + MessageViolation mv = obj as MessageViolation; + msgGroupName = mv.MessageGroupName; + } + + if(msgGroupName != null) + { + for(int i=0;i<_listBoxList.Count;i++) + { + if(_listBoxList[i].MessageGroupName.Equals(msgGroupName)) + { + this.listBoxMessages.SelectedIndex = i; + break; + } + } + } + } + #endregion #region private / protected methods diff --git a/ENI-2/ENI2/ENI2/DetailViewControls/PortNotificationDetailControl.xaml b/ENI-2/ENI2/ENI2/DetailViewControls/PortNotificationDetailControl.xaml index aa84b2d3..64c22e7b 100644 --- a/ENI-2/ENI2/ENI2/DetailViewControls/PortNotificationDetailControl.xaml +++ b/ENI-2/ENI2/ENI2/DetailViewControls/PortNotificationDetailControl.xaml @@ -60,7 +60,7 @@ - + diff --git a/ENI-2/ENI2/ENI2/ENI2.csproj b/ENI-2/ENI2/ENI2/ENI2.csproj index 2e1dea6f..c8a53cb5 100644 --- a/ENI-2/ENI2/ENI2/ENI2.csproj +++ b/ENI-2/ENI2/ENI2/ENI2.csproj @@ -35,8 +35,8 @@ 3.5.1.0 true publish.html - 0 - 3.9.5.%2a + 1 + 3.9.6.%2a false true true @@ -186,6 +186,7 @@ ServerStatusControl.xaml + ValidationConditionControl.xaml diff --git a/ENI-2/ENI2/ENI2/EditControls/CoreStatusInfoDialog.xaml b/ENI-2/ENI2/ENI2/EditControls/CoreStatusInfoDialog.xaml index 72c98b04..77b843f6 100644 --- a/ENI-2/ENI2/ENI2/EditControls/CoreStatusInfoDialog.xaml +++ b/ENI-2/ENI2/ENI2/EditControls/CoreStatusInfoDialog.xaml @@ -8,7 +8,7 @@ xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:p="clr-namespace:ENI2.Properties" mc:Ignorable="d" - Title="{x:Static p:Resources.textCoreStatus}" Height="436" Width="600" WindowStyle="SingleBorderWindow" Background="AliceBlue" > + Title="{x:Static p:Resources.textCoreStatus}" Height="436" Width="600" WindowStyle="SingleBorderWindow" Background="AliceBlue" Icon="/ENI2;component/Resources/bullet_ball_grey.ico" > @@ -21,7 +21,9 @@ - + + + - + diff --git a/ENI-2/ENI2/ENI2/EditControls/ViolationListDialog.xaml.cs b/ENI-2/ENI2/ENI2/EditControls/ViolationListDialog.xaml.cs index d75e3463..b43de5a8 100644 --- a/ENI-2/ENI2/ENI2/EditControls/ViolationListDialog.xaml.cs +++ b/ENI-2/ENI2/ENI2/EditControls/ViolationListDialog.xaml.cs @@ -7,26 +7,39 @@ using System.Windows; using bsmd.database; using ENI2.Controls; +using System; namespace ENI2.EditControls { /// /// Interaction logic for ErrorListDialog.xaml /// - public partial class ViolationListDialog : EditWindowBase + public partial class ViolationListDialog : StatusWindowBase { + + public event Action ViolationSelected; + public ViolationListDialog() { InitializeComponent(); Loaded += ErrorListDialog_Loaded; } - public List Violations { get; set; } + public List Violations + { + get { return this.dataGridViolations.ItemsSource as List; } + set { this.dataGridViolations.ItemsSource = value; } + } private void ErrorListDialog_Loaded(object sender, RoutedEventArgs e) { - this.dataGridViolations.Initialize(); - this.dataGridViolations.ItemsSource = this.Violations; + this.dataGridViolations.Initialize(); + this.dataGridViolations.EditRequested += DataGridViolations_EditRequested; + } + + private void DataGridViolations_EditRequested(DatabaseEntity obj) + { + this.ViolationSelected?.Invoke(obj); } } } diff --git a/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs b/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs index 5435ad42..0fc07fca 100644 --- a/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs +++ b/ENI-2/ENI2/ENI2/Properties/Resources.Designer.cs @@ -1175,6 +1175,15 @@ namespace ENI2.Properties { } } + /// + /// Looks up a localized string similar to Close. + /// + public static string textClose { + get { + return ResourceManager.GetString("textClose", resourceCulture); + } + } + /// /// Looks up a localized string similar to Code. /// @@ -4253,6 +4262,24 @@ namespace ENI2.Properties { } } + /// + /// Looks up a localized string similar to Server status update. + /// + public static string textUpdateStatus { + get { + return ResourceManager.GetString("textUpdateStatus", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reading file {0}/{1}.... + /// + public static string textUpdatingFile { + get { + return ResourceManager.GetString("textUpdatingFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to User administration. /// diff --git a/ENI-2/ENI2/ENI2/Properties/Resources.resx b/ENI-2/ENI2/ENI2/Properties/Resources.resx index 19a053c7..07a1958a 100644 --- a/ENI-2/ENI2/ENI2/Properties/Resources.resx +++ b/ENI-2/ENI2/ENI2/Properties/Resources.resx @@ -1600,4 +1600,13 @@ Copy Id to clipboard + + Server status update + + + Reading file {0}/{1}... + + + Close + \ No newline at end of file diff --git a/ENI-2/ENI2/ENI2/SucheControl.xaml.cs b/ENI-2/ENI2/ENI2/SucheControl.xaml.cs index 441d242f..e60420ba 100644 --- a/ENI-2/ENI2/ENI2/SucheControl.xaml.cs +++ b/ENI-2/ENI2/ENI2/SucheControl.xaml.cs @@ -82,11 +82,11 @@ namespace ENI2 uint? from = null, to = null; if(this.dateTimePickerETAFrom.SelectedDate.HasValue) { - from = this.dateTimePickerETAFrom.SelectedDate.Value.ToUnixTimeStamp(); + from = this.dateTimePickerETAFrom.SelectedDate.Value.ToUniversalTime().ToUnixTimeStamp(); } if(this.dateTimePickerETATo.SelectedDate.HasValue) { - DateTime toTime = this.dateTimePickerETATo.SelectedDate.Value.Add(new TimeSpan(23, 59, 59)); // search till the end of the "to" day (no time selection) + DateTime toTime = this.dateTimePickerETATo.SelectedDate.Value.ToUniversalTime().Add(new TimeSpan(23, 59, 59)); // search till the end of the "to" day (no time selection) to = toTime.ToUnixTimeStamp(); } diff --git a/ENI-2/ENI2/ENI2/Themes/Generic.xaml b/ENI-2/ENI2/ENI2/Themes/Generic.xaml index 8398b911..e1dfe63a 100644 --- a/ENI-2/ENI2/ENI2/Themes/Generic.xaml +++ b/ENI-2/ENI2/ENI2/Themes/Generic.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:enictrl="clr-namespace:ENI2.Controls" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" + xmlns:p="clr-namespace:ENI2.Properties" xmlns:local="clr-namespace:ENI2"> @@ -43,6 +44,27 @@ +