From 08eaa30209fb07132671006392af33044278fb88 Mon Sep 17 00:00:00 2001
From: retr0volkov <68907954+retr0volkov@users.noreply.github.com>
Date: Wed, 30 Jul 2025 09:08:22 +0300
Subject: [PATCH] Removed dialogs for editing equipment and points, and their
related resources
---
.idea/.idea.GazpromApp/.idea/avalonia.xml | 7 +
.idea/.idea.GazpromApp/.idea/dataSources.xml | 7 +
App.axaml | 5 +-
GazpromApp.csproj | 2 +
Messages/EditEquipmentMessage.cs | 4 +-
Messages/EditPointMessage.cs | 6 +-
Messages/NewEquipmentDone.cs | 8 -
Messages/NewEquipmentMessage.cs | 6 -
Messages/NewPointDone.cs | 8 -
Messages/NewPointMessage.cs | 6 -
...pmentDone.cs => RemoveEquipmentMessage.cs} | 2 +-
Messages/RemoveInspectionMessage.cs | 8 +
...EditPointDone.cs => RemovePointMessage.cs} | 2 +-
Messages/RemovePropertyMessage.cs | 8 +
Messages/RequestImageMessage.cs | 11 +
Messages/SaveChangesMessage.cs | 9 +
Messages/SaveChangesResult.cs | 7 +
Messages/SelectionChangedMessage.cs | 8 +
Models/Equipment.cs | 29 ++-
Models/Image.cs | 10 +-
Models/Inspection.cs | 5 +-
Models/Point.cs | 6 +-
Models/Property.cs | 12 +-
Utils/AppDbContext.cs | 63 +----
Utils/ParentsHelper.cs | 53 +++++
Utils/PropertyParentHelper.cs | 30 ---
ViewModels/Basic/EquipmentViewModel.cs | 60 ++++-
ViewModels/Basic/ImageViewModel.cs | 48 ++--
ViewModels/Basic/InspectionViewModel.cs | 23 ++
ViewModels/Basic/PointViewModel.cs | 54 ++++-
ViewModels/Basic/PropertyViewModel.cs | 37 ++-
ViewModels/Basic/SaveChangesViewModel.cs | 42 ++++
...ViewModel.cs => EditEquipmentViewModel.cs} | 143 +++++------
...alogViewModel.cs => EditPointViewModel.cs} | 118 +++------
ViewModels/MainWindowViewModel.cs | 214 ++++++++++++-----
ViewModels/NewEquipmentDialogViewModel.cs | 94 --------
ViewModels/NewPointDialogViewModel.cs | 93 --------
Views/EditEquipmentDialog.axaml | 225 ------------------
Views/EditEquipmentDialog.axaml.cs | 57 -----
Views/EditEquipmentView.axaml | 135 +++++++++++
Views/EditEquipmentView.axaml.cs | 13 +
Views/EditPointDialog.axaml | 220 -----------------
Views/EditPointDialog.axaml.cs | 119 ---------
Views/EditPointView.axaml | 112 +++++++++
Views/EditPointView.axaml.cs | 13 +
Views/EquipmentView.axaml | 38 +++
Views/EquipmentView.axaml.cs | 13 +
Views/InspectionView.axaml | 55 +++++
Views/InspectionView.axaml.cs | 13 +
Views/MainWindow.axaml | 103 +++-----
Views/MainWindow.axaml.cs | 86 +++++--
Views/NewEquipmentDialog.axaml | 76 ------
Views/NewEquipmentDialog.axaml.cs | 37 ---
Views/NewPointDialog.axaml | 82 -------
Views/NewPointDialog.axaml.cs | 36 ---
Views/PointView.axaml | 60 +++++
Views/PointView.axaml.cs | 14 ++
Views/PropertyView.axaml | 43 ++++
Views/PropertyView.axaml.cs | 13 +
Views/SaveChangesView.axaml | 40 ++++
Views/SaveChangesView.axaml.cs | 26 ++
.../net8.0/Avalonia/Resources.Inputs.cache | 2 +-
obj/Debug/net8.0/Avalonia/resources | Bin 473854 -> 462311 bytes
obj/Debug/net8.0/GazpromApp.AssemblyInfo.cs | 15 +-
.../GazpromApp.AssemblyInfoInputs.cache | 2 +-
....GeneratedMSBuildEditorConfig.editorconfig | 17 +-
obj/Debug/net8.0/GazpromApp.assets.cache | Bin 77739 -> 80054 bytes
.../GazpromApp.csproj.AssemblyReference.cache | Bin 35117 -> 37400 bytes
.../GazpromApp.csproj.FileListAbsolute.txt | 6 +
obj/GazpromApp.csproj.nuget.dgspec.json | 8 +
obj/GazpromApp.csproj.nuget.g.props | 2 +-
obj/GazpromApp.csproj.nuget.g.targets | 4 +-
obj/project.assets.json | 97 ++++++++
obj/project.nuget.cache | 5 +-
obj/project.packagespec.json | 2 +-
obj/rider.project.model.nuget.info | 2 +-
obj/rider.project.restore.info | 2 +-
77 files changed, 1498 insertions(+), 1543 deletions(-)
delete mode 100644 Messages/NewEquipmentDone.cs
delete mode 100644 Messages/NewEquipmentMessage.cs
delete mode 100644 Messages/NewPointDone.cs
delete mode 100644 Messages/NewPointMessage.cs
rename Messages/{EditEquipmentDone.cs => RemoveEquipmentMessage.cs} (66%)
create mode 100644 Messages/RemoveInspectionMessage.cs
rename Messages/{EditPointDone.cs => RemovePointMessage.cs} (66%)
create mode 100644 Messages/RemovePropertyMessage.cs
create mode 100644 Messages/RequestImageMessage.cs
create mode 100644 Messages/SaveChangesMessage.cs
create mode 100644 Messages/SaveChangesResult.cs
create mode 100644 Messages/SelectionChangedMessage.cs
create mode 100644 Utils/ParentsHelper.cs
delete mode 100644 Utils/PropertyParentHelper.cs
create mode 100644 ViewModels/Basic/SaveChangesViewModel.cs
rename ViewModels/{EditEquipmentDialogViewModel.cs => EditEquipmentViewModel.cs} (57%)
rename ViewModels/{EditPointDialogViewModel.cs => EditPointViewModel.cs} (64%)
delete mode 100644 ViewModels/NewEquipmentDialogViewModel.cs
delete mode 100644 ViewModels/NewPointDialogViewModel.cs
delete mode 100644 Views/EditEquipmentDialog.axaml
delete mode 100644 Views/EditEquipmentDialog.axaml.cs
create mode 100644 Views/EditEquipmentView.axaml
create mode 100644 Views/EditEquipmentView.axaml.cs
delete mode 100644 Views/EditPointDialog.axaml
delete mode 100644 Views/EditPointDialog.axaml.cs
create mode 100644 Views/EditPointView.axaml
create mode 100644 Views/EditPointView.axaml.cs
create mode 100644 Views/EquipmentView.axaml
create mode 100644 Views/EquipmentView.axaml.cs
create mode 100644 Views/InspectionView.axaml
create mode 100644 Views/InspectionView.axaml.cs
delete mode 100644 Views/NewEquipmentDialog.axaml
delete mode 100644 Views/NewEquipmentDialog.axaml.cs
delete mode 100644 Views/NewPointDialog.axaml
delete mode 100644 Views/NewPointDialog.axaml.cs
create mode 100644 Views/PointView.axaml
create mode 100644 Views/PointView.axaml.cs
create mode 100644 Views/PropertyView.axaml
create mode 100644 Views/PropertyView.axaml.cs
create mode 100644 Views/SaveChangesView.axaml
create mode 100644 Views/SaveChangesView.axaml.cs
diff --git a/.idea/.idea.GazpromApp/.idea/avalonia.xml b/.idea/.idea.GazpromApp/.idea/avalonia.xml
index 122bbc9..a9dc23c 100644
--- a/.idea/.idea.GazpromApp/.idea/avalonia.xml
+++ b/.idea/.idea.GazpromApp/.idea/avalonia.xml
@@ -5,13 +5,20 @@
diff --git a/.idea/.idea.GazpromApp/.idea/dataSources.xml b/.idea/.idea.GazpromApp/.idea/dataSources.xml
index ecc4b04..609f8c1 100644
--- a/.idea/.idea.GazpromApp/.idea/dataSources.xml
+++ b/.idea/.idea.GazpromApp/.idea/dataSources.xml
@@ -9,5 +9,12 @@
jdbc:sqlite:identifier.sqlite
$ProjectFileDir$
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$USER_HOME$/AppData/Local/GazpromApp/GazpromApp.db
+ $ProjectFileDir$
+
\ No newline at end of file
diff --git a/App.axaml b/App.axaml
index 7287b36..1559c72 100644
--- a/App.axaml
+++ b/App.axaml
@@ -2,6 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="GazpromApp.App"
xmlns:local="using:GazpromApp"
+ xmlns:icons="using:Material.Icons.Avalonia"
+ xmlns:material="using:Material.Styles.Themes"
RequestedThemeVariant="Default">
@@ -10,6 +12,7 @@
-
+
+
\ No newline at end of file
diff --git a/GazpromApp.csproj b/GazpromApp.csproj
index 7a9e47b..56fe392 100644
--- a/GazpromApp.csproj
+++ b/GazpromApp.csproj
@@ -26,6 +26,8 @@
+
+
all
diff --git a/Messages/EditEquipmentMessage.cs b/Messages/EditEquipmentMessage.cs
index 00ae057..440747f 100644
--- a/Messages/EditEquipmentMessage.cs
+++ b/Messages/EditEquipmentMessage.cs
@@ -1,9 +1,9 @@
-using CommunityToolkit.Mvvm.Messaging.Messages;
+using System;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
-public class EditEquipmentMessage(EquipmentViewModel equipment) : AsyncRequestMessage
+public class EditEquipmentMessage(EquipmentViewModel equipment)
{
public EquipmentViewModel Equipment { get; } = equipment;
}
\ No newline at end of file
diff --git a/Messages/EditPointMessage.cs b/Messages/EditPointMessage.cs
index 85e0314..e074f02 100644
--- a/Messages/EditPointMessage.cs
+++ b/Messages/EditPointMessage.cs
@@ -1,9 +1,9 @@
-using CommunityToolkit.Mvvm.Messaging.Messages;
+using GazpromApp.Models;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
-public class EditPointMessage(PointViewModel pointViewModel) : AsyncRequestMessage
+public class EditPointMessage(PointViewModel point)
{
- public PointViewModel Point { get; } = pointViewModel;
+ public PointViewModel Point { get; } = point;
}
\ No newline at end of file
diff --git a/Messages/NewEquipmentDone.cs b/Messages/NewEquipmentDone.cs
deleted file mode 100644
index e22b780..0000000
--- a/Messages/NewEquipmentDone.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Messages;
-
-public class NewEquipmentDone(EquipmentViewModel equipment)
-{
- public EquipmentViewModel Equipment { get; } = equipment;
-}
\ No newline at end of file
diff --git a/Messages/NewEquipmentMessage.cs b/Messages/NewEquipmentMessage.cs
deleted file mode 100644
index e7e3d39..0000000
--- a/Messages/NewEquipmentMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using CommunityToolkit.Mvvm.Messaging.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Messages;
-
-public class NewEquipmentMessage : AsyncRequestMessage;
\ No newline at end of file
diff --git a/Messages/NewPointDone.cs b/Messages/NewPointDone.cs
deleted file mode 100644
index 90048b6..0000000
--- a/Messages/NewPointDone.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Messages;
-
-public class NewPointDone(PointViewModel pointViewModel)
-{
- public PointViewModel Point { get; } = pointViewModel;
-}
\ No newline at end of file
diff --git a/Messages/NewPointMessage.cs b/Messages/NewPointMessage.cs
deleted file mode 100644
index b376345..0000000
--- a/Messages/NewPointMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using CommunityToolkit.Mvvm.Messaging.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Messages;
-
-public class NewPointMessage : AsyncRequestMessage;
\ No newline at end of file
diff --git a/Messages/EditEquipmentDone.cs b/Messages/RemoveEquipmentMessage.cs
similarity index 66%
rename from Messages/EditEquipmentDone.cs
rename to Messages/RemoveEquipmentMessage.cs
index 2d9fe72..1e6cc11 100644
--- a/Messages/EditEquipmentDone.cs
+++ b/Messages/RemoveEquipmentMessage.cs
@@ -2,7 +2,7 @@
namespace GazpromApp.Messages;
-public class EditEquipmentDone(EquipmentViewModel equipment)
+public class RemoveEquipmentMessage(EquipmentViewModel equipment)
{
public EquipmentViewModel Equipment { get; } = equipment;
}
\ No newline at end of file
diff --git a/Messages/RemoveInspectionMessage.cs b/Messages/RemoveInspectionMessage.cs
new file mode 100644
index 0000000..e902fd7
--- /dev/null
+++ b/Messages/RemoveInspectionMessage.cs
@@ -0,0 +1,8 @@
+using GazpromApp.ViewModels;
+
+namespace GazpromApp.Messages;
+
+public class RemoveInspectionMessage(InspectionViewModel inspection)
+{
+ public InspectionViewModel Inspection { get; } = inspection;
+}
\ No newline at end of file
diff --git a/Messages/EditPointDone.cs b/Messages/RemovePointMessage.cs
similarity index 66%
rename from Messages/EditPointDone.cs
rename to Messages/RemovePointMessage.cs
index 6244253..e669790 100644
--- a/Messages/EditPointDone.cs
+++ b/Messages/RemovePointMessage.cs
@@ -2,7 +2,7 @@
namespace GazpromApp.Messages;
-public class EditPointDone(PointViewModel pointViewModel)
+public class RemovePointMessage(PointViewModel pointViewModel)
{
public PointViewModel Point { get; } = pointViewModel;
}
\ No newline at end of file
diff --git a/Messages/RemovePropertyMessage.cs b/Messages/RemovePropertyMessage.cs
new file mode 100644
index 0000000..deab9cc
--- /dev/null
+++ b/Messages/RemovePropertyMessage.cs
@@ -0,0 +1,8 @@
+using GazpromApp.ViewModels;
+
+namespace GazpromApp.Messages;
+
+public class RemovePropertyMessage(PropertyViewModel property)
+{
+ public PropertyViewModel Property { get; } = property;
+}
\ No newline at end of file
diff --git a/Messages/RequestImageMessage.cs b/Messages/RequestImageMessage.cs
new file mode 100644
index 0000000..356d9c3
--- /dev/null
+++ b/Messages/RequestImageMessage.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+using Avalonia.Platform.Storage;
+using CommunityToolkit.Mvvm.Messaging.Messages;
+using GazpromApp.ViewModels;
+
+namespace GazpromApp.Messages;
+
+public class RequestImageMessage(ViewModelBase viewModel) : AsyncRequestMessage>
+{
+ private ViewModelBase Caller { get; set; } = viewModel;
+}
\ No newline at end of file
diff --git a/Messages/SaveChangesMessage.cs b/Messages/SaveChangesMessage.cs
new file mode 100644
index 0000000..9ca09d5
--- /dev/null
+++ b/Messages/SaveChangesMessage.cs
@@ -0,0 +1,9 @@
+using CommunityToolkit.Mvvm.Messaging.Messages;
+using GazpromApp.ViewModels;
+
+namespace GazpromApp.Messages;
+
+public class SaveChangesMessage(SaveChangesViewModel saveChanges) : AsyncRequestMessage
+{
+ public SaveChangesViewModel SaveChanges { get; } = saveChanges;
+}
\ No newline at end of file
diff --git a/Messages/SaveChangesResult.cs b/Messages/SaveChangesResult.cs
new file mode 100644
index 0000000..e69d9dc
--- /dev/null
+++ b/Messages/SaveChangesResult.cs
@@ -0,0 +1,7 @@
+namespace GazpromApp.Messages;
+
+public class SaveChangesResult(bool save, bool cancel)
+{
+ public bool Save { get; } = save;
+ public bool Cancel { get; } = cancel;
+}
\ No newline at end of file
diff --git a/Messages/SelectionChangedMessage.cs b/Messages/SelectionChangedMessage.cs
new file mode 100644
index 0000000..03a8b39
--- /dev/null
+++ b/Messages/SelectionChangedMessage.cs
@@ -0,0 +1,8 @@
+using GazpromApp.ViewModels;
+
+namespace GazpromApp.Messages;
+
+public class SelectionChangedMessage(ViewModelBase viewModel)
+{
+ public ViewModelBase ViewModel { get; } = viewModel;
+}
\ No newline at end of file
diff --git a/Models/Equipment.cs b/Models/Equipment.cs
index 2e8d6c0..aafa26a 100644
--- a/Models/Equipment.cs
+++ b/Models/Equipment.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
@@ -7,28 +8,42 @@ namespace GazpromApp.Models;
public class Equipment
{
+ public Equipment()
+ {
+ LocalId = Id == Guid.Empty ? Guid.NewGuid() : Id;
+ }
+
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
- public int Id { get; set; }
+ public Guid Id { get; set; }
+
+ [JsonIgnore]
+ [NotMapped]
+ public Guid LocalId { get; set; }
[Required]
public string? Name { get; set; } = string.Empty;
public string? Description { get; set; } = string.Empty;
+ public DateTime CreationDate { get; set; }
// Foreign keys
- [Required]
[JsonIgnore]
- public int PointId { get; set; }
+ public Guid? PointId { get; set; }
[JsonIgnore]
- public List ImageIds { get; set; } = [];
+ public List ImageIds { get; set; } = [];
[JsonIgnore]
- public List InspectionIds { get; set; } = [];
+ public List InspectionIds { get; set; } = [];
+ [JsonIgnore]
+ public List EquipmentIds { get; set; } = [];
+ public Guid? ParentEquipmentId { get; set; }
// Navigation Properties
public List Images { get; set; } = [];
[JsonIgnore]
- public Point Point { get; set; } = null!;
+ public Point? Point { get; set; } = null!;
public List Properties { get; set; } = [];
public List Inspections { get; set; } = [];
+ public List Equipments { get; set; } = [];
+ public Equipment? ParentEquipment { get; set; }
}
\ No newline at end of file
diff --git a/Models/Image.cs b/Models/Image.cs
index cd02e00..0b7d8f9 100644
--- a/Models/Image.cs
+++ b/Models/Image.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel.DataAnnotations;
+using System;
+using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
@@ -9,16 +10,17 @@ public class Image
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
- public int Id { get; set; }
+ public Guid Id { get; set; }
[Required]
public byte[] Bytes { get; set; } = [];
+ public DateTime CreationDate { get; set; }
// Foreign keys
[JsonIgnore]
- public int? PointId { get; set; }
+ public Guid? PointId { get; set; }
[JsonIgnore]
- public int? EquipmentId { get; set; }
+ public Guid? EquipmentId { get; set; }
// Navigation Properties
[JsonIgnore]
diff --git a/Models/Inspection.cs b/Models/Inspection.cs
index 6e64e6b..afa8c18 100644
--- a/Models/Inspection.cs
+++ b/Models/Inspection.cs
@@ -10,10 +10,11 @@ public class Inspection
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
- public int Id { get; set; }
+ public Guid Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
+ public DateTime CreationDate { get; set; }
[Required]
public DateTimeOffset InspectionDate { get; set; }
[Required]
@@ -23,7 +24,7 @@ public class Inspection
// Foreign keys
[JsonIgnore]
- public int EquipmentId { get; set; }
+ public Guid EquipmentId { get; set; }
// Navigation Properties
[JsonIgnore]
diff --git a/Models/Point.cs b/Models/Point.cs
index de1e9a9..f174300 100644
--- a/Models/Point.cs
+++ b/Models/Point.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
@@ -10,11 +11,12 @@ public class Point
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
- public int Id { get; set; }
+ public Guid Id { get; set; } = Guid.NewGuid();
[Required]
public string? Name { get; set; } = string.Empty;
public string? Description { get; set; } = string.Empty;
+ public DateTime CreationDate { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
// Navigation Properties
diff --git a/Models/Property.cs b/Models/Property.cs
index 83975e2..f162100 100644
--- a/Models/Property.cs
+++ b/Models/Property.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
@@ -10,27 +11,28 @@ public class Property
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[JsonIgnore]
- public int Id { get; set; }
+ public Guid Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
+ public DateTime CreationDate { get; set; }
// For self-referencing hierarchy (Property of a Property)
[JsonIgnore]
- public int? ParentPropertyId { get; set; }
+ public Guid? ParentPropertyId { get; set; }
[JsonIgnore]
public Property? Parent { get; set; }
// For a Property of a Point
[JsonIgnore]
- public int? PointId { get; set; }
+ public Guid? PointId { get; set; }
[JsonIgnore]
public Point? Point { get; set; }
// For a Property of an Equipment
[JsonIgnore]
- public int? EquipmentId { get; set; }
+ public Guid? EquipmentId { get; set; }
[JsonIgnore]
public Equipment? Equipment { get; set; }
diff --git a/Utils/AppDbContext.cs b/Utils/AppDbContext.cs
index f0f16e9..cbca3a4 100644
--- a/Utils/AppDbContext.cs
+++ b/Utils/AppDbContext.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using GazpromApp.Models;
using Microsoft.EntityFrameworkCore;
@@ -17,13 +18,15 @@ public class AppDbContext : DbContext
public AppDbContext()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- DbPath = System.IO.Path.Combine(path, "GazpromApp.db");
+ Directory.CreateDirectory(Path.Combine(path, "GazpromApp"));
+ DbPath = Path.Combine(Path.Combine(path, "GazpromApp"), "GazpromApp.db");
}
public AppDbContext(DbContextOptions options) : base(options)
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- DbPath = System.IO.Path.Combine(path, "GazpromApp.db");
+ Directory.CreateDirectory(Path.Combine(path, "GazpromApp"));
+ DbPath = Path.Combine(Path.Combine(path, "GazpromApp"), "GazpromApp.db");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
@@ -41,6 +44,7 @@ public class AppDbContext : DbContext
.HasMany(p => p.Equipment)
.WithOne(e => e.Point)
.HasForeignKey(e => e.PointId)
+ .IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting a Point deletes its Equipment.
modelBuilder.Entity()
@@ -63,6 +67,13 @@ public class AppDbContext : DbContext
.HasForeignKey(i => i.EquipmentId)
.OnDelete(DeleteBehavior.Cascade); // Equipment has one Image.
+ modelBuilder.Entity()
+ .HasMany(e => e.Equipments)
+ .WithOne(e => e.ParentEquipment)
+ .HasForeignKey(e => e.ParentEquipmentId)
+ .IsRequired(false)
+ .OnDelete(DeleteBehavior.Cascade); // Equipment has many Equipments.
+
// ==== PROPERTY RELATIONSHIPS ====
// Property as a child of a Point
modelBuilder.Entity()
@@ -87,53 +98,5 @@ public class AppDbContext : DbContext
.HasForeignKey(p => p.ParentPropertyId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting a parent Property deletes its children.
-
- // modelBuilder.Entity()
- // .Property(p => p.Id)
- // .ValueGeneratedOnAdd();
- // modelBuilder.Entity()
- // .Property(e => e.Id)
- // .ValueGeneratedOnAdd();
- // modelBuilder.Entity()
- // .Property(i => i.Id)
- // .ValueGeneratedOnAdd();
- // modelBuilder.Entity()
- // .Property(p => p.Id)
- // .ValueGeneratedOnAdd();
- // modelBuilder.Entity()
- // .Property(i => i.Id)
- // .ValueGeneratedOnAdd();
- //
- // modelBuilder.Entity()
- // .HasMany(p => p.Images)
- // .WithMany(i => i.Points);
- // modelBuilder.Entity()
- // .HasMany(p => p.Equipment)
- // .WithOne(e => e.Point)
- // .HasForeignKey(e => e.PointId);
- // modelBuilder.Entity()
- // .HasMany(p => p.Properties)
- // .WithOne(p => p.Point)
- // .HasForeignKey(p => p.ParentId)
- // .IsRequired(false);
- //
- // modelBuilder.Entity()
- // .HasOne(e => e.Image)
- // .WithMany(i => i.Equipment);
- // modelBuilder.Entity()
- // .HasMany(e => e.Properties)
- // .WithOne(p => p.Equipment)
- // .HasForeignKey(p => p.ParentId)
- // .IsRequired(false);
- // modelBuilder.Entity()
- // .HasMany(e => e.Inspections)
- // .WithOne(i => i.Equipment)
- // .HasForeignKey(i => i.EquipmentId);
- //
- // modelBuilder.Entity()
- // .HasMany(p => p.Properties)
- // .WithOne(p => p.Parent)
- // .HasForeignKey(p => p.ParentId)
- // .IsRequired(false);
}
}
\ No newline at end of file
diff --git a/Utils/ParentsHelper.cs b/Utils/ParentsHelper.cs
new file mode 100644
index 0000000..217b449
--- /dev/null
+++ b/Utils/ParentsHelper.cs
@@ -0,0 +1,53 @@
+using System.Linq;
+using GazpromApp.Models;
+
+namespace GazpromApp.Utils;
+
+public static class ParentsHelper
+{
+ public static void SetPropertyParents(this Point point)
+ {
+ foreach (var prop in point.Properties)
+ {
+ SetPropertyParentsRecursively(prop);
+ }
+
+ foreach (var prop in point.Equipment.SelectMany(equipment => equipment.Properties))
+ {
+ SetPropertyParentsRecursively(prop);
+ }
+ }
+
+ private static void SetPropertyParentsRecursively(Property property)
+ {
+ foreach (var childProp in property.Properties)
+ {
+ childProp.Parent = property;
+ childProp.ParentPropertyId = property.Id;
+ SetPropertyParentsRecursively(childProp);
+ }
+ }
+
+ public static void SetEquipmentParents(this Point point)
+ {
+ foreach (var prop in point.Equipment)
+ {
+ SetEquipmentParentsRecursively(prop);
+ }
+
+ foreach (var prop in point.Equipment.SelectMany(equipment1 => equipment1.Equipments))
+ {
+ SetEquipmentParentsRecursively(prop);
+ }
+ }
+
+ private static void SetEquipmentParentsRecursively(Equipment equipment)
+ {
+ foreach (var childProp in equipment.Equipments)
+ {
+ childProp.ParentEquipment = equipment;
+ childProp.ParentEquipmentId = equipment.Id;
+ SetEquipmentParentsRecursively(childProp);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Utils/PropertyParentHelper.cs b/Utils/PropertyParentHelper.cs
deleted file mode 100644
index c082e83..0000000
--- a/Utils/PropertyParentHelper.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using GazpromApp.Models;
-using System.Linq;
-
-namespace GazpromApp.Utils;
-
-public static class PropertyParentHelper
-{
- public static void SetPropertyParents(this Point point)
- {
- foreach (var prop in point.Properties)
- {
- SetParentsRecursively(prop);
- }
-
- foreach (var prop in point.Equipment.SelectMany(equipment => equipment.Properties))
- {
- SetParentsRecursively(prop);
- }
- }
-
- private static void SetParentsRecursively(Property property)
- {
- foreach (var childProp in property.Properties)
- {
- childProp.Parent = property;
- childProp.ParentPropertyId = property.Id;
- SetParentsRecursively(childProp);
- }
- }
-}
\ No newline at end of file
diff --git a/ViewModels/Basic/EquipmentViewModel.cs b/ViewModels/Basic/EquipmentViewModel.cs
index 8092024..0ce2cc5 100644
--- a/ViewModels/Basic/EquipmentViewModel.cs
+++ b/ViewModels/Basic/EquipmentViewModel.cs
@@ -1,7 +1,11 @@
using System;
using System.Collections.ObjectModel;
+using System.Diagnostics;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using GazpromApp.Messages;
using GazpromApp.Models;
using GazpromApp.Utils;
@@ -9,6 +13,7 @@ namespace GazpromApp.ViewModels;
public partial class EquipmentViewModel : ViewModelBase
{
+ public ViewModelBase? Parent { get; set; }
private Equipment Equipment { get; }
[ObservableProperty]
@@ -17,31 +22,72 @@ public partial class EquipmentViewModel : ViewModelBase
[ObservableProperty]
private string? _description;
- public ObservableCollection Images { get; init; } = [];
-
- public ObservableCollection Properties { get; }
+ [ObservableProperty]
+ private DateTime _creationDate;
- public ObservableCollection Inspections { get; }
+ public ObservableCollection Images { get; set; } = [];
+
+ public ObservableCollection Properties { get; set; }
+
+ public ObservableCollection Inspections { get; set; }
+
+ public ObservableCollection Equipments { get; set; }
[ObservableProperty]
private string _nearestInspection;
+ [RelayCommand]
+ private void AddEquipment()
+ {
+ Equipments.Add(new EquipmentViewModel{ Name = "Новое оборудование", Description = "Описание оборудования", Parent = this});
+ CallSavePoint(this);
+ }
+
+ [RelayCommand]
+ private void RemoveEquipment()
+ {
+ WeakReferenceMessenger.Default.Send(new RemoveEquipmentMessage(this));
+ }
+
+ private void RemoveEquipment(object sender, RemoveEquipmentMessage msg)
+ {
+ if (Equipments.Contains(msg.Equipment))
+ Equipments.Remove(msg.Equipment);
+ CallSavePoint(this);
+ }
+
+ private void CallSavePoint(EquipmentViewModel equipment)
+ {
+ var current = equipment;
+ while (current.Parent is EquipmentViewModel model)
+ current = model ?? throw new InvalidOperationException("Parent equipment not found in hierarchy");
+
+ if (current.Parent is PointViewModel pointViewModel)
+ WeakReferenceMessenger.Default.Send(new EditPointMessage(pointViewModel));
+ }
+
public EquipmentViewModel()
{
Name = string.Empty;
Description = string.Empty;
+ CreationDate = DateTime.Now;
Properties = [];
Inspections = [];
+ Equipments = [];
NearestInspection = "Нету инспекций";
Equipment = new Equipment();
+
+ WeakReferenceMessenger.Default.Register(this, RemoveEquipment);
}
public EquipmentViewModel(Equipment equipment)
{
Name = equipment.Name;
Description = equipment.Description;
+ CreationDate = equipment.CreationDate;
Images = new ObservableCollection(equipment.Images.Select(i => new ImageViewModel(i)));
Properties = new ObservableCollection(equipment.Properties.Select(e => new PropertyViewModel(e)));
+ Equipments = new ObservableCollection(equipment.Equipments.Select(e => new EquipmentViewModel(e){Parent = this}));
var times = equipment.Inspections.Select(e => new InspectionViewModel(e))
.Select(e => e.GetNearestDates())
@@ -59,14 +105,20 @@ public partial class EquipmentViewModel : ViewModelBase
if (Inspections.Count == 0) NearestInspection = "Нету инспекций";
Equipment = equipment;
+
+ WeakReferenceMessenger.Default.Register(this, RemoveEquipment);
}
public Equipment GetEquipment()
{
Equipment.Name = Name;
Equipment.Description = Description;
+ Equipment.CreationDate = CreationDate;
Equipment.Images = Images.Select(e => e.GetImage()).ToList();
Equipment.Inspections = Inspections.Select(e => e.GetInspection()).ToList();
+ Equipment.Properties = Properties.Select(e => e.GetProperty()).ToList();
+ Equipment.Equipments = Equipments.Select(e => e.GetEquipment()).ToList();
+
return Equipment;
}
}
\ No newline at end of file
diff --git a/ViewModels/Basic/ImageViewModel.cs b/ViewModels/Basic/ImageViewModel.cs
index 4e04f2b..f42432c 100644
--- a/ViewModels/Basic/ImageViewModel.cs
+++ b/ViewModels/Basic/ImageViewModel.cs
@@ -1,31 +1,49 @@
-using System.IO;
+using System;
+using System.IO;
+using System.Threading.Tasks;
using Avalonia.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using GazpromApp.Messages;
using GazpromApp.Models;
namespace GazpromApp.ViewModels;
public partial class ImageViewModel : ViewModelBase
{
+ public ViewModelBase? Parent;
private Image Image { get; }
-
- [ObservableProperty]
- private byte[]? _bytes;
-
+
+ [ObservableProperty] private byte[]? _bytes;
+
+ [ObservableProperty] private DateTime _creationDate;
+
// EF stuff
-
- [ObservableProperty]
- private Point? _point;
-
- [ObservableProperty]
- private Equipment? _equipment;
-
- [ObservableProperty]
- private Bitmap? _fileName;
+
+ [ObservableProperty] private Point? _point;
+
+ [ObservableProperty] private Equipment? _equipment;
+
+ [ObservableProperty] private Bitmap? _fileName;
+
+ [RelayCommand]
+ private async Task ViewImage() => _ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(this));
+
+ [RelayCommand]
+ private void DeleteImage() => _ = Parent switch
+ {
+ PointViewModel pmv => pmv.Images.Remove(this),
+ EquipmentViewModel emv => emv.Images.Remove(this),
+ EditPointViewModel editPointViewModel => editPointViewModel.Images.Remove(this),
+ EditEquipmentViewModel editEquipmentViewModel => editEquipmentViewModel.Images.Remove(this),
+ _ => false
+ };
public ImageViewModel(Image image)
{
Bytes = image.Bytes;
+ CreationDate = image.CreationDate;
Equipment = image.Equipment;
Point = image.Point;
FileName = image.Bytes is { Length: > 0 } ? new Bitmap(new MemoryStream(image.Bytes)) : null;
@@ -35,6 +53,7 @@ public partial class ImageViewModel : ViewModelBase
public ImageViewModel()
{
Bytes = null;
+ CreationDate = DateTime.Now;
Equipment = null;
Point = null;
Image = new Image();
@@ -45,6 +64,7 @@ public partial class ImageViewModel : ViewModelBase
var ms = new MemoryStream();
FileName?.Save(ms);
Image.Bytes = ms.ToArray();
+ Image.CreationDate = CreationDate;
Image.Equipment = Equipment;
Image.Point = Point;
return Image;
diff --git a/ViewModels/Basic/InspectionViewModel.cs b/ViewModels/Basic/InspectionViewModel.cs
index bf7f4b9..1a18eea 100644
--- a/ViewModels/Basic/InspectionViewModel.cs
+++ b/ViewModels/Basic/InspectionViewModel.cs
@@ -1,6 +1,10 @@
using System;
+using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
using GazpromApp.Enums;
+using GazpromApp.Messages;
using GazpromApp.Models;
namespace GazpromApp.ViewModels;
@@ -11,6 +15,8 @@ public partial class InspectionViewModel : ViewModelBase
[ObservableProperty]
private string _name;
[ObservableProperty]
+ private DateTime _creationDate;
+ [ObservableProperty]
private DateTimeOffset _inspectionDate;
[ObservableProperty]
private PeriodType _periodType;
@@ -21,10 +27,25 @@ public partial class InspectionViewModel : ViewModelBase
[ObservableProperty]
private bool _isEditing;
+
+ [RelayCommand]
+ private void EditInspection()
+ {
+ IsEditing = !IsEditing;
+ }
+
+ [RelayCommand]
+ private void RemoveInspection() => WeakReferenceMessenger.Default.Send(new RemoveInspectionMessage(this));
+
+ // ReSharper disable once MemberCanBeMadeStatic.Global
+ public PeriodType[] AllPeriods => Enum.GetValues()
+ .Where(p => p != PeriodType.Unknown)
+ .ToArray();
public InspectionViewModel()
{
Name = string.Empty;
+ CreationDate = DateTime.Now;
InspectionDate = DateTimeOffset.Now;
PeriodType = 0;
PeriodValue = 1;
@@ -34,6 +55,7 @@ public partial class InspectionViewModel : ViewModelBase
public InspectionViewModel(Inspection inspection)
{
Name = inspection.Name;
+ CreationDate = inspection.CreationDate;
InspectionDate = inspection.InspectionDate;
PeriodType = inspection.PeriodType.ToPeriodType();
PeriodValue = inspection.PeriodValue;
@@ -43,6 +65,7 @@ public partial class InspectionViewModel : ViewModelBase
public Inspection GetInspection()
{
Inspection.Name = Name;
+ Inspection.CreationDate = CreationDate;
Inspection.InspectionDate = InspectionDate;
Inspection.PeriodType = PeriodType.ToDescription();
Inspection.PeriodValue = PeriodValue;
diff --git a/ViewModels/Basic/PointViewModel.cs b/ViewModels/Basic/PointViewModel.cs
index dc826ae..fd1f3d0 100644
--- a/ViewModels/Basic/PointViewModel.cs
+++ b/ViewModels/Basic/PointViewModel.cs
@@ -1,5 +1,12 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using GazpromApp.Messages;
using GazpromApp.Models;
namespace GazpromApp.ViewModels;
@@ -14,39 +21,64 @@ public partial class PointViewModel : ViewModelBase
[ObservableProperty]
private string? _description;
+ [ObservableProperty]
+ private DateTime _creationDate;
+
[ObservableProperty]
private double? _latitude;
[ObservableProperty]
private double? _longitude;
+
+ [RelayCommand]
+ private void AddEquipment()
+ {
+ Equipment.Add(new EquipmentViewModel(new Equipment()) {Name = "Новое оборудование", Description = "Описание оборудования", Parent = this});
+ WeakReferenceMessenger.Default.Send(new EditPointMessage(this));
+ }
+
+ [RelayCommand]
+ private void RemovePoint()
+ {
+ WeakReferenceMessenger.Default.Send(new RemovePointMessage(this));
+ }
+
+ private void RemoveEquipment(object sender, RemoveEquipmentMessage msg)
+ {
+ if (msg.Equipment.GetEquipment().Point == GetPoint())
+ Equipment.Remove(msg.Equipment);
+ }
- // EF stuff
[ObservableProperty]
- private List _images;
+ private ObservableCollection _images;
[ObservableProperty]
- private List _equipment;
+ private ObservableCollection _equipment;
[ObservableProperty]
- private List _properties;
+ private ObservableCollection _properties;
public PointViewModel(Point point)
{
Point = point;
Name = point.Name;
+ CreationDate = point.CreationDate;
Description = point.Description;
Latitude = point.Latitude;
Longitude = point.Longitude;
- Images = point.Images;
- Equipment = point.Equipment;
- Properties = point.Properties;
+ Images = new ObservableCollection(point.Images.Select(i => new ImageViewModel(i)));
+ Equipment = new ObservableCollection(point.Equipment.Select(i => new EquipmentViewModel(i){Parent = this}));
+ Properties = new ObservableCollection(point.Properties.Select(i => new PropertyViewModel(i)));
+
+ WeakReferenceMessenger.Default.Register(this, RemoveEquipment);
}
public Point GetPoint()
{
Point.Name = Name;
Point.Description = Description;
- Point.Equipment = Equipment;
- Point.Images = Images;
- Point.Properties = Properties;
+ Point.CreationDate = CreationDate;
+ Point.Equipment = Equipment.Select(e => e.GetEquipment()).ToList();
+ Point.Images = Images.Select(i => i.GetImage()).ToList();
+ Point.Properties = Properties.Select(p => p.GetProperty()).ToList();
return Point;
}
}
\ No newline at end of file
diff --git a/ViewModels/Basic/PropertyViewModel.cs b/ViewModels/Basic/PropertyViewModel.cs
index 32b20ed..616577f 100644
--- a/ViewModels/Basic/PropertyViewModel.cs
+++ b/ViewModels/Basic/PropertyViewModel.cs
@@ -1,6 +1,10 @@
-using System.Collections.ObjectModel;
+using System;
+using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using GazpromApp.Messages;
using GazpromApp.Models;
namespace GazpromApp.ViewModels;
@@ -8,6 +12,8 @@ namespace GazpromApp.ViewModels;
public partial class PropertyViewModel : ViewModelBase
{
+ public ViewModelBase? Parent { get; init; }
+
private Property Property { get; }
[ObservableProperty]
@@ -16,19 +22,36 @@ public partial class PropertyViewModel : ViewModelBase
[ObservableProperty]
private string _value;
+ [ObservableProperty]
+ private DateTime _creationDate;
+
public ObservableCollection Properties { get; set; }
// Visual and other properties
- public PropertyViewModel? Parent { get; init; }
-
[ObservableProperty]
private bool _isEditing;
+ [RelayCommand]
+ private void AddProperty() => Properties.Add(new PropertyViewModel() {Parent = this});
+
+ [RelayCommand]
+ private void RemoveProperty() => WeakReferenceMessenger.Default.Send(new RemovePropertyMessage(this));
+
+ [RelayCommand]
+ private void EditProperty() => IsEditing = !IsEditing;
+
+ private void RemoveProperty(object sender, RemovePropertyMessage msg)
+ {
+ if (Properties.Contains(msg.Property))
+ Properties.Remove(msg.Property);
+ }
+
public Property GetProperty(Property? parent = null)
{
Property.Name = Name;
Property.Value = Value;
+ Property.CreationDate = CreationDate;
Property.Parent = parent;
Property.Properties = Properties.Select(e => e.GetProperty(Property)).ToList();
return Property;
@@ -38,19 +61,25 @@ public partial class PropertyViewModel : ViewModelBase
{
Name = "Имя свойства";
Value = "Значение свойства";
+ CreationDate = DateTime.Now;
Properties = [];
Parent = null;
Property = new Property();
+
+ WeakReferenceMessenger.Default.Register(this, RemoveProperty);
}
public PropertyViewModel(Property property, PropertyViewModel? parent = null)
{
Name = property.Name;
Value = property.Value;
+ CreationDate = property.CreationDate;
Properties = new ObservableCollection(
property.Properties.Select(e => new PropertyViewModel(e, this)));
Parent = property.Parent is null ? null : parent;
Property = property;
+
+ WeakReferenceMessenger.Default.Register(this, RemoveProperty);
}
public PropertyViewModel(PropertyViewModel property)
@@ -60,5 +89,7 @@ public partial class PropertyViewModel : ViewModelBase
Properties = [];
Parent = property;
Property = new Property();
+
+ WeakReferenceMessenger.Default.Register(this, RemoveProperty);
}
}
\ No newline at end of file
diff --git a/ViewModels/Basic/SaveChangesViewModel.cs b/ViewModels/Basic/SaveChangesViewModel.cs
new file mode 100644
index 0000000..34153c2
--- /dev/null
+++ b/ViewModels/Basic/SaveChangesViewModel.cs
@@ -0,0 +1,42 @@
+using Avalonia.Controls;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using CommunityToolkit.Mvvm.Messaging;
+using GazpromApp.Enums;
+using GazpromApp.Messages;
+using GazpromApp.Models;
+using GazpromApp.Views;
+
+namespace GazpromApp.ViewModels;
+
+public partial class SaveChangesViewModel : ViewModelBase
+{
+ [ObservableProperty]
+ private bool _isSave;
+ [ObservableProperty]
+ private bool _isCancel;
+
+ [RelayCommand]
+ private void Cancel(Window w)
+ {
+ ((SaveChangesView)w).CanClose = true;
+ WeakReferenceMessenger.Default.Send(new SaveChangesResult(false, true));
+ w.Close(this);
+ }
+
+ [RelayCommand]
+ private void Save(Window w)
+ {
+ ((SaveChangesView)w).CanClose = true;
+ WeakReferenceMessenger.Default.Send(new SaveChangesResult(true, false));
+ w.Close(this);
+ }
+
+ [RelayCommand]
+ private void DontSave(Window w)
+ {
+ ((SaveChangesView)w).CanClose = true;
+ WeakReferenceMessenger.Default.Send(new SaveChangesResult(false, false));
+ w.Close(this);
+ }
+}
\ No newline at end of file
diff --git a/ViewModels/EditEquipmentDialogViewModel.cs b/ViewModels/EditEquipmentViewModel.cs
similarity index 57%
rename from ViewModels/EditEquipmentDialogViewModel.cs
rename to ViewModels/EditEquipmentViewModel.cs
index 68d9813..fcb9b2a 100644
--- a/ViewModels/EditEquipmentDialogViewModel.cs
+++ b/ViewModels/EditEquipmentViewModel.cs
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
-using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
@@ -16,26 +15,15 @@ using Image = GazpromApp.Models.Image;
namespace GazpromApp.ViewModels;
-public partial class EditEquipmentDialogViewModel : ViewModelBase
+public partial class EditEquipmentViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _name;
- [ObservableProperty]
- [NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
- private string? _description;
-
[ObservableProperty]
private bool _isNameEditing;
- [ObservableProperty]
- private bool _isDescriptionEditing;
-
- public ObservableCollection Images { get; set; }
-
- public ObservableCollection Inspections { get; set; }
-
[RelayCommand]
private void EditName()
{
@@ -43,6 +31,13 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
IsDescriptionEditing = false;
}
+ [ObservableProperty]
+ [NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
+ private string? _description;
+
+ [ObservableProperty]
+ private bool _isDescriptionEditing;
+
[RelayCommand]
private void EditDescription()
{
@@ -50,20 +45,17 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
IsNameEditing = false;
}
+ public ObservableCollection Images { get; set; }
+
[RelayCommand]
private async Task AddImage(Window w)
{
- var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- AllowMultiple = true,
- Title = "Выберите одну или несколько картинок",
- FileTypeFilter = [FilePickerFileTypes.ImageAll]
- });
+ var files = await WeakReferenceMessenger.Default.Send(new RequestImageMessage(this));
foreach (var file in files)
{
try
{
- Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath) ) });
+ Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath)), Parent = this});
}
catch (ArgumentException)
{
@@ -76,35 +68,20 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
}
}
-
- IsImagesEmpty = Images.Count == 0;
}
+ public ObservableCollection Inspections { get; set; }
+
[RelayCommand]
- private static async Task ViewImage(ImageViewModel image) => _ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(image));
+ private void AddInspection() => Inspections.Add(new InspectionViewModel
+ { Name = "Название инспекции", InspectionDate = DateTimeOffset.Now, PeriodValue = 1, PeriodType = PeriodType.Day });
+
+ private void RemoveInspection(object sender, RemoveInspectionMessage msg)
+ {
+ if (Inspections.Contains(msg.Inspection))
+ Inspections.Remove(msg.Inspection);
+ }
- [RelayCommand]
- private void DeleteImage(ImageViewModel image)
- {
- Images.Remove(image);
- IsImagesEmpty = Images.Count == 0;
- }
-
- [RelayCommand]
- private void AddInspection()
- {
- Inspections.Add(new InspectionViewModel { Name = "Название инспекции", InspectionDate = DateTimeOffset.Now, PeriodValue = 1, PeriodType = PeriodType.Day });
- }
-
- [RelayCommand]
- private void EditInspection(InspectionViewModel inspection)
- {
- foreach (var item in Inspections)
- if (item != inspection)
- item.IsEditing = false;
- inspection.IsEditing = !inspection.IsEditing;
- }
-
[RelayCommand]
private void DeleteInspection(InspectionViewModel inspection)
{
@@ -114,21 +91,12 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
public ObservableCollection Properties { get; set; }
[RelayCommand]
- private void AddPropertySimple() => Properties.Add(new PropertyViewModel());
+ private void AddProperty() => Properties.Add(new PropertyViewModel {Parent = this});
- [RelayCommand]
- private static void AddProperty(PropertyViewModel property) => property.Properties.Add(new PropertyViewModel(property));
-
- [RelayCommand]
- private static void EditProperty(PropertyViewModel property) => property.IsEditing = !property.IsEditing;
-
- [RelayCommand]
- private void DeleteProperty(PropertyViewModel property)
+ private void RemoveProperty(object sender, RemovePropertyMessage msg)
{
- if (property.Parent is null)
- Properties.Remove(property);
- else
- property.Parent?.Properties.Remove(property);
+ if (Properties.Contains(msg.Property))
+ Properties.Remove(msg.Property);
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
@@ -136,32 +104,24 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
- IsClosed = true;
- var equipment = new Equipment
- {
- Name = Name,
- Description = Description,
- Images = Images.Select(e => e.GetImage()).ToList(),
- Inspections = Inspections.Select(e => e.GetInspection()).ToList(),
- Properties = Properties.Select(e => e.GetProperty()).ToList()
- };
- WeakReferenceMessenger.Default.Send(new EditEquipmentDone(new EquipmentViewModel(equipment)));
+ _equipment.Name = Name;
+ _equipment.Description = Description;
+ _equipment.Images = Images;
+ _equipment.Inspections = Inspections;
+ _equipment.Properties = Properties;
+ _ = _equipment.GetEquipment();
+
+ CallUpdatePoint(_equipment);
}
-
+
[RelayCommand]
private void CancelEdit(Window w)
{
- IsClosed = true;
- WeakReferenceMessenger.Default.Send(new EditEquipmentDone(_equipment));
+ CallUpdatePoint(_equipment);
}
// Visual and other properties
-
- [ObservableProperty]
- private bool _isImagesEmpty;
- [ObservableProperty]
- private bool _isClosed;
private readonly EquipmentViewModel _equipment;
@@ -169,8 +129,23 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
public PeriodType[] AllPeriods => Enum.GetValues()
.Where(p => p != PeriodType.Unknown)
.ToArray();
+
+ private void CallUpdatePoint(ViewModelBase vm)
+ {
+ switch (vm)
+ {
+ case PointViewModel pointViewModel:
+ WeakReferenceMessenger.Default.Send(new EditPointMessage(pointViewModel));
+ break;
+ case EquipmentViewModel equipmentViewModel:
+ CallUpdatePoint(equipmentViewModel.Parent ?? throw new InvalidOperationException("Parent equipment not found in hierarchy"));
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(vm), vm, null);
+ }
+ }
- public EditEquipmentDialogViewModel()
+ public EditEquipmentViewModel()
{
Name = "Testing";
Description = "Testing";
@@ -178,12 +153,10 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
Inspections = [];
Properties = [];
- IsImagesEmpty = true;
-
_equipment = new EquipmentViewModel();
}
- public EditEquipmentDialogViewModel(EquipmentViewModel equipment)
+ public EditEquipmentViewModel(EquipmentViewModel equipment)
{
Name = equipment.Name;
Description = equipment.Description;
@@ -191,8 +164,14 @@ public partial class EditEquipmentDialogViewModel : ViewModelBase
Inspections = new ObservableCollection(equipment.Inspections.Select(e => e));
Properties = new ObservableCollection(equipment.Properties.Select(e => e));
- IsImagesEmpty = Images.Count == 0;
-
_equipment = equipment;
+
+ WeakReferenceMessenger.Default.Register(this, RemoveProperty);
+ WeakReferenceMessenger.Default.Register(this, RemoveInspection);
+ }
+
+ ~EditEquipmentViewModel()
+ {
+ WeakReferenceMessenger.Default.UnregisterAll(this);
}
}
\ No newline at end of file
diff --git a/ViewModels/EditPointDialogViewModel.cs b/ViewModels/EditPointViewModel.cs
similarity index 64%
rename from ViewModels/EditPointDialogViewModel.cs
rename to ViewModels/EditPointViewModel.cs
index 4720234..7cedae1 100644
--- a/ViewModels/EditPointDialogViewModel.cs
+++ b/ViewModels/EditPointViewModel.cs
@@ -5,7 +5,6 @@ using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
-using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
@@ -16,7 +15,7 @@ using Image = GazpromApp.Models.Image;
namespace GazpromApp.ViewModels;
-public partial class EditPointDialogViewModel : ViewModelBase
+public partial class EditPointViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
@@ -51,17 +50,12 @@ public partial class EditPointDialogViewModel : ViewModelBase
[RelayCommand]
private async Task AddImage(Window w)
{
- var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- AllowMultiple = true,
- Title = "Выберите одну или несколько картинок",
- FileTypeFilter = [FilePickerFileTypes.ImageAll]
- });
+ var files = await WeakReferenceMessenger.Default.Send(new RequestImageMessage(this));
foreach (var file in files)
{
try
{
- Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath) ) });
+ Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath)), Parent = this});
}
catch (ArgumentException)
{
@@ -74,66 +68,19 @@ public partial class EditPointDialogViewModel : ViewModelBase
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
}
}
-
- IsImagesEmpty = Images.Count == 0;
}
- [RelayCommand]
- private void DeleteImage(ImageViewModel image)
- {
- Images.Remove(image);
- IsImagesEmpty = Images.Count == 0;
- }
-
- [RelayCommand]
- private static async Task ViewImage(ImageViewModel image) => _ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(image));
-
public ObservableCollection Equipment { get; set; }
- [RelayCommand]
- private async Task AddEquipment()
- {
- var equipment = await WeakReferenceMessenger.Default.Send(new NewEquipmentMessage());
-
- if (equipment != null)
- Equipment.Add(equipment);
-
- IsEquipmentEmpty = Equipment.Count == 0;
- }
-
- [RelayCommand]
- private async Task EditEquipment(EquipmentViewModel equipment)
- {
- var e = await WeakReferenceMessenger.Default.Send(new EditEquipmentMessage(equipment)) ?? equipment;
- Equipment[Equipment.IndexOf(equipment)] = e;
- }
-
- [RelayCommand]
- private void DeleteEquipment(EquipmentViewModel equipment)
- {
- Equipment.Remove(equipment);
-
- IsEquipmentEmpty = Equipment.Count == 0;
- }
-
public ObservableCollection Properties { get; set; }
[RelayCommand]
- private void AddPropertySimple() => Properties.Add(new PropertyViewModel());
+ private void AddProperty() => Properties.Add(new PropertyViewModel {Parent = this});
- [RelayCommand]
- private static void AddProperty(PropertyViewModel property) => property.Properties.Add(new PropertyViewModel(property));
-
- [RelayCommand]
- private static void EditProperty(PropertyViewModel property) => property.IsEditing = !property.IsEditing;
-
- [RelayCommand]
- private void DeleteProperty(PropertyViewModel property)
+ private void RemoveProperty(object sender, RemovePropertyMessage msg)
{
- if (property.Parent is null)
- Properties.Remove(property);
- else
- property.Parent?.Properties.Remove(property);
+ if (Properties.Contains(msg.Property))
+ Properties.Remove(msg.Property);
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
@@ -141,41 +88,30 @@ public partial class EditPointDialogViewModel : ViewModelBase
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
- IsClosed = true;
_point.Name = Name;
_point.Description = Description;
- _point.Images = Images.Select(e => e.GetImage()).ToList();
- _point.Equipment = Equipment.Select(e => e.GetEquipment()).ToList();
- _point.Properties = Properties.Select(e => e.GetProperty()).ToList();
+ _point.Images = Images;
+ _point.Equipment = Equipment;
+ _point.Properties = Properties;
_ = _point.GetPoint();
- WeakReferenceMessenger.Default.Send(new EditPointDone(new PointViewModel(_point.GetPoint())));
+ WeakReferenceMessenger.Default.Send(new EditPointMessage(_point));
}
[RelayCommand]
private void CancelEdit(Window w)
{
- IsClosed = true;
- WeakReferenceMessenger.Default.Send(new EditPointDone(_point));
+ WeakReferenceMessenger.Default.Send(new EditPointMessage(_point));
}
// Visual and other properties
- [ObservableProperty]
- private bool _isImagesEmpty;
-
- [ObservableProperty]
- private bool _isEquipmentEmpty;
-
- [ObservableProperty]
- private bool _isClosed;
-
private readonly PointViewModel _point;
- public EditPointDialogViewModel()
+ public EditPointViewModel()
{
- Name = "";
- Description = "";
+ Name = "fsdfasdfasd";
+ Description = "asfasdfasdfa";
Images = [];
Equipment = [
new EquipmentViewModel
@@ -245,23 +181,25 @@ public partial class EditPointDialogViewModel : ViewModelBase
}
];
- IsImagesEmpty = true;
- IsEquipmentEmpty = true;
-
- _point = new PointViewModel(new Point());
+ _point = new PointViewModel(new Point());
}
- public EditPointDialogViewModel(PointViewModel point)
+ public EditPointViewModel(PointViewModel point)
{
Name = point.Name;
Description = point.Description;
- Images = new ObservableCollection(point.Images.Select(e => new ImageViewModel(e)));
- Equipment = new ObservableCollection(point.Equipment.Select(e => new EquipmentViewModel(e)));
- Properties = new ObservableCollection(point.Properties.Select(e => new PropertyViewModel(e)));
-
- IsImagesEmpty = Images.Count == 0;
- IsEquipmentEmpty = Equipment.Count == 0;
+ Images = new ObservableCollection(point.Images);
+ Images.ToList().ForEach(i => i.Parent = this);
+ Equipment = new ObservableCollection(point.Equipment);
+ Properties = new ObservableCollection(point.Properties);
_point = point;
+
+ WeakReferenceMessenger.Default.Register(this, RemoveProperty);
+ }
+
+ ~EditPointViewModel()
+ {
+ WeakReferenceMessenger.Default.UnregisterAll(this);
}
}
\ No newline at end of file
diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs
index 33ec53a..b803084 100644
--- a/ViewModels/MainWindowViewModel.cs
+++ b/ViewModels/MainWindowViewModel.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Collections.ObjectModel;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
@@ -21,14 +21,19 @@ public partial class MainWindowViewModel : ViewModelBase
{
public ObservableCollection Points { get; set; }
+ [ObservableProperty]
+ private object? _selectedItem;
+
+ [ObservableProperty]
+ private ViewModelBase? _selectedItemViewModel;
+
[RelayCommand]
private async Task AddPoint()
{
- var point = await WeakReferenceMessenger.Default.Send(new NewPointMessage());
- if (point == null) return;
-
IsLoading = true;
+ var point = new PointViewModel(new Point {Name = "Новый объект", Description = "Описание объекта"});
+
_context.Point.Add(point.GetPoint());
await _context.SaveChangesAsync();
@@ -37,49 +42,16 @@ public partial class MainWindowViewModel : ViewModelBase
IsLoading = false;
}
- [RelayCommand]
- private async Task EditPoint(PointViewModel point)
- {
- var p = await WeakReferenceMessenger.Default.Send(new EditPointMessage(point));
- if (p == null) return;
-
- IsLoading = true;
-
- _context.Update(p.GetPoint());
- await _context.SaveChangesAsync();
-
- var index = Points.IndexOf(point);
- if (index != -1)
- Points[index] = p;
-
- IsLoading = false;
- }
-
- [RelayCommand]
- private async Task RemovePoint(PointViewModel point)
- {
- IsLoading = true;
-
- var pointInDb = await _context.Point.FindAsync(point.GetPoint().Id);
- if (pointInDb == null) return;
-
- _context.Remove(pointInDb);
- await _context.SaveChangesAsync();
-
- Points.Remove(point);
-
- IsLoading = false;
- }
-
[RelayCommand]
private async Task ImportPoint(Window w)
{
+ Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"));
var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
AllowMultiple = true,
SuggestedStartLocation =
await w.StorageProvider.TryGetFolderFromPathAsync(
- Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"))
});
if (files.Count < 1) return;
@@ -92,6 +64,7 @@ public partial class MainWindowViewModel : ViewModelBase
var decoded = HttpUtility.UrlDecode(url);
var point = DataSerialization.LoadPoint(decoded);
point?.SetPropertyParents();
+ point?.SetEquipmentParents();
if (point == null) continue;
_context.Point.Add(point);
@@ -108,33 +81,81 @@ public partial class MainWindowViewModel : ViewModelBase
[RelayCommand]
private async Task ExportPoint(Window w)
{
+ Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"));
var folder = await w.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
AllowMultiple = false,
SuggestedStartLocation =
await w.StorageProvider.TryGetFolderFromPathAsync(
- Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments))
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"))
});
if (folder.Count != 1) return;
foreach (var point in Points)
DataSerialization.SavePoint(point.GetPoint(), Path.Combine(HttpUtility.UrlDecode(folder[0].Path.AbsolutePath), point.Name + ".json") );
}
+
+ [ObservableProperty]
+ [NotifyCanExecuteChangedFor(nameof(SyncDbCommand))]
+ private bool _canSync = false;
+
+ private bool CanSyncDb() => CanSync;
+
+ [RelayCommand(CanExecute = nameof(CanSyncDb))]
+ private async Task SyncDb()
+ {
+ IsLoading = true;
+
+ foreach (var point in _pointsToUpdate)
+ {
+ _context.Update(point.GetPoint());
+
+ var index = Points.IndexOf(point);
+ if (index != -1)
+ Points[index] = point;
+ }
+ await _context.SaveChangesAsync();
+
+ foreach (var point in _pointsToDelete)
+ {
+ var pointInDb = await _context.Point.FindAsync(point.GetPoint().Id);
+ if (pointInDb == null) continue;
+
+ _context.Remove(pointInDb);
+
+ Points.Remove(point);
+ }
+ await _context.SaveChangesAsync();
+
+ _pointsToUpdate.Clear();
+ _pointsToDelete.Clear();
+
+
+ IsLoading = false;
+ CanSync = false;
+ }
// Visual and other properties
[ObservableProperty] private bool _isLoading = true;
private readonly AppDbContext _context;
- private async Task LoadChildrenForProperties(List properties)
+ private async Task LoadChildrenForProperties(List properties, HashSet loadedIds)
{
if (properties.Count == 0)
return;
- var parentIds = properties.Select(p => p.Id).ToList();
+ var parentIds = properties.Select(p => p.Id)
+ .Where(id => !loadedIds.Contains(id))
+ .ToList();
+
+ if (parentIds.Count == 0)
+ return;
+
+ parentIds.ForEach(id => loadedIds.Add(id));
var children = await _context.Property
.Where(p => p.ParentPropertyId.HasValue && parentIds.Contains(p.ParentPropertyId.Value))
- .AsNoTracking()
+ .OrderBy(p => p.CreationDate)
.ToListAsync();
if (children.Count != 0)
@@ -142,36 +163,85 @@ public partial class MainWindowViewModel : ViewModelBase
var childrenLookup = children.ToLookup(child => child.ParentPropertyId);
foreach (var parent in properties.Where(parent => childrenLookup.Contains(parent.Id)))
- parent.Properties.AddRange(childrenLookup[parent.Id]);
+ {
+ parent.Properties.Clear();
+ parent.Properties.AddRange(childrenLookup[parent.Id]);
+ }
- // ReSharper disable once TailRecursiveCall
- await LoadChildrenForProperties(children);
+ await LoadChildrenForProperties(children, loadedIds);
}
}
+
+ private async Task LoadChildrenForEquipments(List equipments, HashSet loadedIds)
+ {
+ if (equipments.Count == 0)
+ return;
+
+ var parentIds = equipments.Select(e => e.Id)
+ .Where(id => !loadedIds.Contains(id))
+ .ToList();
+
+ if (parentIds.Count == 0)
+ return;
+
+ parentIds.ForEach(id => loadedIds.Add(id));
+
+ var children = await _context.Equipment
+ .Where(e => e.ParentEquipmentId.HasValue && parentIds.Contains(e.ParentEquipmentId.Value))
+ .OrderBy(e => e.CreationDate)
+ .ToListAsync();
+
+ if (children.Count != 0)
+ {
+ var childrenLookup = children.ToLookup(child => child.ParentEquipmentId);
+
+ foreach (var parent in equipments.Where(parent => childrenLookup.Contains(parent.Id)))
+ {
+ parent.Equipments.Clear();
+ parent.Equipments.AddRange(childrenLookup[parent.Id]);
+ }
+
+ await LoadChildrenForEquipments(children, loadedIds);
+ }
+ }
+
private async Task LoadDataAsync()
{
IsLoading = true;
+ // ReSharper disable once EntityFramework.NPlusOne.IncompleteDataQuery
var pointsFromDb = await _context.Point
- .Include(p => p.Images)
+ .OrderBy(p => p.CreationDate)
+ .Include(p => p.Images
+ .OrderBy(i => i.CreationDate))
+ .Include(p => p.Equipment
+ .OrderBy(e => e.CreationDate))
+ .ThenInclude(e => e.Properties
+ .OrderBy(p => p.CreationDate))
.Include(p => p.Equipment)
- .ThenInclude(e => e.Properties)
+ .ThenInclude(e => e.Images
+ .OrderBy(i => i.CreationDate))
.Include(p => p.Equipment)
- .ThenInclude(e => e.Images)
- .Include(p => p.Equipment)
- .ThenInclude(e => e.Inspections)
- .Include(p => p.Properties)
- .AsNoTracking()
+ .ThenInclude(e => e.Inspections
+ .OrderBy(i => i.CreationDate))
+ .Include(p => p.Properties
+ .OrderBy(p => p.CreationDate))
.ToListAsync();
var topLevelProperties = pointsFromDb.SelectMany(p => p.Properties)
.Concat(pointsFromDb.SelectMany(p => p.Equipment).SelectMany(e => e.Properties))
.ToList();
- if (topLevelProperties.Count != 0)
- await LoadChildrenForProperties(topLevelProperties);
+ var topLevelEquipments = pointsFromDb.SelectMany(p => p.Equipment)
+ .ToList();
+ if (topLevelProperties.Count != 0)
+ await LoadChildrenForProperties(topLevelProperties, []);
+
+ if (topLevelEquipments.Count != 0)
+ await LoadChildrenForEquipments(topLevelEquipments, []);
+
Points.Clear();
foreach (var point in pointsFromDb)
Points.Add(new PointViewModel(point));
@@ -179,16 +249,48 @@ public partial class MainWindowViewModel : ViewModelBase
IsLoading = false;
}
+ private readonly ObservableCollection _pointsToUpdate = [];
+ private readonly ObservableCollection _pointsToDelete = [];
+
+ private void EditPoint(object sender, EditPointMessage msg)
+ {
+ if (!_pointsToUpdate.Contains(msg.Point))
+ _pointsToUpdate.Add(msg.Point);
+ CanSync = true;
+ }
+
+ private void RemovePoint(object sender, RemovePointMessage msg)
+ {
+ if (!_pointsToDelete.Contains(msg.Point))
+ _pointsToDelete.Add(msg.Point);
+ Points.Remove(msg.Point);
+ CanSync = true;
+ }
+
+ private void HandleSelectionChanged(object sender, SelectionChangedMessage msg)
+ {
+ SelectedItemViewModel = msg.ViewModel switch
+ {
+ PointViewModel pointViewModel => new EditPointViewModel(pointViewModel),
+ EquipmentViewModel equipmentViewModel => new EditEquipmentViewModel(equipmentViewModel),
+ _ => msg.ViewModel
+ };
+ }
+
public MainWindowViewModel(AppDbContext context)
{
Points = [];
_context = context;
_ = LoadDataAsync();
+
+ WeakReferenceMessenger.Default.Register(this, EditPoint);
+ WeakReferenceMessenger.Default.Register(this, RemovePoint);
+ WeakReferenceMessenger.Default.Register(this, HandleSelectionChanged);
}
public MainWindowViewModel()
{
- Points = [new PointViewModel(new Point()) { Name = "Name test", Description = "Description test" }];
+ Points = [new PointViewModel(new Point()) { Name = "Новый объект", Description = "Описание объекта" }];
_context = new AppDbContext();
IsLoading = false;
}
diff --git a/ViewModels/NewEquipmentDialogViewModel.cs b/ViewModels/NewEquipmentDialogViewModel.cs
deleted file mode 100644
index 0b1e93b..0000000
--- a/ViewModels/NewEquipmentDialogViewModel.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Web;
-using Avalonia.Controls;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform.Storage;
-using CommunityToolkit.Mvvm.ComponentModel;
-using CommunityToolkit.Mvvm.Input;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Enums;
-using GazpromApp.Messages;
-using GazpromApp.Models;
-using Image = GazpromApp.Models.Image;
-
-namespace GazpromApp.ViewModels;
-
-public partial class NewEquipmentDialogViewModel : ViewModelBase
-{
- [ObservableProperty]
- [NotifyCanExecuteChangedFor(nameof(EnterEquipmentCommand))]
- private string? _name;
-
- [ObservableProperty]
- [NotifyCanExecuteChangedFor(nameof(EnterEquipmentCommand))]
- private string? _description;
-
- public ObservableCollection Images { get; } = [];
-
- [RelayCommand]
- private async Task AddImage(Window w)
- {
- var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- AllowMultiple = true,
- Title = "Выберите одну или несколько картинок",
- FileTypeFilter = [FilePickerFileTypes.ImageAll]
- });
-
- foreach (var file in files)
- {
- try
- {
- Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath)) });
- }
- catch (ArgumentException)
- {
- var error = new Error
- {
- Title = "Ошибка обработки картинки",
- Message = $"Картинка не была добавлена: \"{HttpUtility.UrlDecode(file.Name)}\"",
- Severity = ErrorSeverity.Error
- };
- _ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
- }
- }
-
- IsImagesEmpty = Images.Count == 0;
- }
-
- [RelayCommand]
- private void DeleteImage(ImageViewModel image)
- {
- Images.Remove(image);
- IsImagesEmpty = Images.Count == 0;
- }
-
- private bool CanEnterEquipment() => !string.IsNullOrEmpty(Name);
-
- [RelayCommand (CanExecute = nameof(CanEnterEquipment))]
- private void EnterEquipment()
- {
- var equipment = new Equipment
- {
- Name = Name,
- Description = Description ?? string.Empty,
- Images = Images.Select(e => e.GetImage()).ToList()
-
- };
- WeakReferenceMessenger.Default.Send(new NewEquipmentDone(new EquipmentViewModel(equipment)));
- }
-
- [RelayCommand]
- private static void CancelEnterEquipment(Window w)
- {
- w.Close();
- }
-
- // Visual and other stuff
-
- [ObservableProperty]
- private bool _isImagesEmpty;
-}
\ No newline at end of file
diff --git a/ViewModels/NewPointDialogViewModel.cs b/ViewModels/NewPointDialogViewModel.cs
deleted file mode 100644
index b8a6c22..0000000
--- a/ViewModels/NewPointDialogViewModel.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Web;
-using Avalonia.Controls;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform.Storage;
-using CommunityToolkit.Mvvm.ComponentModel;
-using CommunityToolkit.Mvvm.Input;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Enums;
-using GazpromApp.Messages;
-using GazpromApp.Models;
-using Image = GazpromApp.Models.Image;
-using Point = GazpromApp.Models.Point;
-
-namespace GazpromApp.ViewModels;
-
-public partial class NewPointDialogViewModel : ViewModelBase
-{
- [ObservableProperty]
- [NotifyCanExecuteChangedFor(nameof(EnterPointCommand))]
- private string? _name;
-
- [ObservableProperty]
- [NotifyCanExecuteChangedFor(nameof(EnterPointCommand))]
- private string? _description;
-
- public ObservableCollection Images { get; } = [];
-
- [RelayCommand]
- private async Task AddImage(Window w)
- {
- var files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
- {
- AllowMultiple = true,
- Title = "Выберите одну или несколько картинок",
- FileTypeFilter = [FilePickerFileTypes.ImageAll]
- });
- foreach (var file in files)
- {
- try
- {
- Images.Add(new ImageViewModel(new Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(file.Path.AbsolutePath)) });
- }
- catch (ArgumentException)
- {
- var error = new Error
- {
- Title = "Ошибка обработки картинки",
- Message = $"Картинка не была добавлена: \"{HttpUtility.UrlDecode(file.Name)}\"",
- Severity = ErrorSeverity.Error
- };
- _ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
- }
- }
-
- IsImagesEmpty = Images.Count == 0;
- }
-
- [RelayCommand]
- private void DeleteImage(ImageViewModel image)
- {
- Images.Remove(image);
- IsImagesEmpty = Images.Count == 0;
- }
-
- private bool CanEnterPoint() => !string.IsNullOrEmpty(Name);
-
- [RelayCommand (CanExecute = nameof(CanEnterPoint))]
- private void EnterPoint()
- {
- var point = new Point
- {
- Name = Name,
- Description = Description,
- Images = Images.Select(e => e.GetImage()).ToList()
- };
- WeakReferenceMessenger.Default.Send(new NewPointDone(new PointViewModel(point)));
- }
-
- [RelayCommand]
- private static void CancelEnterPoint(Window w)
- {
- w.Close();
- }
-
- // Visual properties
-
- [ObservableProperty]
- private bool _isImagesEmpty = true;
-}
\ No newline at end of file
diff --git a/Views/EditEquipmentDialog.axaml b/Views/EditEquipmentDialog.axaml
deleted file mode 100644
index 6077be6..0000000
--- a/Views/EditEquipmentDialog.axaml
+++ /dev/null
@@ -1,225 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Views/EditEquipmentDialog.axaml.cs b/Views/EditEquipmentDialog.axaml.cs
deleted file mode 100644
index a7d7ff3..0000000
--- a/Views/EditEquipmentDialog.axaml.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using Avalonia.Controls;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Views;
-
-public partial class EditEquipmentDialog : Window
-{
- public EditEquipmentDialog()
- {
- InitializeComponent();
-
- if (Design.IsDesignMode)
- return;
-
- // view image
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ImageView
- {
- DataContext = m.Image
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // error handling
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // complete editing equipment
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- w.Close(m.Equipment);
- });
- }
-
- private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
- {
- if (DataContext is EditEquipmentDialogViewModel { IsClosed: false } vm)
- vm.CancelEditCommand.Execute(this);
- }
-
- private void Window_OnClosed(object? sender, EventArgs e)
- {
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- }
-}
\ No newline at end of file
diff --git a/Views/EditEquipmentView.axaml b/Views/EditEquipmentView.axaml
new file mode 100644
index 0000000..ecbd451
--- /dev/null
+++ b/Views/EditEquipmentView.axaml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/EditEquipmentView.axaml.cs b/Views/EditEquipmentView.axaml.cs
new file mode 100644
index 0000000..cb9c5c2
--- /dev/null
+++ b/Views/EditEquipmentView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class EditEquipmentView : UserControl
+{
+ public EditEquipmentView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/EditPointDialog.axaml b/Views/EditPointDialog.axaml
deleted file mode 100644
index 5084c78..0000000
--- a/Views/EditPointDialog.axaml
+++ /dev/null
@@ -1,220 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Views/EditPointDialog.axaml.cs b/Views/EditPointDialog.axaml.cs
deleted file mode 100644
index 6108110..0000000
--- a/Views/EditPointDialog.axaml.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-using System;
-using Avalonia.Controls;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Views;
-
-public partial class EditPointDialog : Window
-{
- public EditPointDialog()
- {
- InitializeComponent();
-
- if (Design.IsDesignMode)
- return;
-
- // view image
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ImageView
- {
- DataContext = m.Image
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // error
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // new equipment
- WeakReferenceMessenger.Default.Register(this, (w, m) =>
- {
- WeakReferenceMessenger.Default.Unregister(this);
- var dialog = new NewEquipmentDialog
- {
- DataContext = new NewEquipmentDialogViewModel()
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // edit equipment
- WeakReferenceMessenger.Default.Register(this, (w, m) =>
- {
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- var dialog = new EditEquipmentDialog
- {
- DataContext = new EditEquipmentDialogViewModel(m.Equipment)
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- // re registering error when new equipment done
- WeakReferenceMessenger.Default.Register(this, (_, _) =>
- {
- if (!WeakReferenceMessenger.Default.IsRegistered(this))
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
- });
-
- // re registering view image and error view
- WeakReferenceMessenger.Default.Register(this, (_, _) =>
- {
- if (!WeakReferenceMessenger.Default.IsRegistered(this))
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ImageView
- {
- DataContext = m.Image
- };
- m.Reply(dialog.ShowDialog(w));
- });
- if (!WeakReferenceMessenger.Default.IsRegistered(this))
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
- });
-
- // complete editing point
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- w.Close(m.Point);
- });
- }
-
- private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
- {
- if (DataContext is EditPointDialogViewModel { IsClosed: false } vm)
- vm.CancelEditCommand.Execute(this);
- }
-
- private void Window_OnClosed(object? sender, EventArgs e)
- {
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- }
-}
\ No newline at end of file
diff --git a/Views/EditPointView.axaml b/Views/EditPointView.axaml
new file mode 100644
index 0000000..d77f333
--- /dev/null
+++ b/Views/EditPointView.axaml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/EditPointView.axaml.cs b/Views/EditPointView.axaml.cs
new file mode 100644
index 0000000..3247ae4
--- /dev/null
+++ b/Views/EditPointView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class EditPointView : UserControl
+{
+ public EditPointView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/EquipmentView.axaml b/Views/EquipmentView.axaml
new file mode 100644
index 0000000..a2334d3
--- /dev/null
+++ b/Views/EquipmentView.axaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/EquipmentView.axaml.cs b/Views/EquipmentView.axaml.cs
new file mode 100644
index 0000000..a559c6d
--- /dev/null
+++ b/Views/EquipmentView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class EquipmentView : UserControl
+{
+ public EquipmentView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/InspectionView.axaml b/Views/InspectionView.axaml
new file mode 100644
index 0000000..20a7939
--- /dev/null
+++ b/Views/InspectionView.axaml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/InspectionView.axaml.cs b/Views/InspectionView.axaml.cs
new file mode 100644
index 0000000..33a2c0c
--- /dev/null
+++ b/Views/InspectionView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class InspectionView : UserControl
+{
+ public InspectionView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/MainWindow.axaml b/Views/MainWindow.axaml
index aea9bcf..2408919 100644
--- a/Views/MainWindow.axaml
+++ b/Views/MainWindow.axaml
@@ -4,43 +4,27 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:anim="https://github.com/whistyun/AnimatedImage.Avalonia"
xmlns:vm="using:GazpromApp.ViewModels"
+ xmlns:views="using:GazpromApp.Views"
+ xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="1024" d:DesignHeight="600"
- Width="1024" Height="600"
x:Class="GazpromApp.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
x:Name="Window"
Icon="/Assets/gazpromapp.ico"
Title="GazpromApp"
- WindowStartupLocation="CenterScreen">
+ WindowState="Maximized"
+ Closing="Window_OnClosing">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/MainWindow.axaml.cs b/Views/MainWindow.axaml.cs
index 8539032..19b4c67 100644
--- a/Views/MainWindow.axaml.cs
+++ b/Views/MainWindow.axaml.cs
@@ -1,4 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading.Tasks;
using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.Messaging;
using GazpromApp.Messages;
using GazpromApp.ViewModels;
@@ -7,29 +13,79 @@ namespace GazpromApp.Views;
public partial class MainWindow : Window
{
+ private bool _canClose = false;
public MainWindow()
{
InitializeComponent();
if (Design.IsDesignMode)
return;
+
+ WeakReferenceMessenger.Default.Register(this, HandleImageSelection);
+ WeakReferenceMessenger.Default.Register(this, HandleImageViewer);
+ WeakReferenceMessenger.Default.Register(this, HandleErrorViewer);
+ WeakReferenceMessenger.Default.Register(this, HandleSave);
+ }
+
+ private static void HandleImageSelection(MainWindow sender, RequestImageMessage msg)
+ {
+ var files = sender.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
+ {
+ AllowMultiple = true,
+ Title = "Выберите одну или несколько картинок",
+ FileTypeFilter = [FilePickerFileTypes.ImageAll]
+ });
+
+ msg.Reply(files);
+ }
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
+ private static void HandleImageViewer(MainWindow sender, ViewImageMessage msg)
+ {
+ var dialog = new ImageView
{
- var dialog = new NewPointDialog
- {
- DataContext = new NewPointDialogViewModel()
- };
- m.Reply(dialog.ShowDialog(w));
- });
-
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
+ DataContext = msg.Image
+ };
+ msg.Reply(dialog.ShowDialog(sender));
+ }
+
+ private static void HandleErrorViewer(MainWindow sender, ErrorMessage msg)
+ {
+ var dialog = new ErrorView
{
- var dialog = new EditPointDialog
- {
- DataContext = new EditPointDialogViewModel(m.Point)
- };
- m.Reply(dialog.ShowDialog(w));
- });
+ DataContext = msg.Error
+ };
+ msg.Reply(dialog.ShowDialog(sender));
+ }
+
+ private void TreeView_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
+ {
+ if (e.AddedItems.Count > 0)
+ WeakReferenceMessenger.Default.Send(new SelectionChangedMessage((ViewModelBase)e.AddedItems[0]!));
+ }
+
+ private void HandleSave(object sender, SaveChangesResult msg)
+ {
+ if (msg.Cancel) return;
+ if (msg.Save)
+ ((MainWindowViewModel)DataContext!).SyncDbCommand.Execute(null);
+ ForceClose();
+ }
+
+ private void ForceClose()
+ {
+ _canClose = true;
+ Close();
+ }
+
+ private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
+ {
+ if (_canClose) return;
+ if (!((MainWindowViewModel)DataContext!).CanSync) return;
+ var dialog = new SaveChangesView
+ {
+ DataContext = new SaveChangesViewModel()
+ };
+ dialog.ShowDialog(this);
+ e.Cancel = true;
}
}
\ No newline at end of file
diff --git a/Views/NewEquipmentDialog.axaml b/Views/NewEquipmentDialog.axaml
deleted file mode 100644
index 647f83c..0000000
--- a/Views/NewEquipmentDialog.axaml
+++ /dev/null
@@ -1,76 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Views/NewEquipmentDialog.axaml.cs b/Views/NewEquipmentDialog.axaml.cs
deleted file mode 100644
index d89da85..0000000
--- a/Views/NewEquipmentDialog.axaml.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using Avalonia.Controls;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Views;
-
-public partial class NewEquipmentDialog : Window
-{
- public NewEquipmentDialog()
- {
- InitializeComponent();
-
- // done entering new equipment
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- w.Close(m.Equipment);
- });
-
- // register to work with errors
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
- }
-
- private void Window_OnClosed(object? sender, EventArgs e)
- {
- WeakReferenceMessenger.Default.Unregister(this);
- WeakReferenceMessenger.Default.Unregister(this);
- }
-}
\ No newline at end of file
diff --git a/Views/NewPointDialog.axaml b/Views/NewPointDialog.axaml
deleted file mode 100644
index 5f851d3..0000000
--- a/Views/NewPointDialog.axaml
+++ /dev/null
@@ -1,82 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Views/NewPointDialog.axaml.cs b/Views/NewPointDialog.axaml.cs
deleted file mode 100644
index deb150c..0000000
--- a/Views/NewPointDialog.axaml.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using Avalonia.Controls;
-using CommunityToolkit.Mvvm.Messaging;
-using GazpromApp.Messages;
-using GazpromApp.ViewModels;
-
-namespace GazpromApp.Views;
-
-public partial class NewPointDialog : Window
-{
- public NewPointDialog()
- {
- InitializeComponent();
-
- // done entering a new point
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- w.Close(m.Point);
- });
-
- // register to work with errors
- WeakReferenceMessenger.Default.Register(this, static (w, m) =>
- {
- var dialog = new ErrorView
- {
- DataContext = m.Error
- };
- m.Reply(dialog.ShowDialog(w));
- });
- }
-
- private void Window_OnClosed(object? sender, EventArgs e)
- {
- WeakReferenceMessenger.Default.Unregister(this);
- }
-}
\ No newline at end of file
diff --git a/Views/PointView.axaml b/Views/PointView.axaml
new file mode 100644
index 0000000..1604488
--- /dev/null
+++ b/Views/PointView.axaml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/PointView.axaml.cs b/Views/PointView.axaml.cs
new file mode 100644
index 0000000..d12bc0f
--- /dev/null
+++ b/Views/PointView.axaml.cs
@@ -0,0 +1,14 @@
+using System.Windows.Input;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class PointView : UserControl
+{
+ public PointView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/PropertyView.axaml b/Views/PropertyView.axaml
new file mode 100644
index 0000000..9508677
--- /dev/null
+++ b/Views/PropertyView.axaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/PropertyView.axaml.cs b/Views/PropertyView.axaml.cs
new file mode 100644
index 0000000..6014913
--- /dev/null
+++ b/Views/PropertyView.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class PropertyView : UserControl
+{
+ public PropertyView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/Views/SaveChangesView.axaml b/Views/SaveChangesView.axaml
new file mode 100644
index 0000000..b3607c9
--- /dev/null
+++ b/Views/SaveChangesView.axaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/SaveChangesView.axaml.cs b/Views/SaveChangesView.axaml.cs
new file mode 100644
index 0000000..5faaa47
--- /dev/null
+++ b/Views/SaveChangesView.axaml.cs
@@ -0,0 +1,26 @@
+using System;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace GazpromApp.Views;
+
+public partial class SaveChangesView : Window
+{
+ public bool CanClose = false;
+ public SaveChangesView()
+ {
+ InitializeComponent();
+ }
+
+ private void Window_OnClosing(object? sender, WindowClosingEventArgs e)
+ {
+ if (CanClose) return;
+ e.Cancel = true;
+ }
+
+ private void Window_OnClosed(object? sender, EventArgs e)
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/obj/Debug/net8.0/Avalonia/Resources.Inputs.cache b/obj/Debug/net8.0/Avalonia/Resources.Inputs.cache
index b15b07b..c48616c 100644
--- a/obj/Debug/net8.0/Avalonia/Resources.Inputs.cache
+++ b/obj/Debug/net8.0/Avalonia/Resources.Inputs.cache
@@ -1 +1 @@
-ce571eaa8794cd8018cfc316b7aa3a875ff0192541a3e5a99ac1c0b1fe0464bc
+cc067bc255287b1def9594eac16771691c8ab80aebe0b1c73635a5ea9772fd91
diff --git a/obj/Debug/net8.0/Avalonia/resources b/obj/Debug/net8.0/Avalonia/resources
index f03dac41d8cf95fae3855ec38759bd513e5906e5..6fea3645fa1cab7893f3a3f7275194605e6a9b9f 100644
GIT binary patch
delta 9877
zcmeHNd2keE7N1{=&o=i55$bT-4nfS7>a&(-9MWzAoC@NKZfriBR(
zVCmgMU@5R!EO{Yn4PLcX@%opCX?^`ASgx^JEQO&Fjq(zuezELXr1-*vuKpG*c{C{B
zF{*Zn>{dN4`Etdlwt4aTi9!-A{Q)dvg`2;yuKvOrL!Vgs#L*|7J_%i4SmCpk3zxOH
zJ-(@~Ce`C}N^L%uXVKKzvS0DKWOw;Y_Ox85ETtrg=09y_OK9+*$&LQyZpBwVXR*?v
z_`3G3fypr|^})sx{H<6g`xJiXlxBJs)7pMXZ1B2TWbg8N)vbD+(k$1a#r`^Xn<9yg
z3USpOepTDDK=DeBX<_baxHQHZObU$|jJ+KyZCCgdZ@udAdsR2atbyxs`|U6Tr+*Ju
z;KuJ^Vmg;m6K)C9Jly&{!HTKpu9U06^PhAtjles7@b0
zegO*bhl7xd>+b{y*1iN~*uM_uuDsCeYA)9#F{G{G-)U3aq>OB*>e~E%)l;stwECAz
z#xPN=X;l1lthBG1rqNcDBKcek+_a}x%CxmkX^xj|uw$C2?`4gHlh??sq>YKToJaMa
z`;(TuKz931v8Gt#Fr-dUe8dQ@Yln03&HYe>?dzdbvWrB*y+CfdMiXLeU~`}|&=vRt
zUH1mM1G~rKW!oVG(>Fp6I$r@>#=seVZyS~u2%|7%1EgbMKjg)V6Y!>S!suZU-vCuv
z14%AqQlWeR?AWmZ&cTQJz?wRtLJ}`hm?Ar+2^A<#6eK*c0rHCntE+gi%hT+Xn9Gwe
zt(!QX|2h=orgj*Q0g`_R#mlKCxkYc9F51{;8mEdhc^3@N6Glq`{ClD
zsN=B`Aro!wkjN>IicWbt8Kqx|pc#Z?nR8vu{>4lM!i-PA$_~gLQ}332KJuB|lAO}@
zb)*I4ki}7>m^AdFUTyREnLcNi>0=GcGmjrM9OsV^M&kCjVFc&=9LlM1=GGc?y+8{9^*c$a$$S4a5JfskjLeubxocFQhg`!%_Aif`d
z2&Um>$H|4>o+Q|C@jEcGYhEYJiW$j$`&8W>GL^xd-H?eXeXuTff~3njK)-_bF=J$#
z`S(7sVP!n&!j?TC6h&pJwz)a9hpk7U3HN>inIrBC>?Kp(7uX$mE_f?Bscu~V4%A{t
zCzRluTj_FjFErrG50m!NVUNL7q*dSAN-B5l(~y%@qwyY@f}9@rS9QSI!{qrDysZba
z<7O!fv4r`oul5pKO$W#UcYg(&icH~@-1E`r_tlu5{7L~f3s+Q4C73!bxLPqZ74QJ1T_|#|DR)R
zd2(YD;VL(Ctcn*eK289J2j1WIQ?z`rlP=fwQxfvb2atMJpmVAuUO-5!(RCf6k17hf
zvt{ohmxtZkD>$aZ++GTdM>;78ioKA4ck~iWqi~pw=l4Q!wiXD@L7V|WjOnAK`}OAu
zXwB_|ENtzAbEAj!7X=|78#*8rSL^{R59ti){CGf**VfuWQ0~GV6ccAWNNat5lp^;p
z8!#vH%(za<8g5|MQsCdW%vjbcdzuxm2Kz+gd-+9*
ztUboN9*1*gkF$%lZGKg|MqtgTdpApMl35BLKIsa3g}s^%o5P$K2de#awjE_c3U1s6
zMJ3`KWto4jS8i>kMA#{@ySXm^;!Bq(-i2;;DN;U`eeWx@?>ioY}m8hd?SmokK79(bY`)%%u#k2A3->>JkNmhoEGb03xhxi5ezm
zdS3EA6yjz3A-jqngmK}3sj*dV;+tmTqnZ#^wY`cR76$r3#LfaCC02A`LqB9C^SvUd
z<&-KVTz8!GnogszFt8=CGtd*fF?e%eSD?p0*3V8AC4OF|*@jAmAj%Dz?bhy~N(Nbe
zvWaq)i86BoBeXLw#o`Z17G_7KhJ0j&4wEw0I82#k*RdX05!3aTe}N+@Z5UbSPd1`O
zYhe=Jd=g4yr;Nw=6EMm!B_S)K252^=9G1M3Tlj`hJ5S?(^Ad90-+g8#vGgz*Q{_G6N7g+B0`@%y)_jc_
zeJ;biI)-GNWOCb!XLSy|x&y?L=mr?Bg@i2u;eANs+ffwSjtDQroJE7|q3nL^A0g8^
zM{Si@X$udf3Ptgi74|Aj-9~Zc?oD)3D?X*t-1&l#hAXyFkfN{W?P3}4OAgjn|&xhLX5XR2^Zku
zCqcr?_R!ATo`OlKH4Z~`ra9_iC@QTqaljSi)Mui5D0V78$3v|@3R$@|jylz=MUF@t
z{_lU_wir~`0wnNA&P%P6%%#@hM?JjZBwUI|Pr{2Se#$0h%gbCXlvgz4iLap)>%M`K
zIPxcWEKSHpvc@8OHBMLnjmtev(-*LyuSBm*u|XjW|B_W0U$m9H;Vq;9yuuh<6}&?X
zbc>`6JE`K>(=|0gsE!e%hQKRY-KwmY1Q@xl96@l#NKq$DSC@JsryRv6--Bel=uLv<
z_NsAs?Y(5v*JKEZ=q#kbNuE2Ed5RqTvXc^;vR=qdU>y-3D<Wp)|
zio!Csd6#+yzLanTO~-}3RFqiV3umY3trZP66T!2%UM3nLfR!k+q)>^%XnTkaax<%C
zIVBbfspeRLwGWfKNb4ibUDFF=Mj8YdCj+P_883aD{Fo4V<1w3aiX}=|GFZwkNqFLU
zNWnKYgS8@5r*cZQO-75v6lw~JTe>!@bE$V(MHI)Tv(Cb54>j7V3=W+_aN5>Iz|wO*4`(oz|pso_D+
z!{aCZLp_a162yM!HPr`2y`ZR_veG=$ue2E3O+g#KIzXDVDnob)mt_jq{mQM9L8g61!gw%X%`ywRspdvoR6SUGQ~#C4^Sv)YZj;bgBI
z5{WfNbBOnbw1>plz@`|}bKm7ktHPR<5xp_i)M9@>sXa#1%nh;-A=dXaHRK}KHY(kr
zOl2OQG`#f(_sRw{VCt7??J_;f&%(L=kZMZAPcOv}qeiU>@pCeKVx>?>%MGIq6D%Wm
z!Z2Mf3o6CfxE*p%qbrhEuD2eHZI0Fzxq(BV7w#pnnNHpVr-1-?^+C!=w;YG$G!u5>
zAb-7GD8tw8rMP;Rjj9FL7YS2v#}-IUn?&GB&!p%cpWXz8n#RxHOy!47b|D?bLlo#%
zZ>Cgr-)0ad4-4K<-gZh*bFo!#(&GB>q53DIn;}}#ndWjzgrm(ezu_U8?_&O^Fd4V)
zr?5zA^ArPIcTo%czIOT=_c_#rr{cQL
z>G-D<2)TIhbK1C`3?jg%74M?VnNPcQFKz1`hryOYK~6sdDof7)Cv}P(6GJVU3QDb8
zsGPwMTr;*|glp{xw?0Gqz?XUNnW)QT%w}zaP*;73#W(_?;|v-4DUyXS#KF1;NPOP1
zCX|+l1xFxxOmwzG5uW`-B$TG=^EpJb;YUXxNvLsXU`T$Ql>Q&AX7cf~QKcGLtCc8D
zAz1W;)ztU28^0zX5Ws($z_-G%fk-^SF+CEdpO-e^_bxbpjF4|LJ;aYrK;hWUf!!i?
z(!%NZZc4%T2G`PKs#UQ3oPWVTj}b<ppfyy%GLkm>IYXp~!Mhn1eDMv)NT^r6vK#dR
zrcId6imCDv-1#=uQszHE7I{=4R50t`kd#QVLZgk9qlK)vPD#X%6NEezk3n*R>}evH
zJpU`o{sMw<_P`nL9#Tg>n(CysxS^MDcDW}CPsQN0YN05ZY{E#+abC3`BWuC&clg$1
z!OEYRKm(g()qj`8Uv^EY7E)u9!c9zPNblf7_?a9e`bwPWu?x9pWw*Ihm_{EfYf
S&?Gi5;sK4Qzyni-iT?w($yf9M
delta 13489
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
diff --git a/obj/Debug/net8.0/GazpromApp.AssemblyInfo.cs b/obj/Debug/net8.0/GazpromApp.AssemblyInfo.cs
index 12cbd37..df49297 100644
--- a/obj/Debug/net8.0/GazpromApp.AssemblyInfo.cs
+++ b/obj/Debug/net8.0/GazpromApp.AssemblyInfo.cs
@@ -7,16 +7,15 @@
//
//------------------------------------------------------------------------------
-using System;
using System.Reflection;
-[assembly: System.Reflection.AssemblyCompanyAttribute("GazpromApp")]
-[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
-[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d8cb1c0597162160d03e7987cc85991c880988b8")]
-[assembly: System.Reflection.AssemblyProductAttribute("GazpromApp")]
-[assembly: System.Reflection.AssemblyTitleAttribute("GazpromApp")]
-[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
+[assembly: AssemblyCompany("GazpromApp")]
+[assembly: AssemblyConfiguration("Debug")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyInformationalVersion("1.0.0+edae732facddad296bc2957b70d69e109c8df0dc")]
+[assembly: AssemblyProduct("GazpromApp")]
+[assembly: AssemblyTitle("GazpromApp")]
+[assembly: AssemblyVersion("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.
diff --git a/obj/Debug/net8.0/GazpromApp.AssemblyInfoInputs.cache b/obj/Debug/net8.0/GazpromApp.AssemblyInfoInputs.cache
index 879cf21..d806021 100644
--- a/obj/Debug/net8.0/GazpromApp.AssemblyInfoInputs.cache
+++ b/obj/Debug/net8.0/GazpromApp.AssemblyInfoInputs.cache
@@ -1 +1 @@
-77f531bfc5aeafe36631b408a11c11c294e011bb2a474f23c97785d02864a447
+d5e1f758b4af1a11eec5b0ef10074d2fa0359670b43f632e44e63e702c71cb03
diff --git a/obj/Debug/net8.0/GazpromApp.GeneratedMSBuildEditorConfig.editorconfig b/obj/Debug/net8.0/GazpromApp.GeneratedMSBuildEditorConfig.editorconfig
index b4e0635..be134b9 100644
--- a/obj/Debug/net8.0/GazpromApp.GeneratedMSBuildEditorConfig.editorconfig
+++ b/obj/Debug/net8.0/GazpromApp.GeneratedMSBuildEditorConfig.editorconfig
@@ -32,10 +32,13 @@ build_property.EnableCodeStyleSeverity =
[D:/RiderProjects/GazpromApp/App.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
-[D:/RiderProjects/GazpromApp/Views/EditEquipmentDialog.axaml]
+[D:/RiderProjects/GazpromApp/Views/EditEquipmentView.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
-[D:/RiderProjects/GazpromApp/Views/EditPointDialog.axaml]
+[D:/RiderProjects/GazpromApp/Views/EditPointView.axaml]
+build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
+
+[D:/RiderProjects/GazpromApp/Views/EquipmentView.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[D:/RiderProjects/GazpromApp/Views/ErrorView.axaml]
@@ -44,11 +47,17 @@ build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
[D:/RiderProjects/GazpromApp/Views/ImageView.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
+[D:/RiderProjects/GazpromApp/Views/InspectionView.axaml]
+build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
+
[D:/RiderProjects/GazpromApp/Views/MainWindow.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
-[D:/RiderProjects/GazpromApp/Views/NewEquipmentDialog.axaml]
+[D:/RiderProjects/GazpromApp/Views/PointView.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
-[D:/RiderProjects/GazpromApp/Views/NewPointDialog.axaml]
+[D:/RiderProjects/GazpromApp/Views/PropertyView.axaml]
+build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
+
+[D:/RiderProjects/GazpromApp/Views/SaveChangesView.axaml]
build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml
diff --git a/obj/Debug/net8.0/GazpromApp.assets.cache b/obj/Debug/net8.0/GazpromApp.assets.cache
index ed4907724079c04dde274737ce7996db4b221b3e..d867f7def5d03188b13f3601b3e595050e9ce638 100644
GIT binary patch
literal 80054
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