using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using brecal.model; using brecal.mysql; using ExcelDataReader; using Microsoft.Win32; namespace RoleEditor { /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { #region private fields private readonly ObservableCollection _participants = new ObservableCollection(); private readonly ObservableCollection _terminals = new ObservableCollection(); private readonly ObservableCollection _authorities = new ObservableCollection(); private readonly ObservableCollection _roles = new ObservableCollection(); private readonly ObservableCollection _securables = new ObservableCollection(); private readonly ObservableCollection _users = new ObservableCollection(); private readonly ObservableCollection _assignedRoles = new ObservableCollection(); private readonly ObservableCollection _assignedSecurables = new ObservableCollection(); private readonly ObservableCollection _berths = new ObservableCollection(); private readonly ObservableCollection _ships = new ObservableCollection(); private readonly ObservableCollection _ports = new ObservableCollection(); private readonly ObservableCollection _assignedPorts = new ObservableCollection(); private DBManager _dbManager; #endregion #region Construction / Loading public MainWindow() { InitializeComponent(); _dbManager = new(); System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance); // for ExcelDataReader on .NET Core } private async void Window_Loaded(object sender, RoutedEventArgs e) { try { DBManager.SetConnectionString(Properties.Settings.Default.ConnectionString); // load all participants List participants = await Participant.LoadAll(_dbManager); participants.Sort((x, y) => string.Compare(x.Name, y.Name)); foreach (Participant p in participants) { _participants.Add(p); if(p.IsTypeFlagSet(Participant.ParticipantType.TERMINAL)) { _terminals.Add(p); } if(p.IsTypeFlagSet(Participant.ParticipantType.PORT_ADMINISTRATION)) { _authorities.Add(p); } } this.listBoxParticipant.ItemsSource = _participants; // load all roles foreach(Role r in await Role.LoadAll(_dbManager)) _roles.Add(r); this.listBoxRoles.ItemsSource = _roles; // load all securables foreach(Securable s in await Securable.LoadAll(_dbManager)) _securables.Add(s); this.listBoxSecurables.ItemsSource = _securables; // load all ports foreach (Port port in await Port.LoadAll(_dbManager)) _ports.Add(port); this.listBoxPort.ItemsSource = _ports; // load all berths foreach (Berth b in await Berth.LoadAll(_dbManager)) { _berths.Add(b); if (b.Owner_Id != null) { b.Owner = participants.Where(p => p.Id == b.Owner_Id).FirstOrDefault(); } if (b.Authority_Id != null) { b.Authority = participants.Where(p => p.Id == b.Authority_Id).FirstOrDefault(); } if (b.Port_Id != null) { b.Port = _ports.Where(p => p.Id == b.Port_Id).FirstOrDefault(); } } this.dataGridBerths.Initialize(); this.dataGridBerths.ItemsSource = _berths; this.dataGridBerths.CreateRequested += DataGridBerths_CreateRequested; this.dataGridBerths.EditRequested += DataGridBerths_EditRequested; this.dataGridBerths.DeleteRequested += DataGridBerths_DeleteRequested; // load all ships foreach (Ship s in await Ship.LoadAll(_dbManager)) { _ships.Add(s); if(s.Participant_Id != null) { s.Participant = participants.Where( p => p.Id == s.Participant_Id ).FirstOrDefault(); } } this.dataGridShips.Initialize(); this.dataGridShips.ItemsSource = _ships; this.dataGridShips.CreateRequested += DataGridShips_CreateRequested; this.dataGridShips.EditRequested += DataGridShips_EditRequested; this.dataGridShips.DeleteRequested += DataGridShips_DeleteRequested; // set other item sources (filled later after selection) this.listBoxUser.ItemsSource = _users; this.listBoxRoleSecurables.ItemsSource = _assignedSecurables; this.listBoxUserRoles.ItemsSource = _assignedRoles; this.listBoxPortAssignment.ItemsSource = _assignedPorts; this.comboBoxParticipantType.ItemsSource = EnumHelper.GetAllValuesAndDescription(typeof(Participant.ParticipantType)); } catch (Exception ex) { MessageBox.Show($"Database connection couldn't be established: {ex.Message}"); this.Close(); } } #region ship context menu callbacks private async void DataGridShips_DeleteRequested(DbEntity obj) { if (obj is Ship s) { await s.Delete(this._dbManager); this._ships.Remove(s); } } private async void DataGridShips_EditRequested(DbEntity obj) { if(obj is Ship s) { EditShipDialog esd = new(); esd.Ship = s; esd.Participants.AddRange(this._participants); if (esd.ShowDialog() ?? false) { await s.Save(_dbManager); this.dataGridShips.ItemsSource = null; this.dataGridShips.ItemsSource = _ships; } } } private async void DataGridShips_CreateRequested() { Ship s = new(); EditShipDialog esd = new(); esd.Ship = s; esd.Participants.AddRange(this._participants); if(esd.ShowDialog() ?? false) { _ships.Add(s); await s.Save(_dbManager); this.dataGridShips.ItemsSource = null; this.dataGridShips.ItemsSource = _ships; } } #endregion #region berth context menu callbacks private async void DataGridBerths_DeleteRequested(DbEntity obj) { if (obj is Berth b) { await b.Delete(this._dbManager); this._berths.Remove(b); } } private async void DataGridBerths_EditRequested(DbEntity obj) { if(obj is Berth b) { EditBerthDialog ebd = new(); ebd.Berth = b; ebd.Owners.AddRange(this._terminals); ebd.Authorities.AddRange(this._authorities); ebd.Ports.AddRange(this._ports.Where(p => !p.IsDeleted)); if (ebd.ShowDialog() ?? false) { await b.Save(_dbManager); this.dataGridBerths.ItemsSource = null; // extreme stupidity for me not wanting to implement INotifyPropertyChanged this.dataGridBerths.ItemsSource = _berths; } } } private async void DataGridBerths_CreateRequested() { Berth b = new(); EditBerthDialog ebd = new(); ebd.Berth = b; ebd.Owners.AddRange(this._terminals); ebd.Authorities.AddRange(this._authorities); ebd.Ports.AddRange(_ports.Where(p => !p.IsDeleted)); if (ebd.ShowDialog() ?? false) { _berths.Add(b); await b.Save(_dbManager); this.dataGridBerths.ItemsSource = null; this.dataGridBerths.ItemsSource = _berths; } } #endregion #endregion #region button callbacks private async void buttonParticipantSave_Click(object sender, RoutedEventArgs e) { Participant? p = this.listBoxParticipant.SelectedItem as Participant; if (p != null) { p.Name = this.textBoxParticipantName.Text.Trim(); p.Street = this.textBoxParticipantStreet.Text.Trim(); p.PostalCode = this.textBoxParticipantPostalCode.Text.Trim(); p.City = this.textBoxParticipantCity.Text.Trim(); p.SetFlag(this.checkBoxParticipantAllowBSMD.IsChecked ?? false, Participant.ParticipantFlags.ALLOW_BSMD); p.Type = 0; for(int i = 0; i < this.comboBoxParticipantType?.SelectedItems.Count; i++) { object? v = this.comboBoxParticipantType?.SelectedItems[i]; if (v != null) { KeyValuePair kvp = (KeyValuePair)v; Participant.ParticipantType pType = (Participant.ParticipantType)Enum.Parse(typeof(Participant.ParticipantType), kvp.Key); p.SetTypeFlag(true, pType); } } await p.Save(_dbManager); this.listBoxParticipant.ItemsSource = null; this.listBoxParticipant.ItemsSource = _participants; this.listBoxParticipant.SelectedItem = p; } } private async void buttonUserSave_Click(object sender, RoutedEventArgs e) { User? u = this.listBoxUser.SelectedItem as User; if(u != null) { u.Firstname = this.textBoxUserFirstName.Text.Trim(); u.Lastname = this.textBoxUserLastName.Text.Trim(); u.Username = this.textBoxUserUserName.Text.Trim(); u.EMail = this.textBoxUserEMail.Text.Trim(); u.Phone = this.textBoxUserPhone.Text.Trim(); if(this.textBoxUserPassword.Text.Trim().Length > 0 ) { string passwortText = this.textBoxUserPassword.Text.Trim(); byte[] bytes = Encoding.Default.GetBytes(passwortText); passwortText = Encoding.UTF8.GetString(bytes); // Das sollte nicht verändert werden um kompatibel zu der Python Implementierung zu bleiben string salt = BCrypt.Net.BCrypt.GenerateSalt(12, 'b'); u.PasswordHash = BCrypt.Net.BCrypt.HashPassword(passwortText, salt); } u.APIKey = this.textBoxUserAPIKey.Text.Trim(); await u.Save(_dbManager); this.listBoxUser.ItemsSource = null; this.listBoxUser.ItemsSource = _users; this.listBoxUser.SelectedItem = u; } } private async void buttonAddRole_Click(object sender, RoutedEventArgs e) { Role? r = this.listBoxRoles.SelectedItem as Role; User? u = this.listBoxUser.SelectedItem as User; if((r != null) && (u != null)) { // test if assignment is already present bool foundMatchingAssignment = false; foreach(RoleAssignment ra in _assignedRoles) { if((ra.UserId == u.Id) && (ra.RoleId == r.Id)) { foundMatchingAssignment = true; break; } } if(!foundMatchingAssignment) { RoleAssignment ra = new RoleAssignment(); ra.UserId = (int) u.Id; ra.RoleId = (int) r.Id; ra.AssignedRole = r; ra.AssignedUser = u; await ra.Save(_dbManager); _assignedRoles.Add(ra); } } } private async void buttonRemoveRole_Click(object sender, RoutedEventArgs e) { // remove role from user RoleAssignment? ra = this.listBoxUserRoles.SelectedItem as RoleAssignment; if(ra != null) { await ra.Delete(_dbManager); if(_assignedRoles.Contains(ra)) _assignedRoles.Remove(ra); } } private async void buttonAddSecurable_Click(object sender, RoutedEventArgs e) { if ((this.listBoxRoles.SelectedItem is Role r) && (this.listBoxSecurables.SelectedItem is Securable s)) { // test if assignment is already present bool foundMatchingAssignment = false; foreach (SecurableAssignment sa in _assignedSecurables) { if ((sa.SecurableId == s.Id) && (sa.RoleId == r.Id)) { foundMatchingAssignment = true; break; } } if (!foundMatchingAssignment) { SecurableAssignment sa = new SecurableAssignment(); sa.SecurableId = (int)s.Id; sa.RoleId = (int)r.Id; sa.AssignedRole = r; sa.AssignedSecurable = s; await sa.Save(_dbManager); _assignedSecurables.Add(sa); } } } private async void buttonRemoveSecurable_Click(object sender, RoutedEventArgs e) { SecurableAssignment? sa = this.listBoxRoleSecurables.SelectedItem as SecurableAssignment; if(sa != null) { await sa.Delete(_dbManager); if (_assignedSecurables.Contains(sa)) _assignedSecurables.Remove(sa); } } private async void buttonSaveSecurable_Click(object sender, RoutedEventArgs e) { Securable? s = this.listBoxSecurables.SelectedItem as Securable; if(s != null) { s.Name = this.textBoxSecurableName.Text.Trim(); await s.Save(_dbManager); this.listBoxSecurables.ItemsSource = null; this.listBoxSecurables.ItemsSource = _securables; this.listBoxSecurables.SelectedItem = s; } } private async void buttonSaveRole_Click(object sender, RoutedEventArgs e) { Role? r = this.listBoxRoles.SelectedItem as Role; if(r != null) { r.Name = this.textBoxRoleName.Text.Trim(); r.Description = this.textBoxRoleDescription.Text.Trim(); await r.Save(_dbManager); this.listBoxRoles.ItemsSource = null; this.listBoxRoles.ItemsSource = _roles; this.listBoxRoles.SelectedItem = r; } } private async void buttonPortSave_Click(object sender, RoutedEventArgs e) { Port? p = this.listBoxPort.SelectedItem as Port; if (p != null) { p.Name = this.textBoxPortName.Text.Trim(); p.Locode = this.textBoxPortLocode.Text.Trim(); await p.Save(_dbManager); this.listBoxPort.ItemsSource = null; this.listBoxPort.ItemsSource = _ports; this.listBoxPort.SelectedItem = p; } } private async void buttonAddPortAssignment_Click(object sender, RoutedEventArgs e) { if ((this.listBoxPort.SelectedItem is Port p) && (this.listBoxParticipant.SelectedItem is Participant pa)) { // test if assignment is already present bool foundMatchingAssignment = false; foreach (PortAssignment portAssignment in _assignedPorts) { if ((portAssignment.PortId == p.Id) && (portAssignment.ParticipantId == pa.Id)) { foundMatchingAssignment = true; break; } } if (!foundMatchingAssignment) { PortAssignment portAssignment = new PortAssignment(); portAssignment.PortId = (int)p.Id; portAssignment.ParticipantId = (int)pa.Id; portAssignment.AssignedParticipant = pa; portAssignment.AssignedPort = p; await portAssignment.Save(_dbManager); _assignedPorts.Add(portAssignment); } } } private async void buttonRemovePortAssignment_Click(object sender, RoutedEventArgs e) { PortAssignment? pa = this.listBoxPortAssignment.SelectedItem as PortAssignment; if (pa != null) { await pa.Delete(_dbManager); if (_assignedPorts.Contains(pa)) _assignedPorts.Remove(pa); } } #endregion #region listbox selection callbacks private async void listBoxParticipant_SelectionChanged(object sender, SelectionChangedEventArgs e) { Participant? p = this.listBoxParticipant.SelectedItem as Participant; this.textBoxParticipantName.Text = (p != null) ? p.Name : string.Empty; this.textBoxParticipantStreet.Text = (p != null) ? p.Street : string.Empty; this.textBoxParticipantPostalCode.Text = (p != null) ? p.PostalCode : string.Empty; this.textBoxParticipantCity.Text = (p != null) ? p.City : string.Empty; this.textBoxParticipantCreated.Text = (p != null) ? p.Created.ToString() : string.Empty; this.checkboxParticipantDeleted.IsChecked = (p != null) ? p.Deleted : null; this.textBoxParticipantModified.Text = (p != null) ? p.Modified.ToString() : string.Empty; this.checkBoxParticipantAllowBSMD.IsChecked = (p != null) ? p.IsFlagSet(Participant.ParticipantFlags.ALLOW_BSMD) : null; this.comboBoxParticipantType.SelectedItems.Clear(); bool hasAgencyType = false; if (p != null) { foreach (Participant.ParticipantType pType in Enum.GetValues(typeof(Participant.ParticipantType))) { if (p.IsTypeFlagSet(pType)) { if(pType == Participant.ParticipantType.AGENCY) hasAgencyType = true; foreach (KeyValuePair kvp in this.comboBoxParticipantType.Items) { if (kvp.Key.Equals(pType.ToString())) { this.comboBoxParticipantType.SelectedItems.Add(kvp); } } } } } this.checkBoxParticipantAllowBSMD.IsEnabled = hasAgencyType; // -> load users for this participant selection this._users.Clear(); if (p != null) { foreach (User u in await User.LoadForParticipant(p, _dbManager)) _users.Add(u); } // -> load port assignments for this participant selection this._assignedPorts.Clear(); if(p != null) { foreach (PortAssignment pa in await PortAssignment.LoadForParticipant(p, this._dbManager)) { foreach (Port port in this._ports) if (pa.PortId == port.Id) pa.AssignedPort = port; _assignedPorts.Add(pa); } } this.contextMenuUser.IsEnabled = !p.Deleted; this.buttonAddPortAssignment.IsEnabled = !p.Deleted; this.buttonRemovePortAssignment.IsEnabled = !p.Deleted; } private async void listBoxRoles_SelectionChanged(object sender, SelectionChangedEventArgs e) { Role? r = this.listBoxRoles.SelectedItem as Role; this.textBoxRoleName.Text = (r != null) ? r.Name : string.Empty; this.textBoxRoleDescription.Text = (r != null) ? r.Description : string.Empty; _assignedSecurables.Clear(); if (r != null) { // load assigned securables foreach (SecurableAssignment sa in await SecurableAssignment.LoadForRole(r, _dbManager)) { foreach (Securable s in this._securables) { if (sa.SecurableId == s.Id) { sa.AssignedSecurable = s; break; } } _assignedSecurables.Add(sa); } } } private async void listBoxUser_SelectionChanged(object sender, SelectionChangedEventArgs e) { User? u = this.listBoxUser.SelectedItem as User; this.textBoxUserFirstName.Text = (u != null) ? u.Firstname : string.Empty; this.textBoxUserLastName.Text = (u != null) ? u.Lastname : string.Empty; this.textBoxUserUserName.Text = (u != null) ? u.Username : string.Empty; this.textBoxUserEMail.Text = (u != null) ? u.EMail : string.Empty; this.textBoxUserPhone.Text = (u != null) ? u.Phone : string.Empty; this.textBoxUserAPIKey.Text = (u != null) ? u.APIKey : string.Empty; this.textBoxUserCreated.Text = (u != null) ? u.Created.ToString() : string.Empty; this.textBoxUserModified.Text = (u != null) ? u.Modified.ToString() : string.Empty; this.textBoxUserPassword.Text = string.Empty; _assignedRoles.Clear(); if (u != null) { // load roles assigned to user foreach (RoleAssignment ra in await RoleAssignment.LoadForUser(u, _dbManager)) { foreach (Role r in this._roles) { if (ra.RoleId == r.Id) { ra.AssignedRole = r; break; } } _assignedRoles.Add(ra); } } } private void listBoxSecurables_SelectionChanged(object sender, SelectionChangedEventArgs e) { Securable? s = this.listBoxSecurables.SelectedItem as Securable; this.textBoxSecurableName.Text = (s != null) ? s.Name : string.Empty; } private void listBoxPort_SelectionChanged(object sender, SelectionChangedEventArgs e) { Port? p = this.listBoxPort.SelectedItem as Port; this.textBoxPortName.Text = (p != null) ? p.Name : string.Empty; this.textBoxPortLocode.Text = (p != null) ? p.Locode : string.Empty; } #endregion #region menuitem callbacks private async void menuItemDeleteParticipant_Click(object sender, RoutedEventArgs e) { try { if(this.listBoxParticipant.SelectedItem is Participant p) { await p.Delete(_dbManager); p.Deleted = true; } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void menuItemNewParticipant_Click(object sender, RoutedEventArgs e) { Participant p = new(); this._participants.Add(p); this.listBoxParticipant.SelectedItem = p; } private void menuItemNewUser_Click(object sender, RoutedEventArgs e) { Participant? p = this.listBoxParticipant.SelectedItem as Participant; if(p != null) { User u = new(); u.Participant_Id = p.Id; _users.Add(u); this.listBoxUser.SelectedItem = u; } } private async void menuItemDeleteUser_Click(object sender, RoutedEventArgs e) { try { if (this.listBoxUser.SelectedItem is User u) { await u.ExecuteNonQuery(_dbManager); // extra history delete happens here await u.Delete(_dbManager); this._users.Remove(u); } } catch(Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void menuItemNewRole_Click(object sender, RoutedEventArgs e) { Role r = new(); this._roles.Add(r); this.listBoxRoles.SelectedItem = r; } private async void menuItemDeleteRole_Click(object sender, RoutedEventArgs e) { try { if (this.listBoxRoles.SelectedItem is Role r) { await r.Delete(_dbManager); this._roles.Remove(r); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void menuItemNewSecurable_Click(object sender, RoutedEventArgs e) { Securable s = new Securable(); _securables.Add(s); this.listBoxSecurables.SelectedItem = s; } private async void menuItemDeleteSecurable_Click(object sender, RoutedEventArgs e) { try { if (this.listBoxSecurables.SelectedItem is Securable s) { await s.Delete(_dbManager); this._securables.Remove(s); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } private void menuItemNewPort_Click(object sender, RoutedEventArgs e) { Port p = new(); this._ports.Add(p); this.listBoxPort.SelectedItem = p; } private async void menuItemDeletePort_Click(object sender, RoutedEventArgs e) { try { if (this.listBoxPort.SelectedItem is Port p) { await p.Delete(_dbManager); this._ports.Remove(p); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } #endregion #region Excel import private async void buttonImportBerths_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = new OpenFileDialog { Filter = "Excel Files|*.xls;*.xlsx" }; if (ofd.ShowDialog() ?? false) { FileStream stream; try { stream = File.Open(ofd.FileName, FileMode.Open, FileAccess.Read); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); return; } using (var reader = ExcelReaderFactory.CreateReader(stream)) { List importBerthList = new(); int bCounter = 0; int pCounter = 0; try { do { while (reader.Read()) { if (reader.FieldCount < 2) { throw new InvalidDataException("Sheet must have at least 3 Columns of data"); } if (reader.IsDBNull(0) && reader.IsDBNull(1)) continue; string berth_name = ""; if (!reader.IsDBNull(0)) berth_name = reader.GetString(0); if (berth_name.Equals("Liegeplatz", StringComparison.OrdinalIgnoreCase)) continue; string participant_name = ""; if (!reader.IsDBNull(1)) participant_name = reader.GetString(1); // find berth in existing list if (_berths.Any(predicate: x => (x.Name != null) && x.Name.Equals(berth_name, StringComparison.OrdinalIgnoreCase))) continue; string port_name = ""; if (!reader.IsDBNull(2)) port_name = reader.GetString(2); // find port in list if(!_ports.Any(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase))) continue; Port port = _ports.First(x => (x.Name != null) && x.Name.Equals(port_name, StringComparison.OrdinalIgnoreCase)); Berth b = new Berth(); b.Name = berth_name; b.Port = port; b.Port_Id = port.Id; bool found_participant = false; foreach(Participant p in this._participants) { if ((p.Name != null) && p.Name.Contains(participant_name, StringComparison.OrdinalIgnoreCase)) { b.Owner_Id = p.Id; found_participant = true; break; } } if (!found_participant) { // create new participant Participant p = new Participant(); p.Name = participant_name; p.Type = (uint) Participant.ParticipantType.TERMINAL; await p.Save(_dbManager); _participants.Add(p); pCounter++; b.Owner_Id = p.Id; } await b.Save(_dbManager); _berths.Add(b); bCounter++; } } while (reader.NextResult()); if((pCounter > 0) || (bCounter > 0)) { MessageBox.Show($"Imported {bCounter} berths and added {pCounter} participants while doing so"); } } catch (Exception ex) { MessageBox.Show("Error reading Excel: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } stream.Close(); } } private async void buttonImportShipss_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = new OpenFileDialog { Filter = "Excel Files|*.xls;*.xlsx" }; if (ofd.ShowDialog() ?? false) { FileStream stream; try { stream = File.Open(ofd.FileName, FileMode.Open, FileAccess.Read); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); return; } using (var reader = ExcelReaderFactory.CreateReader(stream)) { List importShipList = new(); int bCounter = 0; int pCounter = 0; try { do { while (reader.Read()) { if (reader.FieldCount < 4) { throw new InvalidDataException("Sheet must have at least 4 Columns of data"); } if (reader.IsDBNull(0) && reader.IsDBNull(1)) continue; string ship_name = ""; if (!reader.IsDBNull(0)) ship_name = reader.GetString(0); if (ship_name.Equals("Name", StringComparison.OrdinalIgnoreCase)) continue; // find ship in existing list if (_ships.Any(predicate: x => (x.Name != null) && x.Name.Equals(ship_name, StringComparison.OrdinalIgnoreCase))) continue; Ship s = new(); s.Name = ship_name; if (!reader.IsDBNull(1)) s.IMO = (int) reader.GetDouble(1); if (!reader.IsDBNull(2)) s.Length = reader.GetDouble(2); if(!reader.IsDBNull(3)) s.Width = reader.GetDouble(3); await s.Save(_dbManager); _ships.Add(s); bCounter++; } } while (reader.NextResult()); if ((pCounter > 0) || (bCounter > 0)) { MessageBox.Show($"Imported {bCounter} ships"); } } catch (Exception ex) { MessageBox.Show("Error reading Excel: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } stream.Close(); } } #endregion #region private static helper private static BitmapImage? LoadImage(byte[] imageData) { if (imageData == null || imageData.Length == 0) return null; var image = new BitmapImage(); using (var mem = new MemoryStream(imageData)) { mem.Position = 0; image.BeginInit(); image.CreateOptions = BitmapCreateOptions.PreservePixelFormat; image.CacheOption = BitmapCacheOption.OnLoad; image.UriSource = null; image.StreamSource = mem; image.EndInit(); } image.Freeze(); return image; } #endregion } }