Compare commits

..
10 Commits
88 changed files with 2405 additions and 1490 deletions
+7
View File
@@ -5,13 +5,20 @@
<map>
<entry key="App.axaml" value="GazpromApp.csproj" />
<entry key="Views/EditEquipmentDialog.axaml" value="GazpromApp.csproj" />
<entry key="Views/EditEquipmentView.axaml" value="GazpromApp.csproj" />
<entry key="Views/EditPointDialog.axaml" value="GazpromApp.csproj" />
<entry key="Views/EditPointView.axaml" value="GazpromApp.csproj" />
<entry key="Views/EquipmentView.axaml" value="GazpromApp.csproj" />
<entry key="Views/ErrorView.axaml" value="GazpromApp.csproj" />
<entry key="Views/ImageView.axaml" value="GazpromApp.csproj" />
<entry key="Views/InspectionView.axaml" value="GazpromApp.csproj" />
<entry key="Views/MainWindow.axaml" value="GazpromApp.csproj" />
<entry key="Views/NewEquipmentDialog.axaml" value="GazpromApp.csproj" />
<entry key="Views/NewPointDialog.axaml" value="GazpromApp.csproj" />
<entry key="Views/NewPointView.axaml" value="GazpromApp.csproj" />
<entry key="Views/PointView.axaml" value="GazpromApp.csproj" />
<entry key="Views/PropertyView.axaml" value="GazpromApp.csproj" />
<entry key="Views/SaveChangesView.axaml" value="GazpromApp.csproj" />
</map>
</option>
</component>
+7
View File
@@ -9,5 +9,12 @@
<jdbc-url>jdbc:sqlite:identifier.sqlite</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
<data-source source="LOCAL" name="GazpromApp.db" uuid="594ee7a3-9498-4753-a25d-1e2967c88d5c">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$USER_HOME$/AppData/Local/GazpromApp/GazpromApp.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
+4 -1
View File
@@ -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">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
@@ -10,6 +12,7 @@
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
<material:MaterialTheme BaseTheme="Inherit" PrimaryColor="LightBlue" SecondaryColor="Amber"/>
<icons:MaterialIconStyles/>
</Application.Styles>
</Application>
+23 -6
View File
@@ -1,16 +1,20 @@
using System.Linq;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using System.Linq;
using Avalonia.Markup.Xaml;
using GazpromApp.Utils;
using GazpromApp.ViewModels;
using GazpromApp.Views;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace GazpromApp;
public partial class App : Application
public class App : Application
{
private static ServiceProvider? Services { get; set; }
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
@@ -18,14 +22,27 @@ public partial class App : Application
public override void OnFrameworkInitializationCompleted()
{
var services = new ServiceCollection();
services.AddDbContext<AppDbContext>(options =>
{
var dbPath = new AppDbContext().DbPath;
options.UseSqlite($"Data Source={dbPath}");
});
services.AddTransient<MainWindowViewModel>();
Services = services.BuildServiceProvider();
var dbContext = Services.GetRequiredService<AppDbContext>();
dbContext.Database.EnsureCreated();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
DataContext = Services.GetRequiredService<MainWindowViewModel>()
};
}
+22 -1
View File
@@ -1,4 +1,8 @@
namespace GazpromApp.Enums;
using System;
using System.Globalization;
using Avalonia.Data.Converters;
namespace GazpromApp.Enums;
public enum PeriodType
{
@@ -35,4 +39,21 @@ public static class PeriodTypeExtensions
_ => PeriodType.Unknown
};
}
}
public class PeriodConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is PeriodType periodType)
return periodType.ToDescription();
return false;
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is string periodType)
return periodType.ToPeriodType();
return false;
}
}
+3
View File
@@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AnimatedImage.Avalonia" Version="2.0.0" />
<PackageReference Include="Avalonia" Version="11.3.2" />
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.3.2" />
@@ -25,6 +26,8 @@
</PackageReference>
<PackageReference Include="AvaloniaUI.DiagnosticsSupport" Version="2.0.4" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageReference Include="Material.Avalonia" Version="3.12.0" />
<PackageReference Include="Material.Icons.Avalonia" Version="2.4.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.6">
<PrivateAssets>all</PrivateAssets>
+2 -2
View File
@@ -1,9 +1,9 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
using System;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class EditEquipmentMessage(EquipmentViewModel equipment) : AsyncRequestMessage<EquipmentViewModel?>
public class EditEquipmentMessage(EquipmentViewModel equipment)
{
public EquipmentViewModel Equipment { get; } = equipment;
}
+3 -3
View File
@@ -1,9 +1,9 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
using GazpromApp.Models;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class EditPointMessage(PointViewModel pointViewModel) : AsyncRequestMessage<PointViewModel?>
public class EditPointMessage(PointViewModel point)
{
public PointViewModel Point { get; } = pointViewModel;
public PointViewModel Point { get; } = point;
}
-8
View File
@@ -1,8 +0,0 @@
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class NewEquipmentDone(EquipmentViewModel equipment)
{
public EquipmentViewModel Equipment { get; } = equipment;
}
-6
View File
@@ -1,6 +0,0 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class NewEquipmentMessage : AsyncRequestMessage<EquipmentViewModel?>;
-8
View File
@@ -1,8 +0,0 @@
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class NewPointDone(PointViewModel pointViewModel)
{
public PointViewModel Point { get; } = pointViewModel;
}
-5
View File
@@ -1,5 +0,0 @@
using GazpromApp.ViewModels;
using CommunityToolkit.Mvvm.Messaging.Messages;
namespace GazpromApp.Messages;
public class NewPointMessage : AsyncRequestMessage<PointViewModel?>;
@@ -2,7 +2,7 @@
namespace GazpromApp.Messages;
public class EditEquipmentDone(EquipmentViewModel equipment)
public class RemoveEquipmentMessage(EquipmentViewModel equipment)
{
public EquipmentViewModel Equipment { get; } = equipment;
}
+8
View File
@@ -0,0 +1,8 @@
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class RemoveInspectionMessage(InspectionViewModel inspection)
{
public InspectionViewModel Inspection { get; } = inspection;
}
@@ -2,7 +2,7 @@
namespace GazpromApp.Messages;
public class EditPointDone(PointViewModel pointViewModel)
public class RemovePointMessage(PointViewModel pointViewModel)
{
public PointViewModel Point { get; } = pointViewModel;
}
+8
View File
@@ -0,0 +1,8 @@
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class RemovePropertyMessage(PropertyViewModel property)
{
public PropertyViewModel Property { get; } = property;
}
+11
View File
@@ -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<IReadOnlyList<IStorageFile>>
{
private ViewModelBase Caller { get; set; } = viewModel;
}
+9
View File
@@ -0,0 +1,9 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class SaveChangesMessage(SaveChangesViewModel saveChanges) : AsyncRequestMessage<SaveChangesViewModel?>
{
public SaveChangesViewModel SaveChanges { get; } = saveChanges;
}
+7
View File
@@ -0,0 +1,7 @@
namespace GazpromApp.Messages;
public class SaveChangesResult(bool save, bool cancel)
{
public bool Save { get; } = save;
public bool Cancel { get; } = cancel;
}
+8
View File
@@ -0,0 +1,8 @@
using GazpromApp.ViewModels;
namespace GazpromApp.Messages;
public class SelectionChangedMessage(ViewModelBase viewModel)
{
public ViewModelBase ViewModel { get; } = viewModel;
}
+34 -11
View File
@@ -1,26 +1,49 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace GazpromApp.Models;
public class Equipment
{
public Equipment()
{
LocalId = Id == Guid.Empty ? Guid.NewGuid() : Id;
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[JsonIgnore]
public Guid Id { get; set; }
[JsonIgnore]
[NotMapped]
public Guid LocalId { get; set; }
[Required]
public string? Name { get; set; } = string.Empty;
[Required]
public string? Description { get; set; } = string.Empty;
[Required]
public int PointId { get; set; }
public int ImageId { get; set; }
public List<int> InspectionIds { get; set; } = [];
public DateTime CreationDate { get; set; }
// Foreign keys
[JsonIgnore]
public Guid? PointId { get; set; }
[JsonIgnore]
public List<Guid> ImageIds { get; set; } = [];
[JsonIgnore]
public List<Guid> InspectionIds { get; set; } = [];
[JsonIgnore]
public List<Guid> EquipmentIds { get; set; } = [];
public Guid? ParentEquipmentId { get; set; }
// EF stuff
public Image? Image { get; set; }
public Models.Point? Point { get; set; }
// Navigation Properties
public List<Image> Images { get; set; } = [];
[JsonIgnore]
public Point? Point { get; set; } = null!;
public List<Property> Properties { get; set; } = [];
public List<Inspection> Inspections { get; set; } = [];
public List<Equipment> Equipments { get; set; } = [];
public Equipment? ParentEquipment { get; set; }
}
+3 -4
View File
@@ -1,11 +1,10 @@
using GazpromApp.Enums;
using GazpromApp.ViewModels;
namespace GazpromApp.Models;
public class Error
{
public string? Title { get; set; }
public string? Message { get; set; }
public ErrorSeverity Severity { get; set; }
public string? Title { get; init; }
public string? Message { get; init; }
public ErrorSeverity Severity { get; init; }
}
+17 -5
View File
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace GazpromApp.Models;
public class Image
@@ -9,10 +9,22 @@ public class Image
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[JsonIgnore]
public Guid Id { get; set; }
[Required]
public byte[] Bytes { get; set; } = [];
// EF stuff
public List<Point> Points { get; set; } = [];
public List<Equipment> Equipment { get; set; } = [];
public DateTime CreationDate { get; set; }
// Foreign keys
[JsonIgnore]
public Guid? PointId { get; set; }
[JsonIgnore]
public Guid? EquipmentId { get; set; }
// Navigation Properties
[JsonIgnore]
public Point? Point { get; set; }
[JsonIgnore]
public Equipment? Equipment { get; set; }
}
+13 -5
View File
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace GazpromApp.Models;
@@ -8,17 +9,24 @@ public class Inspection
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[JsonIgnore]
public Guid Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
public DateTime CreationDate { get; set; }
[Required]
public DateTime InspectionDate { get; set; }
public DateTimeOffset InspectionDate { get; set; }
[Required]
public string PeriodType { get; set; } = string.Empty;
[Required]
public float PeriodValue { get; set; }
public int EquipmentId { get; set; }
// Foreign keys
[JsonIgnore]
public Guid EquipmentId { get; set; }
// EF stuff
public Equipment? Equipment { get; set; }
// Navigation Properties
[JsonIgnore]
public Equipment? Equipment { get; } = new();
}
+10 -8
View File
@@ -1,6 +1,8 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace GazpromApp.Models;
@@ -8,16 +10,16 @@ public class Point
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[JsonIgnore]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
public string? Name { get; set; } = string.Empty;
[Required]
public string? Description { get; set; } = string.Empty;
[Required]
public double Latitude { get; set; } = 0;
[Required]
public double Longitude { get; set; } = 0;
// EF stuff
public DateTime CreationDate { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
// Navigation Properties
public List<Image> Images { get; set; } = [];
public List<Equipment> Equipment { get; set; } = [];
public List<Property> Properties { get; set; } = [];
+29 -5
View File
@@ -1,17 +1,41 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace GazpromApp.Models;
public class Property
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int ParentId { get; set; }
[JsonIgnore]
public Guid Id { get; set; }
[Required]
public string Name { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public List<Models.Point> Points { get; set; } = [];
public List<Equipment> Equipment { get; } = [];
public DateTime CreationDate { get; set; }
// For self-referencing hierarchy (Property of a Property)
[JsonIgnore]
public Guid? ParentPropertyId { get; set; }
[JsonIgnore]
public Property? Parent { get; set; }
// For a Property of a Point
[JsonIgnore]
public Guid? PointId { get; set; }
[JsonIgnore]
public Point? Point { get; set; }
// For a Property of an Equipment
[JsonIgnore]
public Guid? EquipmentId { get; set; }
[JsonIgnore]
public Equipment? Equipment { get; set; }
// Child properties in the hierarchy
public List<Property> Properties { get; set; } = [];
}
+3 -3
View File
@@ -1,5 +1,5 @@
using Avalonia;
using System;
using System;
using Avalonia;
namespace GazpromApp;
@@ -7,7 +7,7 @@ sealed class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
// yet, and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
+81 -30
View File
@@ -1,51 +1,102 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.IO;
using GazpromApp.Models;
using Microsoft.EntityFrameworkCore;
namespace GazpromApp.Utils;
public class AppDbContext : DbContext
{
public DbSet<Models.Image> Image { get; set; }
public DbSet<Image> Image { get; set; }
public DbSet<Equipment> Equipment { get; set; }
public DbSet<Models.Point> Point { get; set; }
public DbSet<Inspection> Inspection { get; set; }
public DbSet<Property> Property { get; set; }
public DbSet<Point> Point { get; set; }
public string DbPath { get; }
public AppDbContext()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Directory.CreateDirectory(Path.Combine(path, "GazpromApp"));
DbPath = Path.Combine(Path.Combine(path, "GazpromApp"), "GazpromApp.db");
}
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Directory.CreateDirectory(Path.Combine(path, "GazpromApp"));
DbPath = Path.Combine(Path.Combine(path, "GazpromApp"), "GazpromApp.db");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlite("Data Source=MainDB.db");
optionsBuilder.UseSqlite($"Data Source={DbPath}");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// ==== Point RELATIONSHIPS ====
modelBuilder.Entity<Point>()
.HasMany(p => p.Equipment)
.WithOne(e => e.Point)
.HasForeignKey(e => e.PointId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting a Point deletes its Equipment.
// Images
modelBuilder.Entity<Models.Point>()
.HasMany(e => e.Images)
.WithMany(e => e.Points);
modelBuilder.Entity<Equipment>()
.HasOne(e => e.Image)
.WithMany(e => e.Equipment)
.HasForeignKey(e => e.ImageId);
// Properties
modelBuilder.Entity<Models.Point>()
.HasMany(e => e.Properties)
.WithMany(e => e.Points);
modelBuilder.Entity<Equipment>()
.HasMany(e => e.Properties)
.WithMany(e => e.Equipment);
// Equipment
modelBuilder.Entity<Equipment>()
.HasOne(e => e.Point)
.WithMany(e => e.Equipment)
.HasForeignKey(e => e.PointId);
modelBuilder.Entity<Point>()
.HasMany(p => p.Images)
.WithOne(i => i.Point)
.HasForeignKey(i => i.PointId)
.OnDelete(DeleteBehavior.Cascade); // Deleting a Point deletes its Images.
// ==== Equipment RELATIONSHIPS ====
modelBuilder.Entity<Equipment>()
.HasMany(e => e.Inspections)
.WithOne(e => e.Equipment)
.HasForeignKey(e => e.EquipmentId);
.WithOne(i => i.Equipment)
.HasForeignKey(i => i.EquipmentId)
.OnDelete(DeleteBehavior.Cascade); // Deleting Equipment deletes its Inspections.
modelBuilder.Entity<Equipment>()
.HasMany(e => e.Images)
.WithOne(i => i.Equipment)
.HasForeignKey(i => i.EquipmentId)
.OnDelete(DeleteBehavior.Cascade); // Equipment has one Image.
modelBuilder.Entity<Equipment>()
.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<Point>()
.HasMany(p => p.Properties)
.WithOne(prop => prop.Point)
.HasForeignKey(prop => prop.PointId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting a Point deletes its Properties.
// Property as a child of an Equipment
modelBuilder.Entity<Equipment>()
.HasMany(e => e.Properties)
.WithOne(prop => prop.Equipment)
.HasForeignKey(prop => prop.EquipmentId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting Equipment deletes its Properties.
// Property as a child of another Property (self-referencing)
modelBuilder.Entity<Property>()
.HasMany(p => p.Properties)
.WithOne(p => p.Parent)
.HasForeignKey(p => p.ParentPropertyId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade); // Deleting a parent Property deletes its children.
}
}
+67
View File
@@ -0,0 +1,67 @@
using System;
using System.IO;
using System.Text.Json;
using GazpromApp.Models;
namespace GazpromApp.Utils;
public static class DataSerialization
{
private static void SaveData(string path, string data)
{
if (!File.Exists(path))
{
File.WriteAllText(path, data);
return;
}
var dir = Path.GetDirectoryName(path) ?? "";
var fileName = Path.GetFileNameWithoutExtension(path);
var ext = Path.GetExtension(path);
var index = 1;
while (File.Exists(Path.Combine(dir, $"{fileName} ({index}){ext}")))
index++;
File.WriteAllText(Path.Combine(dir, $"{fileName} ({index}){ext}"), data);
}
private static string LoadData(string path)
{
var text = File.ReadAllText(path);
return text;
}
public static void SavePoint(Point point, string path)
{
SaveData(path, point.Serialize());
}
public static Point? LoadPoint(string path)
{
return Deserialization.Deserialize(LoadData(path));
}
}
public static class Serialization
{
public static string Serialize(this Point point)
{
return JsonSerializer.Serialize(point);
}
}
public static class Deserialization
{
public static Point? Deserialize(string point)
{
try
{
return !string.IsNullOrEmpty(point) ? JsonSerializer.Deserialize<Point>(point) : null;
}
catch
{
throw new ArgumentException("Ошибка расшифровки json файла");
}
}
}
+47
View File
@@ -0,0 +1,47 @@
using System;
using System.Linq;
using GazpromApp.Enums;
using GazpromApp.ViewModels;
namespace GazpromApp.Utils;
public static class DateCalculator
{
public static DateTime[] GetNearestDates(this InspectionViewModel inspection)
{
var today = DateTime.Today;
var firstFutureDate = AddPeriod(inspection.InspectionDate.DateTime, inspection.PeriodType, inspection.PeriodValue);
if (firstFutureDate > today)
{
return [inspection.InspectionDate.DateTime, firstFutureDate];
}
var futureDate = Enumerable.Range(1, int.MaxValue)
.Select(i => AddPeriod(inspection.InspectionDate.DateTime, inspection.PeriodType, inspection.PeriodValue * i))
.First(d => d > today);
var pastDate = SubtractPeriod(futureDate, inspection.PeriodType, inspection.PeriodValue);
return [pastDate, futureDate];
}
private static DateTime AddPeriod(DateTime date, PeriodType periodType, float value)
{
return periodType switch
{
PeriodType.Day => date.AddDays(value),
PeriodType.Week => date.AddDays(value * 7),
PeriodType.Month => date.AddDays(value * 30.436875), // Avg days/month
PeriodType.Year => date.AddDays(value * 365.2425), // Avg days/year (incl. leap years)
PeriodType.Unknown => throw new ArgumentException("Invalid period type"),
_ => throw new ArgumentException("Invalid period type")
};
}
private static DateTime SubtractPeriod(DateTime date, PeriodType periodType, float value)
{
return AddPeriod(date, periodType, -value);
}
}
+53
View File
@@ -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);
}
}
}
+82 -16
View File
@@ -1,58 +1,124 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Diagnostics;
using System.Linq;
using Avalonia.Media.Imaging;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using GazpromApp.Messages;
using GazpromApp.Models;
using GazpromApp.Utils;
namespace GazpromApp.ViewModels;
public partial class EquipmentViewModel : ViewModelBase
{
public ViewModelBase? Parent { get; set; }
private Equipment Equipment { get; }
[ObservableProperty]
private string? _name;
[ObservableProperty]
private string? _description;
[ObservableProperty]
private ImageViewModel? _image;
[ObservableProperty]
private DateTime _creationDate;
public ObservableCollection<ImageViewModel> Images { get; set; } = [];
public ObservableCollection<PropertyViewModel> Properties { get; set; }
public ObservableCollection<InspectionViewModel> Inspections { get; set; }
public ObservableCollection<EquipmentViewModel> 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;
Image = null;
CreationDate = DateTime.Now;
Properties = [];
Inspections = [];
NearestInspection = DateTime.Now.ToLongDateString();
Equipments = [];
NearestInspection = "Нету инспекций";
Equipment = new Equipment();
WeakReferenceMessenger.Default.Register<RemoveEquipmentMessage>(this, RemoveEquipment);
}
public EquipmentViewModel(Equipment equipment)
{
Name = equipment.Name;
Description = equipment.Description;
Image = new ImageViewModel(equipment.Image ?? new Image());
CreationDate = equipment.CreationDate;
Images = new ObservableCollection<ImageViewModel>(equipment.Images.Select(i => new ImageViewModel(i)));
Properties = new ObservableCollection<PropertyViewModel>(equipment.Properties.Select(e => new PropertyViewModel(e)));
Inspections = new ObservableCollection<InspectionViewModel>(equipment.Inspections.Select(e => new InspectionViewModel(e)));
NearestInspection = DateTime.Now.ToLongDateString();
Equipments = new ObservableCollection<EquipmentViewModel>(equipment.Equipments.Select(e => new EquipmentViewModel(e){Parent = this}));
var times = equipment.Inspections.Select(e => new InspectionViewModel(e))
.Select(e => e.GetNearestDates())
.ToList();
Inspections = new ObservableCollection<InspectionViewModel>(equipment.Inspections
.Select((e, i) => new InspectionViewModel(e) { InspectionDate = times[i][0] }));
NearestInspection = times
.Where(e => e[1] > DateTime.Now)
.Select(e => e[1])
.OrderBy(e => e)
.FirstOrDefault()
.ToLongDateString();
if (Inspections.Count == 0) NearestInspection = "Нету инспекций";
Equipment = equipment;
WeakReferenceMessenger.Default.Register<RemoveEquipmentMessage>(this, RemoveEquipment);
}
public Equipment GetEquipment()
{
return new Equipment()
{
Name = Name,
Description = Description,
Image = Image?.GetImage(),
};
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;
}
}
+5 -6
View File
@@ -20,7 +20,7 @@ public partial class ErrorViewModel : ViewModelBase
w.Close();
}
private ErrorSeverity severity;
private readonly ErrorSeverity _severity;
// Visual and other properties
[ObservableProperty] private bool _isErrorVisible;
@@ -38,7 +38,7 @@ public partial class ErrorViewModel : ViewModelBase
{
Title = error.Title;
Message = error.Message;
severity = error.Severity;
_severity = error.Severity;
switch (error.Severity)
{
case ErrorSeverity.Error:
@@ -48,21 +48,20 @@ public partial class ErrorViewModel : ViewModelBase
IsWarnVisible = true;
break;
case ErrorSeverity.Message:
IsInfoVisible = true;
break;
default:
IsInfoVisible = true;
break;
}
}
// ReSharper disable once UnusedMember.Global
public Error GetError()
{
Error error = new Error()
var error = new Error
{
Title = Title,
Message = Message,
Severity = severity,
Severity = _severity
};
return error;
}
+43 -18
View File
@@ -1,47 +1,72 @@
using System.Collections.Generic;
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
{
[ObservableProperty]
private byte[]? _bytes;
public ViewModelBase? Parent;
private Image Image { get; }
[ObservableProperty] private byte[]? _bytes;
[ObservableProperty] private DateTime _creationDate;
// EF stuff
[ObservableProperty]
private List<Point>? _points;
[ObservableProperty]
private List<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;
Points = image.Points;
Point = image.Point;
FileName = image.Bytes is { Length: > 0 } ? new Bitmap(new MemoryStream(image.Bytes)) : null;
Image = image;
}
public ImageViewModel()
{
Bytes = null;
CreationDate = DateTime.Now;
Equipment = null;
Points = null;
Point = null;
Image = new Image();
}
public Image GetImage()
{
MemoryStream ms = new MemoryStream();
var ms = new MemoryStream();
FileName?.Save(ms);
return new Image()
{
Bytes = ms.ToArray(),
Equipment = Equipment ?? [],
Points = Points ?? [],
};
Image.Bytes = ms.ToArray();
Image.CreationDate = CreationDate;
Image.Equipment = Equipment;
Image.Point = Point;
return Image;
}
}
+63 -3
View File
@@ -1,16 +1,76 @@
using GazpromApp.Models;
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;
public partial class InspectionViewModel : ViewModelBase
{
private Inspection Inspection { get; }
[ObservableProperty]
private string _name;
[ObservableProperty]
private DateTime _creationDate;
[ObservableProperty]
private DateTimeOffset _inspectionDate;
[ObservableProperty]
private PeriodType _periodType;
[ObservableProperty]
private float _periodValue;
// Visual properties
[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<PeriodType>()
.Where(p => p != PeriodType.Unknown)
.ToArray();
public InspectionViewModel()
{
Name = string.Empty;
CreationDate = DateTime.Now;
InspectionDate = DateTimeOffset.Now;
PeriodType = 0;
PeriodValue = 1;
Inspection = new Inspection();
}
public InspectionViewModel(Inspection inspection)
{
Name = inspection.Name;
CreationDate = inspection.CreationDate;
InspectionDate = inspection.InspectionDate;
PeriodType = inspection.PeriodType.ToPeriodType();
PeriodValue = inspection.PeriodValue;
Inspection = inspection;
}
public Inspection GetInspection()
{
Inspection.Name = Name;
Inspection.CreationDate = CreationDate;
if (InspectionDate.Year > 2500)
InspectionDate = DateTimeOffset.Now;
Inspection.InspectionDate = InspectionDate;
Inspection.PeriodType = PeriodType.ToDescription();
Inspection.PeriodValue = PeriodValue;
return Inspection;
}
}
+55 -21
View File
@@ -1,50 +1,84 @@
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;
public partial class PointViewModel : ViewModelBase
{
private Point Point { get; }
[ObservableProperty]
private string? _name;
[ObservableProperty]
private string? _description;
[ObservableProperty]
private DateTime _creationDate;
[ObservableProperty]
private double? _latitude;
[ObservableProperty]
private double? _longitude;
// EF stuff
[ObservableProperty]
private List<Image>? _images;
[ObservableProperty]
private List<Equipment>? _equipment;
[ObservableProperty]
private List<Property>? _properties;
public PointViewModel(Models.Point point)
[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);
}
[ObservableProperty]
private ObservableCollection<ImageViewModel> _images;
[ObservableProperty]
private ObservableCollection<EquipmentViewModel> _equipment;
[ObservableProperty]
private ObservableCollection<PropertyViewModel> _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<ImageViewModel>(point.Images.Select(i => new ImageViewModel(i)));
Equipment = new ObservableCollection<EquipmentViewModel>(point.Equipment.Select(i => new EquipmentViewModel(i){Parent = this}));
Properties = new ObservableCollection<PropertyViewModel>(point.Properties.Select(i => new PropertyViewModel(i)));
WeakReferenceMessenger.Default.Register<RemoveEquipmentMessage>(this, RemoveEquipment);
}
public Models.Point GetPoint()
public Point GetPoint()
{
return new Models.Point()
{
Name = this.Name,
Description = this.Description,
Equipment = this.Equipment ?? [],
Properties = this.Properties ?? [],
};
Point.Name = Name;
Point.Description = Description;
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;
}
}
+73 -6
View File
@@ -1,28 +1,95 @@
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;
public partial class PropertyViewModel : ViewModelBase
{
public ViewModelBase? Parent { get; init; }
private Property Property { get; }
[ObservableProperty]
private string _name;
[ObservableProperty]
private string _value;
public ObservableCollection<PropertyViewModel> Properties { get; set; } = [];
[ObservableProperty]
private DateTime _creationDate;
public ObservableCollection<PropertyViewModel> Properties { get; set; }
// Visual and other properties
[ObservableProperty]
private bool _isEditing;
public PropertyViewModel()
[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)
{
Name = string.Empty;
Value = string.Empty;
if (Properties.Contains(msg.Property))
Properties.Remove(msg.Property);
}
public PropertyViewModel(Property 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;
}
public PropertyViewModel()
{
Name = "Имя свойства";
Value = "Значение свойства";
CreationDate = DateTime.Now;
Properties = [];
Parent = null;
Property = new Property();
WeakReferenceMessenger.Default.Register<RemovePropertyMessage>(this, RemoveProperty);
}
public PropertyViewModel(Property property, PropertyViewModel? parent = null)
{
Name = property.Name;
Value = property.Value;
CreationDate = property.CreationDate;
Properties = new ObservableCollection<PropertyViewModel>(
property.Properties.Select(e => new PropertyViewModel(e, this)));
Parent = property.Parent is null ? null : parent;
Property = property;
WeakReferenceMessenger.Default.Register<RemovePropertyMessage>(this, RemoveProperty);
}
public PropertyViewModel(PropertyViewModel property)
{
Name = "Имя свойства";
Value = "Значение свойства";
Properties = [];
Parent = property;
Property = new Property();
WeakReferenceMessenger.Default.Register<RemovePropertyMessage>(this, RemoveProperty);
}
}
+42
View File
@@ -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);
}
}
-148
View File
@@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
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;
namespace GazpromApp.ViewModels;
public partial class EditEquipmentDialogViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _name;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _description;
[ObservableProperty]
private bool _isNameEditing;
[ObservableProperty]
private bool _isDescriptionEditing;
[ObservableProperty]
private ImageViewModel? _image;
[RelayCommand]
private void EditName()
{
IsNameEditing = !IsNameEditing;
IsDescriptionEditing = false;
}
[RelayCommand]
private void EditDescription()
{
IsDescriptionEditing = !IsDescriptionEditing;
IsNameEditing = false;
}
[RelayCommand]
private async Task AddImage(Window w)
{
IReadOnlyList<IStorageFile> files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions()
{
AllowMultiple = false,
Title = "Выберите картинку",
FileTypeFilter = [FilePickerFileTypes.ImageAll],
});
IsImageSelected = files.Count > 0;
try
{
Image = IsImageSelected ? new ImageViewModel(new Models.Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(files[0].Path.AbsolutePath)) } : null;
}
catch (ArgumentException)
{
Error error = new Error()
{
Title = "Ошибка обработки картинки",
Message = "Картинка не была добавлена",
Severity = ErrorSeverity.Error,
};
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
IsImageSelected = false;
}
}
[RelayCommand]
private async Task ViewImage()
{
if (Image is null) return;
_ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(Image));
}
[RelayCommand]
private void DeleteImage()
{
Image = null;
IsImageSelected = false;
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
IsClosed = true;
Equipment equipment = new Equipment()
{
Name = Name,
Description = Description,
Image = Image?.GetImage(),
Properties = [],
};
WeakReferenceMessenger.Default.Send(new EditEquipmentDone(new EquipmentViewModel(equipment)));
}
[RelayCommand]
private void CancelEdit(Window w)
{
IsClosed = true;
WeakReferenceMessenger.Default.Send(new EditEquipmentDone(_equipment));
}
// Visual and other properties
[ObservableProperty]
private bool _isImageSelected;
[ObservableProperty]
private bool _isClosed;
private readonly EquipmentViewModel _equipment;
public EditEquipmentDialogViewModel()
{
Name = "";
Description = "";
Image = null;
IsImageSelected = false;
_equipment = new EquipmentViewModel(new Equipment());
}
public EditEquipmentDialogViewModel(EquipmentViewModel equipment)
{
Name = equipment.Name;
Description = equipment.Description;
Image = equipment.Image;
IsImageSelected = equipment.Image is { Bytes.Length: > 0 };
_equipment = equipment;
}
}
+177
View File
@@ -0,0 +1,177 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
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 EditEquipmentViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _name;
[ObservableProperty]
private bool _isNameEditing;
[RelayCommand]
private void EditName()
{
IsNameEditing = !IsNameEditing;
IsDescriptionEditing = false;
}
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _description;
[ObservableProperty]
private bool _isDescriptionEditing;
[RelayCommand]
private void EditDescription()
{
IsDescriptionEditing = !IsDescriptionEditing;
IsNameEditing = false;
}
public ObservableCollection<ImageViewModel> Images { get; set; }
[RelayCommand]
private async Task AddImage(Window w)
{
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)), Parent = this});
}
catch (ArgumentException)
{
var error = new Error
{
Title = "Ошибка обработки картинки",
Message = $"Картинка не была добавлена: \"{HttpUtility.UrlDecode(file.Name)}\"",
Severity = ErrorSeverity.Error
};
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
}
}
}
public ObservableCollection<InspectionViewModel> Inspections { get; set; }
[RelayCommand]
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 DeleteInspection(InspectionViewModel inspection)
{
Inspections.Remove(inspection);
}
public ObservableCollection<PropertyViewModel> Properties { get; set; }
[RelayCommand]
private void AddProperty() => Properties.Add(new PropertyViewModel {Parent = this});
private void RemoveProperty(object sender, RemovePropertyMessage msg)
{
if (Properties.Contains(msg.Property))
Properties.Remove(msg.Property);
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
_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)
{
CallUpdatePoint(_equipment);
}
// Visual and other properties
private readonly EquipmentViewModel _equipment;
// ReSharper disable once MemberCanBeMadeStatic.Global
public PeriodType[] AllPeriods => Enum.GetValues<PeriodType>()
.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 EditEquipmentViewModel()
{
Name = "Testing";
Description = "Testing";
Images = [];
Inspections = [];
Properties = [];
_equipment = new EquipmentViewModel();
}
public EditEquipmentViewModel(EquipmentViewModel equipment)
{
Name = equipment.Name;
Description = equipment.Description;
Images = equipment.Images;
Inspections = new ObservableCollection<InspectionViewModel>(equipment.Inspections.Select(e => e));
Properties = new ObservableCollection<PropertyViewModel>(equipment.Properties.Select(e => e));
_equipment = equipment;
WeakReferenceMessenger.Default.Register<RemovePropertyMessage>(this, RemoveProperty);
WeakReferenceMessenger.Default.Register<RemoveInspectionMessage>(this, RemoveInspection);
}
~EditEquipmentViewModel()
{
WeakReferenceMessenger.Default.UnregisterAll(this);
}
}
-197
View File
@@ -1,197 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
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 GazpromApp.Views;
using Image = GazpromApp.Models.Image;
namespace GazpromApp.ViewModels;
public partial class EditPointDialogViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _name;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _description;
[ObservableProperty]
private bool _isNameEditing;
[ObservableProperty]
private bool _isDescriptionEditing;
[RelayCommand]
private void EditName()
{
IsNameEditing = !IsNameEditing;
IsDescriptionEditing = false;
}
[RelayCommand]
private void EditDescription()
{
IsDescriptionEditing = !IsDescriptionEditing;
IsNameEditing = false;
}
public ObservableCollection<ImageViewModel> Images { get; set; }
[RelayCommand]
private async Task AddImage(Window w)
{
IReadOnlyList<IStorageFile> 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)
{
Error 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;
}
[RelayCommand]
private static async Task ViewImage(ImageViewModel image)
{
_ = await WeakReferenceMessenger.Default.Send(new ViewImageMessage(image));
}
public ObservableCollection<EquipmentViewModel> Equipment { get; set; }
[RelayCommand]
private async Task AddEquipment()
{
EquipmentViewModel? equipment = await WeakReferenceMessenger.Default.Send(new NewEquipmentMessage());
if (equipment != null)
Equipment.Add(equipment);
IsEquipmentEmpty = Equipment.Count == 0;
}
[RelayCommand]
private async Task EditEquipment(EquipmentViewModel equipment)
{
EquipmentViewModel 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;
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
IsClosed = true;
Point point = new Point()
{
Name = Name,
Description = Description,
Images = Images.Select(e => e.GetImage()).ToList(),
Equipment = Equipment.Select(e => e.GetEquipment()).ToList()
};
WeakReferenceMessenger.Default.Send(new EditPointDone(new PointViewModel(point)));
}
[RelayCommand]
private void CancelEdit(Window w)
{
IsClosed = true;
WeakReferenceMessenger.Default.Send(new EditPointDone(_point));
}
// Visual and other properties
[ObservableProperty]
private bool _isImagesEmpty;
[ObservableProperty]
private bool _isEquipmentEmpty;
[ObservableProperty]
private bool _isClosed;
private readonly PointViewModel _point;
public EditPointDialogViewModel()
{
Name = "";
Description = "";
Images = [];
Equipment = [
new EquipmentViewModel
{
Name = "Equipment Name Very Long",
Description = "Really big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long text", Image = null
},
new EquipmentViewModel
{
Name = "Equipment Name Very Long",
Description = "Really big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long text", Image = null
}
];
IsImagesEmpty = true;
IsEquipmentEmpty = true;
_point = new PointViewModel(new Point());
}
public EditPointDialogViewModel(PointViewModel point)
{
Name = point.Name;
Description = point.Description;
Images = new ObservableCollection<ImageViewModel>((point.Images ?? []).Select(e => new ImageViewModel(e)));
Equipment = new ObservableCollection<EquipmentViewModel>((point.Equipment ?? []).Select(e => new EquipmentViewModel(e)));
IsImagesEmpty = Images.Count == 0;
IsEquipmentEmpty = Equipment.Count == 0;
_point = point;
}
}
+205
View File
@@ -0,0 +1,205 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using Avalonia.Media.Imaging;
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 EditPointViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _name;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CompleteEditCommand))]
private string? _description;
[ObservableProperty]
private bool _isNameEditing;
[ObservableProperty]
private bool _isDescriptionEditing;
[RelayCommand]
private void EditName()
{
IsNameEditing = !IsNameEditing;
IsDescriptionEditing = false;
}
[RelayCommand]
private void EditDescription()
{
IsDescriptionEditing = !IsDescriptionEditing;
IsNameEditing = false;
}
public ObservableCollection<ImageViewModel> Images { get; set; }
[RelayCommand]
private async Task AddImage(Window w)
{
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)), Parent = this});
}
catch (ArgumentException)
{
var error = new Error
{
Title = "Ошибка обработки картинки",
Message = $"Картинка не была добавлена: \"{HttpUtility.UrlDecode(file.Name)}\"",
Severity = ErrorSeverity.Error
};
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
}
}
}
public ObservableCollection<EquipmentViewModel> Equipment { get; set; }
public ObservableCollection<PropertyViewModel> Properties { get; set; }
[RelayCommand]
private void AddProperty() => Properties.Add(new PropertyViewModel {Parent = this});
private void RemoveProperty(object sender, RemovePropertyMessage msg)
{
if (Properties.Contains(msg.Property))
Properties.Remove(msg.Property);
}
private bool CanCompleteEdit() => !string.IsNullOrWhiteSpace(Name);
[RelayCommand(CanExecute = nameof(CanCompleteEdit))]
private void CompleteEdit()
{
_point.Name = Name;
_point.Description = Description;
_point.Images = Images;
_point.Equipment = Equipment;
_point.Properties = Properties;
_ = _point.GetPoint();
WeakReferenceMessenger.Default.Send(new EditPointMessage(_point));
}
[RelayCommand]
private void CancelEdit(Window w)
{
WeakReferenceMessenger.Default.Send(new EditPointMessage(_point));
}
// Visual and other properties
private readonly PointViewModel _point;
public EditPointViewModel()
{
Name = "fsdfasdfasd";
Description = "asfasdfasdfa";
Images = [];
Equipment = [
new EquipmentViewModel
{
Name = "Equipment Name Very Long",
Description = "Really big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long text",
Images = []
},
new EquipmentViewModel
{
Name = "Equipment Name Very Long",
Description = "Really big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long textReally big description for the equipment to show the long text",
Images = []
}
];
Properties = [
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [],
Parent = null
},
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [],
Parent = null
},
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [],
Parent = null
}
],
Parent = null
},
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [],
Parent = null
}
],
Parent = null
},
new PropertyViewModel
{
Name = "Property Name",
Value = "Property Value",
Properties = [],
Parent = null
}
];
_point = new PointViewModel(new Point());
}
public EditPointViewModel(PointViewModel point)
{
Name = point.Name;
Description = point.Description;
Images = new ObservableCollection<ImageViewModel>(point.Images);
Images.ToList().ForEach(i => i.Parent = this);
Equipment = new ObservableCollection<EquipmentViewModel>(point.Equipment);
Properties = new ObservableCollection<PropertyViewModel>(point.Properties);
_point = point;
WeakReferenceMessenger.Default.Register<RemovePropertyMessage>(this, RemoveProperty);
}
~EditPointViewModel()
{
WeakReferenceMessenger.Default.UnregisterAll(this);
}
}
+272 -20
View File
@@ -1,45 +1,297 @@
using CommunityToolkit.Mvvm.ComponentModel;
using GazpromApp.Messages;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using GazpromApp.Messages;
using GazpromApp.Models;
using GazpromApp.Utils;
using Microsoft.EntityFrameworkCore;
namespace GazpromApp.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
public ObservableCollection<PointViewModel> Points { get; } = [];
public ObservableCollection<PointViewModel> Points { get; set; }
[ObservableProperty]
private object? _selectedItem;
[ObservableProperty]
private ViewModelBase? _selectedItemViewModel;
[RelayCommand]
private async Task AddPoint()
{
PointViewModel? point = await WeakReferenceMessenger.Default.Send(new NewPointMessage());
IsLoading = true;
if (point != null)
Points.Add(point);
var point = new PointViewModel(new Point {Name = "Новый объект", Description = "Описание объекта"});
IsLineVisible = Points.Count > 0;
_context.Point.Add(point.GetPoint());
await _context.SaveChangesAsync();
Points.Add(point);
IsLoading = false;
}
[RelayCommand]
private async Task EditPoint(PointViewModel point)
private async Task ImportPoint(Window w)
{
PointViewModel p = await WeakReferenceMessenger.Default.Send(new EditPointMessage(point)) ?? point;
Points[Points.IndexOf(point)] = p;
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(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "GazpromApp"))
});
if (files.Count < 1) return;
IsLoading = true;
foreach (var file in files)
{
var url = file.Path.AbsolutePath;
var decoded = HttpUtility.UrlDecode(url);
var point = DataSerialization.LoadPoint(decoded);
point?.SetPropertyParents();
point?.SetEquipmentParents();
if (point == null) continue;
_context.Point.Add(point);
await _context.SaveChangesAsync();
_context.Update(point);
await _context.SaveChangesAsync();
Points.Add(new PointViewModel(point));
}
IsLoading = false;
}
[RelayCommand]
private void RemovePoint(PointViewModel point)
private async Task ExportPoint(Window w)
{
Points.Remove(point);
IsLineVisible = Points.Count > 0;
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(
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") );
}
// Visual properties
[ObservableProperty]
private bool _isLineVisible;
[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<Property> properties, HashSet<Guid> loadedIds)
{
if (properties.Count == 0)
return;
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))
.OrderBy(p => p.CreationDate)
.ToListAsync();
if (children.Count != 0)
{
var childrenLookup = children.ToLookup(child => child.ParentPropertyId);
foreach (var parent in properties.Where(parent => childrenLookup.Contains(parent.Id)))
{
parent.Properties.Clear();
parent.Properties.AddRange(childrenLookup[parent.Id]);
}
await LoadChildrenForProperties(children, loadedIds);
}
}
private async Task LoadChildrenForEquipments(List<Equipment> equipments, HashSet<Guid> 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
.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.Images
.OrderBy(i => i.CreationDate))
.Include(p => p.Equipment)
.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();
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));
IsLoading = false;
}
private readonly ObservableCollection<PointViewModel> _pointsToUpdate = [];
private readonly ObservableCollection<PointViewModel> _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<EditPointMessage>(this, EditPoint);
WeakReferenceMessenger.Default.Register<RemovePointMessage>(this, RemovePoint);
WeakReferenceMessenger.Default.Register<SelectionChangedMessage>(this, HandleSelectionChanged);
}
public MainWindowViewModel()
{
Points = [new PointViewModel(new Point()) { Name = "Новый объект", Description = "Описание объекта" }];
_context = new AppDbContext();
IsLoading = false;
}
}
-92
View File
@@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
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;
namespace GazpromApp.ViewModels;
public partial class NewEquipmentDialogViewModel : ViewModelBase
{
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(EnterEquipmentCommand))]
private string? _name;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(EnterEquipmentCommand))]
private string? _description;
[ObservableProperty]
private ImageViewModel? _image;
[RelayCommand]
private async Task AddImage(Window w)
{
IReadOnlyList<IStorageFile> files = await w.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions()
{
AllowMultiple = false,
Title = "Выберите картинку",
FileTypeFilter = [FilePickerFileTypes.ImageAll],
});
IsImageSelected = files.Count > 0;
try
{
Image = IsImageSelected ? new ImageViewModel(new Models.Image()) { FileName = new Bitmap(HttpUtility.UrlDecode(files[0].Path.AbsolutePath)) } : null;
}
catch (ArgumentException)
{
Error error = new Error()
{
Title = "Ошибка обработки картинки",
Message = "Картинка не была добавлена",
Severity = ErrorSeverity.Error,
};
_ = await WeakReferenceMessenger.Default.Send(new ErrorMessage(new ErrorViewModel(error)));
IsImageSelected = false;
}
}
[RelayCommand]
private void DeleteImage()
{
Image = null;
IsImageSelected = false;
}
private bool CanEnterEquipment() => !string.IsNullOrEmpty(Name);
[RelayCommand (CanExecute = nameof(CanEnterEquipment))]
private void EnterEquipment()
{
Equipment equipment = new Equipment()
{
Name = Name,
Description = Description ?? string.Empty,
Image = (Image ?? new ImageViewModel()).GetImage()
};
WeakReferenceMessenger.Default.Send(new NewEquipmentDone(new EquipmentViewModel(equipment)));
}
[RelayCommand]
private static void CancelEnterEquipment(Window w)
{
w.Close();
}
// Visual and other stuff
[ObservableProperty]
private bool _isImageSelected;
}
-95
View File
@@ -1,95 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
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<ImageViewModel> Images { get; } = [];
[RelayCommand]
private async Task AddImage(Window w)
{
IReadOnlyList<IStorageFile> 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)
{
Error 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()
{
Point 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;
}
+1 -3
View File
@@ -2,6 +2,4 @@
namespace GazpromApp.ViewModels;
public class ViewModelBase : ObservableObject
{
}
public class ViewModelBase : ObservableObject;
-80
View File
@@ -1,80 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
Width="1000" Height="600"
x:Class="GazpromApp.Views.EditEquipmentDialog"
x:DataType="vm:EditEquipmentDialogViewModel"
Title="Редактирование/просмотр оборудования"
Icon="/Assets/ic_fluent_table_edit_24_filled (Custom).png"
WindowStartupLocation="CenterOwner"
Closing="Window_OnClosing"
Closed="Window_OnClosed">
<Design.DataContext>
<vm:EditEquipmentDialogViewModel/>
</Design.DataContext>
<Grid RowDefinitions="70,150,*,Auto" ColumnDefinitions="*,100,220" x:Name="Root">
<TextBlock Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20,4,0,4"
Text="{Binding Name}"
IsVisible="{Binding !IsNameEditing}"/>
<TextBox Grid.Column="0" Grid.Row="0" Margin="12,12,0,4"
Text="{Binding Name}"
IsVisible="{Binding IsNameEditing}"/>
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" Margin="10"
Command="{Binding EditNameCommand}">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="20,4,0,4"
Text="{Binding Description}"
IsVisible="{Binding !IsDescriptionEditing}"/>
<TextBox Grid.Column="0" Grid.Row="1" Margin="12,4,0,4"
Text="{Binding Description}"
IsVisible="{Binding IsDescriptionEditing}"/>
<Button Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" Margin="10"
Command="{Binding EditDescriptionCommand}">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<Grid Grid.Row="0" Grid.RowSpan="2" Grid.Column="2"
ColumnDefinitions="*,20,4,20,8" RowDefinitions="8,20,*"
IsVisible="{Binding IsImageSelected}">
<Image Grid.ColumnSpan="5" Grid.RowSpan="3"
Source="{Binding Image.FileName, FallbackValue=null}"/>
<Button Grid.Row="1" Grid.Column="1" Width="20" Height="20"
Command="{Binding ViewImageCommand}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_eye_show_24_filled (Custom) 16.png"/>
</Button>
<Button Grid.Row="1" Grid.Column="3" Width="20" Height="20"
Command="{Binding DeleteImageCommand}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom) 16.png"/>
</Button>
</Grid>
<Button Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Center"
IsVisible="{Binding !IsImageSelected}"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Height="24"
Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
<TabControl Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2">
<TabItem Header="Тех. осмотры">
</TabItem>
<TabItem Header="Свойства">
</TabItem>
</TabControl>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить"
Command="{Binding CancelEditCommand}"
CommandParameter="{Binding #Window}"/>
<Button Grid.Column="2" Grid.Row="3" Margin="8" Content="Сохранить" HorizontalAlignment="Right"
Command="{Binding CompleteEditCommand}"/>
</Grid>
</Window>
-68
View File
@@ -1,68 +0,0 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using CommunityToolkit.Mvvm.Messaging;
using GazpromApp.Messages;
using GazpromApp.Models;
using GazpromApp.ViewModels;
namespace GazpromApp.Views;
public partial class EditEquipmentDialog : Window
{
public Equipment? Equipment;
public EditEquipmentDialog()
{
InitializeComponent();
if (Design.IsDesignMode)
return;
// view image
WeakReferenceMessenger.Default.Register<EditEquipmentDialog, ViewImageMessage>(this, static (w, m) =>
{
ImageView dialog = new ImageView()
{
DataContext = m.Image
};
m.Reply(dialog.ShowDialog<ImageViewModel?>(w));
});
// error handling
WeakReferenceMessenger.Default.Register<EditEquipmentDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
// new property dialog
// edit property dialog
// complete editing equipment
WeakReferenceMessenger.Default.Register<EditEquipmentDialog, EditEquipmentDone>(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<ViewImageMessage>(this);
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
//
//
WeakReferenceMessenger.Default.Unregister<EditEquipmentDone>(this);
}
}
+135
View File
@@ -0,0 +1,135 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:views="using:GazpromApp.Views"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="GazpromApp.Views.EditEquipmentView"
x:DataType="vm:EditEquipmentViewModel">
<Design.DataContext>
<vm:EditEquipmentViewModel/>
</Design.DataContext>
<Grid RowDefinitions="70,150,*,Auto" ColumnDefinitions="*,100,220" x:Name="Root">
<Grid.Styles>
<Style Selector="Button.empty">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="Button.not-empty">
<Setter Property="IsVisible" Value="False" />
</Style>
</Grid.Styles>
<TextBlock Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20,4"
Text="{Binding Name, FallbackValue='Название'}"
IsVisible="{Binding !IsNameEditing, FallbackValue=true}"/>
<TextBox Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20, 4"
Text="{Binding Name, FallbackValue='Название'}"
IsVisible="{Binding IsNameEditing, FallbackValue=false}"/>
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" Margin="10" Width="40" Height="40"
Command="{Binding EditNameCommand}">
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"/>
</Button>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="20,4"
Text="{Binding Description, FallbackValue='Описание'}"
IsVisible="{Binding !IsDescriptionEditing, FallbackValue=true}"/>
<TextBox Grid.Column="0" Grid.Row="1" Margin="20,4" AcceptsReturn="True" TextWrapping="Wrap"
Text="{Binding Description, FallbackValue='Название'}"
IsVisible="{Binding IsDescriptionEditing, FallbackValue=false}"/>
<Button Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" Margin="10" Width="40" Height="40"
Command="{Binding EditDescriptionCommand}">
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"/>
</Button>
<Panel Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Center">
<ScrollViewer HorizontalAlignment="Center">
<StackPanel>
<ItemsRepeater HorizontalAlignment="Center"
ItemsSource="{Binding Images}">
<ItemsRepeater.Layout>
<UniformGridLayout Orientation="Horizontal" MaximumRowsOrColumns="1"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:ImageViewModel">
<Border Margin="4" CornerRadius="4" Background="LightGray">
<Grid Margin="2" Width="200" Height="200" Background="LightGray"
ColumnDefinitions="*,32,4,32,8" RowDefinitions="8,32,*">
<Image Stretch="Uniform" Width="200" Height="200" Grid.RowSpan="3" Grid.ColumnSpan="5"
Source="{Binding FileName}" />
<Button Grid.Row="1" Grid.Column="1" Width="32" Height="32"
Command="{Binding ViewImageCommand}">
<icons:MaterialIcon Kind="PrintPreview" Width="24" Height="24"/>
</Button>
<Button Grid.Row="1" Grid.Column="3" Width="32" Height="32"
Command="{Binding DeleteImageCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Height="40"
Classes.empty="{Binding !!Images.Count}"
Classes.not-empty="{Binding !Images.Count}"
Command="{Binding AddImageCommand}">
<icons:MaterialIcon Kind="CameraPlus" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Height="40"
Classes.empty="{Binding !Images.Count}"
Classes.not-empty="{Binding !!Images.Count}"
Command="{Binding AddImageCommand}">
<icons:MaterialIcon Kind="CameraPlus" Width="24" Height="24"/>
</Button>
</Panel>
<TabControl Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3">
<TabItem Header="Свойства">
<ScrollViewer>
<StackPanel>
<TreeView ItemsSource="{Binding Properties}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type vm:PropertyViewModel}"
ItemsSource="{Binding Properties}">
<views:PropertyView/>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
<Button HorizontalAlignment="Center" Margin="4" Width="32" Height="32"
Command="{Binding AddPropertyCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem Header="Инспекции">
<ScrollViewer>
<StackPanel>
<TreeView ItemsSource="{Binding Inspections}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type vm:InspectionViewModel}"
ItemsSource="{Binding Inspection}">
<views:InspectionView/>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
<Button HorizontalAlignment="Center" Margin="4" Width="32" Height="32"
Command="{Binding AddInspectionCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить" HorizontalAlignment="Left"
Command="{Binding CancelEditCommand}"/>
<Button Grid.Column="2" Grid.Row="3" Margin="8" Content="Сохранить" HorizontalAlignment="Right"
Command="{Binding CompleteEditCommand}"/>
</Grid>
</UserControl>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
public partial class EditEquipmentView : UserControl
{
public EditEquipmentView()
{
InitializeComponent();
}
}
-157
View File
@@ -1,157 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
Width="1000" Height="600"
x:Class="GazpromApp.Views.EditPointDialog"
x:DataType="vm:EditPointDialogViewModel"
Title="Редактирование/просмотр объекта"
Icon="/Assets/ic_fluent_edit_24_filled (Custom).png"
WindowStartupLocation="CenterOwner"
Closing="Window_OnClosing"
Closed="Window_OnClosed">
<Design.DataContext>
<vm:EditPointDialogViewModel/>
</Design.DataContext>
<Grid RowDefinitions="70,150,*,Auto" ColumnDefinitions="*,100,220" x:Name="Root">
<TextBlock Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20,4,0,4"
Text="{Binding Name}"
IsVisible="{Binding !IsNameEditing}"/>
<TextBox Grid.Column="0" Grid.Row="0" Margin="12,12,0,4"
Text="{Binding Name}"
IsVisible="{Binding IsNameEditing}"/>
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" Margin="10"
Command="{Binding EditNameCommand}">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="20,4,0,4"
Text="{Binding Description}"
IsVisible="{Binding !IsDescriptionEditing}"/>
<TextBox Grid.Column="0" Grid.Row="1" Margin="12,4,0,4"
Text="{Binding Description}"
IsVisible="{Binding IsDescriptionEditing}"/>
<Button Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" Margin="10"
Command="{Binding EditDescriptionCommand}">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<Panel Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Center">
<ScrollViewer HorizontalAlignment="Center">
<StackPanel>
<ItemsRepeater HorizontalAlignment="Center"
ItemsSource="{Binding Images}">
<ItemsRepeater.Layout>
<UniformGridLayout Orientation="Horizontal" MaximumRowsOrColumns="1"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:ImageViewModel">
<Border Margin="4" CornerRadius="4" Background="LightGray">
<Grid Margin="2" Width="200" Height="200" Background="LightGray"
ColumnDefinitions="*,20,4,20,8" RowDefinitions="8,20,*">
<Image Stretch="Uniform" Width="200" Height="200" Grid.RowSpan="3" Grid.ColumnSpan="5"
Source="{Binding FileName}" />
<Button Grid.Row="1" Grid.Column="1" Width="20" Height="20"
Command="{Binding #Root.((vm:EditPointDialogViewModel)DataContext).ViewImageCommand}"
CommandParameter="{Binding .}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_eye_show_24_filled (Custom) 16.png"/>
</Button>
<Button Grid.Row="1" Grid.Column="3" Width="20" Height="20"
Command="{Binding #Root.((vm:EditPointDialogViewModel)DataContext).DeleteImageCommand}"
CommandParameter="{Binding .}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom) 16.png"/>
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" IsVisible="{Binding !IsImagesEmpty}"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
</StackPanel>
</ScrollViewer>
<Button HorizontalAlignment="Center" VerticalAlignment="Center"
IsVisible="{Binding IsImagesEmpty}"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
</Panel>
<TabControl Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="2">
<TabItem Header="Оборудование">
<ScrollViewer>
<StackPanel>
<ItemsRepeater
IsVisible="{Binding !IsEquipmentEmpty}"
ItemsSource="{Binding Equipment}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Vertical"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:EquipmentViewModel">
<Expander HorizontalAlignment="Stretch" Margin="0,4,0,4">
<Expander.Header>
<Grid Height="54" HorizontalAlignment="Left"
ColumnDefinitions="52, 300, *, Auto">
<Image Height="50" Width="50" Margin="0,2,2,2" HorizontalAlignment="Center" Stretch="Uniform"
Source="{Binding Image.FileName, FallbackValue=null}"/>
<TextBlock Grid.Column="1" FontSize="20" VerticalAlignment="Center" Margin="4,0,0,0"
Text="{Binding Name}"/>
<TextBlock Grid.Column="2" FontSize="15" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Stretch"
Text="{Binding Description}"/>
</Grid>
</Expander.Header>
<Grid ColumnDefinitions="Auto, *, Auto, Auto">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock FontSize="18" Text="Ближайший ТО: "/>
<TextBlock FontSize="18" Text="{Binding NearestInspection}"/>
<TextBlock FontSize="18" Text="Свойств: " Margin="18, 0,0,0"/>
<TextBlock FontSize="18" Text="{Binding Properties.Count}"/>
</StackPanel>
<Button Grid.Column="2"
Command="{Binding #Root.((vm:EditPointDialogViewModel)DataContext).EditEquipmentCommand}"
CommandParameter="{Binding .}"
Margin="4,0,4,0">
<Image Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<Button Grid.Column="3"
Command="{Binding #Root.((vm:EditPointDialogViewModel)DataContext).DeleteEquipmentCommand}"
CommandParameter="{Binding .}"
Margin="4,0,4,0">
<Image Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom).png"/>
</Button>
</Grid>
</Expander>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<Button Height="30" Width="30" HorizontalAlignment="Center" Margin="0,20,0,0"
Command="{Binding AddEquipmentCommand}">
<Image Height="24" Width="24" Source="avares://GazpromApp/Assets/ic_fluent_add_24_filled (Custom).png"/>
</Button>
</StackPanel>
</ScrollViewer>
</TabItem>
<TabItem Header="Свойства">
<ScrollViewer>
<StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить"
Command="{Binding CancelEditCommand}"
CommandParameter="{Binding #Window}"/>
<Button Grid.Column="2" Grid.Row="3" Margin="8" Content="Сохранить" HorizontalAlignment="Right"
Command="{Binding CompleteEditCommand}"/>
</Grid>
</Window>
-126
View File
@@ -1,126 +0,0 @@
using System;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.Messaging;
using GazpromApp.Messages;
using GazpromApp.Models;
using GazpromApp.ViewModels;
namespace GazpromApp.Views;
public partial class EditPointDialog : Window
{
public Point? Point;
public EditPointDialog()
{
InitializeComponent();
if (Design.IsDesignMode)
return;
// view image
WeakReferenceMessenger.Default.Register<EditPointDialog, ViewImageMessage>(this, static (w, m) =>
{
ImageView dialog = new ImageView()
{
DataContext = m.Image
};
m.Reply(dialog.ShowDialog<ImageViewModel?>(w));
});
// error
WeakReferenceMessenger.Default.Register<EditPointDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
// new equipment
WeakReferenceMessenger.Default.Register<EditPointDialog, NewEquipmentMessage>(this, (w, m) =>
{
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
NewEquipmentDialog dialog = new NewEquipmentDialog()
{
DataContext = new NewEquipmentDialogViewModel()
};
m.Reply(dialog.ShowDialog<EquipmentViewModel?>(w));
});
// edit equipment
WeakReferenceMessenger.Default.Register<EditPointDialog, EditEquipmentMessage>(this, (w, m) =>
{
WeakReferenceMessenger.Default.Unregister<ViewImageMessage>(this);
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
EditEquipmentDialog dialog = new EditEquipmentDialog()
{
DataContext = new EditEquipmentDialogViewModel(m.Equipment)
};
m.Reply(dialog.ShowDialog<EquipmentViewModel?>(w));
});
// re registering error when new equipment done
WeakReferenceMessenger.Default.Register<EditPointDialog, NewEquipmentDone>(this, (_, _) =>
{
WeakReferenceMessenger.Default.Register<EditPointDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
});
// re registering view image and error view
WeakReferenceMessenger.Default.Register<EditPointDialog, EditEquipmentDone>(this, (_, _) =>
{
WeakReferenceMessenger.Default.Register<EditPointDialog, ViewImageMessage>(this, static (w, m) =>
{
ImageView dialog = new ImageView()
{
DataContext = m.Image
};
m.Reply(dialog.ShowDialog<ImageViewModel?>(w));
});
WeakReferenceMessenger.Default.Register<EditPointDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
});
// new property
// edit property
// complete editing point
WeakReferenceMessenger.Default.Register<EditPointDialog, EditPointDone>(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<ViewImageMessage>(this);
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
WeakReferenceMessenger.Default.Unregister<NewEquipmentMessage>(this);
WeakReferenceMessenger.Default.Unregister<EditEquipmentMessage>(this);
// new prop
// edit prop
WeakReferenceMessenger.Default.Unregister<EditPointDone>(this);
}
}
+112
View File
@@ -0,0 +1,112 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:views="using:GazpromApp.Views"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="500"
x:Class="GazpromApp.Views.EditPointView"
x:DataType="vm:EditPointViewModel">
<Design.DataContext>
<vm:EditPointViewModel/>
</Design.DataContext>
<Grid RowDefinitions="70,150,*,Auto" ColumnDefinitions="*,100,220" x:Name="Root">
<Grid.Styles>
<Style Selector="Button.empty">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="Button.not-empty">
<Setter Property="IsVisible" Value="False" />
</Style>
</Grid.Styles>
<TextBlock Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20,4"
Text="{Binding Name, FallbackValue='Название'}"
IsVisible="{Binding !IsNameEditing, FallbackValue=true}"/>
<TextBox Grid.Column="0" Grid.Row="0" FontSize="28" Margin="20, 4"
Text="{Binding Name, FallbackValue='Название'}"
IsVisible="{Binding IsNameEditing, FallbackValue=false}"/>
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" Margin="10" Width="40" Height="40"
Command="{Binding EditNameCommand}">
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"/>
</Button>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="20,4"
Text="{Binding Description, FallbackValue='Описание'}"
IsVisible="{Binding !IsDescriptionEditing, FallbackValue=true}"/>
<TextBox Grid.Column="0" Grid.Row="1" Margin="20,4" AcceptsReturn="True" TextWrapping="Wrap"
Text="{Binding Description, FallbackValue='Название'}"
IsVisible="{Binding IsDescriptionEditing, FallbackValue=false}"/>
<Button Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" Margin="10" Width="40" Height="40"
Command="{Binding EditDescriptionCommand}">
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"/>
</Button>
<Panel Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Center">
<ScrollViewer HorizontalAlignment="Center">
<StackPanel>
<ItemsRepeater HorizontalAlignment="Center"
ItemsSource="{Binding Images}">
<ItemsRepeater.Layout>
<UniformGridLayout Orientation="Horizontal" MaximumRowsOrColumns="1"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:ImageViewModel">
<Border Margin="4" CornerRadius="4" Background="LightGray">
<Grid Margin="2" Width="200" Height="200" Background="LightGray"
ColumnDefinitions="*,32,4,32,8" RowDefinitions="8,32,*">
<Image Stretch="Uniform" Width="200" Height="200" Grid.RowSpan="3" Grid.ColumnSpan="5"
Source="{Binding FileName}" />
<Button Grid.Row="1" Grid.Column="1" Width="32" Height="32"
Command="{Binding ViewImageCommand}">
<icons:MaterialIcon Kind="PrintPreview" Width="24" Height="24"/>
</Button>
<Button Grid.Row="1" Grid.Column="3" Width="32" Height="32"
Command="{Binding DeleteImageCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Height="40"
Classes.empty="{Binding !!Images.Count}"
Classes.not-empty="{Binding !Images.Count}"
Command="{Binding AddImageCommand}">
<icons:MaterialIcon Kind="CameraPlus" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="40" Height="40"
Classes.empty="{Binding !Images.Count}"
Classes.not-empty="{Binding !!Images.Count}"
Command="{Binding AddImageCommand}">
<icons:MaterialIcon Kind="CameraPlus" Width="24" Height="24"/>
</Button>
</Panel>
<ScrollViewer Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3">
<StackPanel>
<TextBlock Text="Свойства:" FontSize="24" Margin="24,0"/>
<TreeView ItemsSource="{Binding Properties}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type vm:PropertyViewModel}"
ItemsSource="{Binding Properties}">
<views:PropertyView/>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
<Button HorizontalAlignment="Center" Margin="4" Width="32" Height="32"
Command="{Binding AddPropertyCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить" HorizontalAlignment="Left"
Command="{Binding CancelEditCommand}"/>
<Button Grid.Column="2" Grid.Row="3" Margin="8" Content="Сохранить" HorizontalAlignment="Right"
Command="{Binding CompleteEditCommand}"/>
</Grid>
</UserControl>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
public partial class EditPointView : UserControl
{
public EditPointView()
{
InitializeComponent();
}
}
+38
View File
@@ -0,0 +1,38 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="500"
x:Class="GazpromApp.Views.EquipmentView"
x:DataType="vm:EquipmentViewModel">
<Expander>
<Expander.Header>
<Grid ColumnDefinitions="Auto, Auto, *, Auto, Auto">
<icons:MaterialIcon Kind="Location" Margin="0,0,8,0" Width="24" Height="24"/>
<TextBlock Grid.Column="1" VerticalAlignment="Center" TextWrapping="WrapWithOverflow"
Text="{Binding Name}"/>
<Button Width="32" Grid.Column="3" Margin="0,0,8,0"
Command="{Binding AddEquipmentCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
<Button Width="32" Grid.Column="4" Margin="0,0,8,0"
Command="{Binding RemoveEquipmentCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</Expander.Header>
<Grid RowDefinitions="Auto,Auto,Auto" RowSpacing="4" Margin="8,4,8,2">
<TextBlock Text="{Binding Description}" />
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock Text="Оборудований: "/>
<TextBlock Text="{Binding Equipments.Count}"/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock Text="Свойств: "/>
<TextBlock Text="{Binding Properties.Count}"/>
</StackPanel>
</Grid>
</Expander>
</UserControl>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
public partial class EquipmentView : UserControl
{
public EquipmentView()
{
InitializeComponent();
}
}
+2 -4
View File
@@ -1,7 +1,5 @@
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
@@ -11,8 +9,8 @@ public partial class ErrorView : Window
{
InitializeComponent();
if (Design.IsDesignMode)
return;
// if (Design.IsDesignMode)
// return;
}
+2 -4
View File
@@ -1,6 +1,4 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Controls;
namespace GazpromApp.Views;
@@ -13,6 +11,6 @@ public partial class ImageView : Window
if (Design.IsDesignMode)
return;
this.ExtendClientAreaToDecorationsHint = true;
ExtendClientAreaToDecorationsHint = true;
}
}
+55
View File
@@ -0,0 +1,55 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:icons="using:Material.Icons.Avalonia"
xmlns:enums="using:GazpromApp.Enums"
mc:Ignorable="d" d:DesignWidth="930" d:DesignHeight="450"
x:Class="GazpromApp.Views.InspectionView"
x:DataType="vm:InspectionViewModel">
<Design.DataContext>
<vm:InspectionViewModel/>
</Design.DataContext>
<UserControl.Resources>
<enums:PeriodConverter x:Key="PeriodConverter"/>
</UserControl.Resources>
<Border CornerRadius="4" BorderThickness="1">
<StackPanel Orientation="Vertical">
<Grid ColumnDefinitions="*, Auto">
<TextBlock Grid.Column="0" Margin="12,6" FontSize="22" Height="50"
IsVisible="{Binding !IsEditing}"
Text="{Binding Name}"/>
<TextBox Grid.Column="0" Margin="12,6" FontSize="18" Height="50"
IsVisible="{Binding IsEditing}"
Text="{Binding Name}"/>
<Button Grid.Column="1" HorizontalAlignment="Right" Margin="12,6" Height="40" Width="40"
Command="{Binding EditInspectionCommand}">
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"/>
</Button>
</Grid>
<Grid ColumnDefinitions="*, Auto">
<WrapPanel VerticalAlignment="Top">
<TextBlock Margin="10,2" Text="Дата проведения:"
FontSize="18" VerticalAlignment="Center"/>
<DatePicker FontSize="18" VerticalAlignment="Center" MaxYear="2500-01-01"
SelectedDate="{Binding InspectionDate}"/>
<TextBlock Margin="10,2" Text="Период:" FontSize="18" VerticalAlignment="Center"/>
<NumericUpDown AllowSpin="True" Width="120" Margin="10,2" FontSize="18"
Value="{Binding PeriodValue}"
Minimum="0"/>
<ComboBox Width="110" VerticalAlignment="Center" Margin="10,2" FontSize="18"
ItemsSource="{Binding AllPeriods}"
SelectedItem="{Binding PeriodType, Mode=TwoWay}"
DisplayMemberBinding="{Binding .,
Converter={StaticResource PeriodConverter}}"/>
</WrapPanel>
<Button Grid.Column="1" Margin="12,6" Height="40" Width="40"
Command="{Binding RemoveInspectionCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</StackPanel>
</Border>
</UserControl>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
public partial class InspectionView : UserControl
{
public InspectionView()
{
InitializeComponent();
}
}
+43 -56
View File
@@ -2,94 +2,81 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:anim="https://github.com/whistyun/AnimatedImage.Avalonia"
xmlns:vm="using:GazpromApp.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Width="1424" Height="714"
xmlns:views="using:GazpromApp.Views"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="1024" d:DesignHeight="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">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<DockPanel x:Name="Root">
<Menu DockPanel.Dock="Top">
<MenuItem Command="{Binding AddPointCommand}">
<MenuItem Command="{Binding SyncDbCommand}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_home_add_24_filled (Custom).png"/>
<TextBlock Margin="8,0,0,0" Text="Добавить" VerticalAlignment="Center"/>
<icons:MaterialIcon Kind="Sync" Width="24" Height="24"/>
<TextBlock Margin="8,0,0,0" Text="Сохранить и обновить" VerticalAlignment="Center"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem Command="{Binding ExportPointCommand}"
CommandParameter="{Binding #Window}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_arrow_export_ltr_24_filled (Custom).png"/>
<icons:MaterialIcon Kind="Upload" Width="24" Height="24"/>
<TextBlock Margin="8,0,0,0" Text="Экспорт" VerticalAlignment="Center"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
<MenuItem>
<MenuItem Command="{Binding ImportPointCommand}"
CommandParameter="{Binding #Window}">
<MenuItem.Header>
<StackPanel Orientation="Horizontal">
<Image Width="24" Height="24" Source="avares://GazpromApp/Assets/ic_fluent_arrow_import_24_filled (Custom).png"/>
<icons:MaterialIcon Kind="Download" Width="24" Height="24"/>
<TextBlock Margin="8,0,0,0" Text="Импорт" VerticalAlignment="Center"/>
</StackPanel>
</MenuItem.Header>
</MenuItem>
</Menu>
<Grid DockPanel.Dock="Top" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition MaxHeight="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.ColumnSpan="3">
<Grid DockPanel.Dock="Top" HorizontalAlignment="Stretch"
ColumnDefinitions="*,2,2*">
<ScrollViewer>
<StackPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding Points}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:PointViewModel">
<Grid Margin="10,6,18,6" RowDefinitions="12, Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MaxWidth="300"/>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Rectangle Margin="-2,0,-2,5" Grid.ColumnSpan="4" Height="1" Fill="Gray" Opacity="0.25" VerticalAlignment="Top"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Name}" FontSize="24" Margin="4" VerticalAlignment="Center"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Description}" Margin="4" VerticalAlignment="Center"/>
<Button Grid.Row="1" Grid.Column="2"
Command="{Binding #Root.((vm:MainWindowViewModel)DataContext).EditPointCommand}"
CommandParameter="{Binding .}"
Margin="4">
<Image Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom).png"/>
</Button>
<Button Grid.Row="1" Grid.Column="3"
Command="{Binding #Root.((vm:MainWindowViewModel)DataContext).RemovePointCommand}"
CommandParameter="{Binding .}"
Margin="4">
<Image Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom).png"/>
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Rectangle IsVisible="{Binding IsLineVisible}" Margin="6,6,6,0" Height="1" Fill="Gray" Opacity="0.25"/>
<TreeView ItemsSource="{Binding Points}"
SelectionChanged="TreeView_OnSelectionChanged">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type vm:PointViewModel}"
ItemsSource="{Binding Equipment}">
<views:PointView Padding="0,0,20,0"/>
</TreeDataTemplate>
<TreeDataTemplate DataType="{x:Type vm:EquipmentViewModel}"
ItemsSource="{Binding Equipments}">
<views:EquipmentView Padding="0,0,20,0"/>
</TreeDataTemplate>
</TreeView.DataTemplates>
</TreeView>
<Button Classes="Accent" Height="32" Width="32" Margin="4" HorizontalAlignment="Center"
Command="{Binding AddPointCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
</StackPanel>
</ScrollViewer>
<GridSplitter Background="#b6b6b6" Grid.Column="1" ResizeDirection="Columns"/>
<ContentControl Grid.Column="2" Content="{Binding SelectedItemViewModel}"/>
<Image Width="100" Height="100" VerticalAlignment="Center"
IsVisible="{Binding IsLoading}"
HorizontalAlignment="Center"
Grid.Row="0" Grid.Column="0"
anim:ImageBehavior.AnimatedSource="avares://GazpromApp/Assets/loading.gif"/>
</Grid>
</DockPanel>
</Window>
+72 -17
View File
@@ -1,36 +1,91 @@
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;
using CommunityToolkit.Mvvm.Messaging;
namespace GazpromApp.Views;
public partial class MainWindow : Window
{
private bool _canClose = false;
public MainWindow()
{
InitializeComponent();
if (Design.IsDesignMode)
return;
WeakReferenceMessenger.Default.Register<MainWindow, RequestImageMessage>(this, HandleImageSelection);
WeakReferenceMessenger.Default.Register<MainWindow, ViewImageMessage>(this, HandleImageViewer);
WeakReferenceMessenger.Default.Register<MainWindow, ErrorMessage>(this, HandleErrorViewer);
WeakReferenceMessenger.Default.Register<MainWindow, SaveChangesResult>(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<MainWindow, NewPointMessage>(this, static (w, m) =>
private static void HandleImageViewer(MainWindow sender, ViewImageMessage msg)
{
var dialog = new ImageView
{
NewPointDialog dialog = new NewPointDialog()
{
DataContext = new NewPointDialogViewModel()
};
m.Reply(dialog.ShowDialog<PointViewModel?>(w));
});
WeakReferenceMessenger.Default.Register<MainWindow, EditPointMessage>(this, static (w, m) =>
DataContext = msg.Image
};
msg.Reply(dialog.ShowDialog<ImageViewModel?>(sender));
}
private static void HandleErrorViewer(MainWindow sender, ErrorMessage msg)
{
var dialog = new ErrorView
{
EditPointDialog dialog = new EditPointDialog()
{
DataContext = new EditPointDialogViewModel(m.Point),
Point = m.Point.GetPoint()
};
m.Reply(dialog.ShowDialog<PointViewModel?>(w));
});
DataContext = msg.Error
};
msg.Reply(dialog.ShowDialog<ErrorViewModel?>(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<SaveChangesViewModel?>(this);
e.Cancel = true;
}
}
-67
View File
@@ -1,67 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="500"
Width="500" Height="500"
x:Class="GazpromApp.Views.NewEquipmentDialog"
x:DataType="vm:NewEquipmentDialogViewModel"
Title="Создание нового оборудования"
Icon="/Assets/ic_fluent_table_add_24_filled (Custom).png"
WindowStartupLocation="CenterOwner"
Closed="Window_OnClosed">
<Design.DataContext>
<vm:NewEquipmentDialogViewModel/>
</Design.DataContext>
<Grid Margin="12" x:Name="Root">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="120"/>
<ColumnDefinition MinWidth="300"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="50"/>
<RowDefinition MaxHeight="100"/>
<RowDefinition MinHeight="200" Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Margin="8" Text="Название: "/>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="8" Text="Описание: "/>
<TextBlock Grid.Column="0" Grid.Row="2" Margin="8" Text="Изображение: "/>
<TextBox Grid.Column="1" Grid.Row="0" Margin="8"
Text="{Binding Name}"/>
<TextBox Grid.Column="1" Grid.Row="1" Margin="8"
Text="{Binding Description}"/>
<Grid Grid.Column="1" Grid.Row="2" Margin="2"
ColumnDefinitions="*,20,8,20,8" RowDefinitions="8,20,*"
IsVisible="True">
<Image Stretch="Uniform" Grid.RowSpan="3" Grid.ColumnSpan="3"
Source="{Binding Image.FileName, FallbackValue=null}"/>
<Button Grid.Row="1" Grid.Column="1" Width="20" Height="20"
IsVisible="{Binding IsImageSelected}"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_edit_24_filled (Custom) 16.png"/>
</Button>
<Button Grid.Row="1" Grid.Column="3" Width="20" Height="20"
IsVisible="{Binding IsImageSelected}"
Command="{Binding DeleteImageCommand}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom) 16.png"/>
</Button>
</Grid>
<Button Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center"
IsVisible="{Binding !IsImageSelected}"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить"
Command="{Binding CancelEnterEquipmentCommand}"
CommandParameter="{Binding #Window}"/>
<Button Grid.Column="1" Grid.Row="3" Margin="8" Content="Добавить" HorizontalAlignment="Right"
Command="{Binding EnterEquipmentCommand}"/>
</Grid>
</Window>
-37
View File
@@ -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<NewEquipmentDialog, NewEquipmentDone>(this, static (w, m) =>
{
w.Close(m.Equipment);
});
// register to work with errors
WeakReferenceMessenger.Default.Register<NewEquipmentDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
}
private void Window_OnClosed(object? sender, EventArgs e)
{
WeakReferenceMessenger.Default.Unregister<NewEquipmentDone>(this);
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
}
}
-82
View File
@@ -1,82 +0,0 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="500" d:DesignHeight="500"
Width="500" Height="500"
x:Class="GazpromApp.Views.NewPointDialog"
x:DataType="vm:NewPointDialogViewModel"
Title="Создание нового объекта"
Icon="/Assets/ic_fluent_home_add_24_filled (Custom).png"
WindowStartupLocation="CenterOwner"
Closed="Window_OnClosed">
<Design.DataContext>
<vm:NewPointDialogViewModel/>
</Design.DataContext>
<Grid Margin="12" x:Name="Root">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="120"/>
<ColumnDefinition MinWidth="300"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="50"/>
<RowDefinition MaxHeight="100"/>
<RowDefinition MinHeight="200" Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Margin="8" Text="Название: "/>
<TextBlock Grid.Column="0" Grid.Row="1" Margin="8" Text="Описание: "/>
<TextBlock Grid.Column="0" Grid.Row="2" Margin="8" Text="Изображение: "/>
<TextBox Grid.Column="1" Grid.Row="0" Margin="8"
Text="{Binding Name}"/>
<TextBox Grid.Column="1" Grid.Row="1" Margin="8"
Text="{Binding Description}"/>
<Panel Grid.Column="1" Grid.Row="2" Margin="8" IsVisible="{Binding !IsImagesEmpty}">
<ScrollViewer>
<StackPanel>
<ItemsRepeater ItemsSource="{Binding Images}" HorizontalAlignment="Center">
<ItemsRepeater.Layout>
<UniformGridLayout Orientation="Horizontal" MaximumRowsOrColumns="1"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:ImageViewModel">
<Border Margin="4" CornerRadius="4" Background="LightGray">
<Grid Margin="2" Width="200" Height="200" Background="LightGray"
ColumnDefinitions="*,20,8" RowDefinitions="8,20,*">
<Image Stretch="Uniform" Width="200" Height="200" Grid.RowSpan="3" Grid.ColumnSpan="3"
Source="{Binding FileName}" />
<Button Grid.Row="1" Grid.Column="1" Width="20" Height="20"
Command="{Binding #Root.((vm:NewPointDialogViewModel)DataContext).DeleteImageCommand}"
CommandParameter="{Binding .}">
<Image Width="16" Height="16" Source="avares://GazpromApp/Assets/ic_fluent_delete_24_filled (Custom) 16.png"/>
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
<Button HorizontalAlignment="Center" IsVisible="True"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
</StackPanel>
</ScrollViewer>
</Panel>
<Panel Grid.Column="1" Grid.Row="2" Margin="8"
IsVisible="{Binding IsImagesEmpty}">
<Button HorizontalAlignment="Center" IsVisible="True"
Command="{Binding AddImageCommand}"
CommandParameter="{Binding #Window}">
<Image Width="24" Source="avares://GazpromApp/Assets/ic_fluent_camera_add_24_filled (Custom).png"/>
</Button>
</Panel>
<Button Grid.Column="0" Grid.Row="3" Margin="8" Content="Отменить"
Command="{Binding CancelEnterPointCommand}"
CommandParameter="{Binding #Window}"/>
<Button Grid.Column="1" Grid.Row="3" Margin="8" Content="Добавить" HorizontalAlignment="Right"
Command="{Binding EnterPointCommand}"/>
</Grid>
</Window>
-36
View File
@@ -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 new point
WeakReferenceMessenger.Default.Register<NewPointDialog, NewPointDone>(this, static (w, m) =>
{
w.Close(m.Point);
});
// register to work with errors
WeakReferenceMessenger.Default.Register<NewPointDialog, ErrorMessage>(this, static (w, m) =>
{
ErrorView dialog = new ErrorView()
{
DataContext = m.Error
};
m.Reply(dialog.ShowDialog<ErrorViewModel?>(w));
});
}
private void Window_OnClosed(object? sender, EventArgs e)
{
WeakReferenceMessenger.Default.Unregister<ErrorMessage>(this);
}
}
+60
View File
@@ -0,0 +1,60 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:views="using:GazpromApp.Views"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="500"
x:Class="GazpromApp.Views.PointView"
x:DataType="vm:PointViewModel">
<Expander>
<Expander.Header>
<Grid ColumnDefinitions="Auto, Auto, *, Auto, Auto">
<icons:MaterialIcon Kind="Location" Margin="0,0,8,0" Width="24" Height="24"/>
<TextBlock Grid.Column="1" VerticalAlignment="Center" TextWrapping="WrapWithOverflow"
Text="{Binding Name}"/>
<Button Width="32" Grid.Column="3" Margin="0,0,8,0"
Command="{Binding AddEquipmentCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
<Button Width="32" Grid.Column="4" Margin="0,0,8,0"
Command="{Binding RemovePointCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</Expander.Header>
<Grid RowDefinitions="Auto,Auto,Auto,Auto" RowSpacing="4" Margin="8,4,8,2">
<Grid.Styles>
<Style Selector="ItemsRepeater.empty">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="ItemsRepeater.not-empty">
<Setter Property="IsVisible" Value="False" />
</Style>
</Grid.Styles>
<TextBlock Text="{Binding Description}"/>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<TextBlock Text="Оборудований: "/>
<TextBlock Text="{Binding Equipment.Count}"/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<TextBlock Text="Свойств: "/>
<TextBlock Text="{Binding Properties.Count}"/>
</StackPanel>
<ItemsRepeater Grid.Row="3" Margin="4,8"
ItemsSource="{Binding Images}"
Classes.empty="{Binding !!Images.Count}"
Classes.not-empty="{Binding !Images.Count}">
<ItemsRepeater.Layout>
<StackLayout Orientation="Horizontal" Spacing="4"/>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate DataType="vm:ImageViewModel">
<Image Width="64" Height="64" Source="{Binding FileName}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</Expander>
</UserControl>
+14
View File
@@ -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();
}
}
+43
View File
@@ -0,0 +1,43 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
xmlns:icons="using:Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="GazpromApp.Views.PropertyView"
x:DataType="vm:PropertyViewModel">
<Grid ColumnDefinitions="150,*,Auto,Auto,Auto">
<TextBlock Grid.Column="0" FontSize="18" VerticalAlignment="Center"
IsVisible="{Binding !IsEditing}"
Text="{Binding Name}"/>
<TextBox Grid.Column="0" FontSize="18"
IsVisible="{Binding IsEditing}"
Text="{Binding Name}"/>
<TextBlock Grid.Column="1" FontSize="18" VerticalAlignment="Center"
IsVisible="{Binding !IsEditing}"
Text="{Binding Value}"/>
<TextBox Grid.Column="1"
IsVisible="{Binding IsEditing}"
Text="{Binding Value}"/>
<Button Grid.Column="2" Width="32" Height="32" Margin="4" VerticalAlignment="Center"
Command="{Binding AddPropertyCommand}">
<icons:MaterialIcon Kind="Add" Width="24" Height="24"/>
</Button>
<Button Grid.Column="3" Width="32" Height="32" Margin="4" VerticalAlignment="Center"
Command="{Binding EditPropertyCommand}">
<Panel>
<icons:MaterialIcon Kind="Edit" Width="24" Height="24"
IsVisible="{Binding !IsEditing}"/>
<icons:MaterialIcon Kind="ContentSave" Width="24" Height="24"
IsVisible="{Binding IsEditing}"/>
</Panel>
</Button>
<Button Grid.Column="4" Width="32" Height="32" Margin="4" VerticalAlignment="Center"
Command="{Binding RemovePropertyCommand}">
<icons:MaterialIcon Kind="Delete" Width="24" Height="24"/>
</Button>
</Grid>
</UserControl>
+13
View File
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace GazpromApp.Views;
public partial class PropertyView : UserControl
{
public PropertyView()
{
InitializeComponent();
}
}
+40
View File
@@ -0,0 +1,40 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:GazpromApp.ViewModels"
x:Name="Window"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="180"
Width="400" Height="180"
x:Class="GazpromApp.Views.SaveChangesView"
x:DataType="vm:SaveChangesViewModel"
Title="Не сохраненные данные"
Icon="/Assets/ic_fluent_error_circle_24_filled (1) (Custom).png"
WindowStartupLocation="CenterOwner"
Closing="Window_OnClosing"
Closed="Window_OnClosed">
<Grid x:Name="Root" Margin="16"
ColumnDefinitions="50, *" RowDefinitions="50, *, Auto">
<Image Grid.Row="0" Grid.Column="0"
Source="avares://GazpromApp/Assets/ic_fluent_info_24_filled (Custom).png"/>
<Panel Grid.Row="0" Grid.Column="1" Grid.RowSpan="2">
<StackPanel Margin="8">
<TextBlock Text="Есть несохраненные изменения." FontSize="20" MaxLines="2" TextWrapping="Wrap"/>
<TextBlock Text="Уверены что хотите закрыть?" MaxLines="3" TextWrapping="Wrap"/>
</StackPanel>
</Panel>
<Panel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="8">
<Button Content="Не сохранять" Background="LightCoral"
Command="{Binding DontSaveCommand}"
CommandParameter="{Binding #Window}"/>
<Button Content="Отмена"
Command="{Binding CancelCommand}"
CommandParameter="{Binding #Window}"/>
<Button Content="Сохранить"
Command="{Binding SaveCommand}"
CommandParameter="{Binding #Window}"/>
</StackPanel>
</Panel>
</Grid>
</Window>
+26
View File
@@ -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)
{
}
}
@@ -1 +1 @@
004891c51b7c26ff54260c1cbfcff302500ddbafa20549c101da76cc7da60e8a
cc067bc255287b1def9594eac16771691c8ab80aebe0b1c73635a5ea9772fd91
Binary file not shown.
+1 -1
View File
@@ -13,7 +13,7 @@ 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+5816f21e6cc989b7059d5a18a1f56939b27bf40d")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+08eaa30209fb07132671006392af33044278fb88")]
[assembly: System.Reflection.AssemblyProductAttribute("GazpromApp")]
[assembly: System.Reflection.AssemblyTitleAttribute("GazpromApp")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
22f6a7bf36b71d326c8840f0501afa961a7d4f13e9163340a4acf3e167738c72
991b92f7461b0b0cb8dff258086ca1dd3fd0a9b1938281c5774aefca5ef9edfc
@@ -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
Binary file not shown.
@@ -201,3 +201,11 @@ D:\RiderProjects\GazpromApp\bin\Debug\net8.0\zh-Hant\Microsoft.CodeAnalysis.Work
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\AvaloniaUI.DiagnosticsSupport.Avalonia.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Microsoft.IO.RecyclableMemoryStream.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Avalonia.Controls.ItemsRepeater.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\AnimatedImage.Avalonia.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\AnimatedImage.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Avalonia.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Colors.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Ripple.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Styles.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Icons.dll
D:\RiderProjects\GazpromApp\bin\Debug\net8.0\Material.Icons.Avalonia.dll
+14 -2
View File
@@ -44,12 +44,16 @@
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
"SdkAnalysisLevel": "9.0.300"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"AnimatedImage.Avalonia": {
"target": "Package",
"version": "[2.0.0, )"
},
"Avalonia": {
"target": "Package",
"version": "[11.3.2, )"
@@ -82,6 +86,14 @@
"target": "Package",
"version": "[8.2.1, )"
},
"Material.Avalonia": {
"target": "Package",
"version": "[3.12.0, )"
},
"Material.Icons.Avalonia": {
"target": "Package",
"version": "[2.4.1, )"
},
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[9.0.6, )"
@@ -113,7 +125,7 @@
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.204/PortableRuntimeIdentifierGraph.json"
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.302/PortableRuntimeIdentifierGraph.json"
}
}
}
+1 -1
View File
@@ -18,8 +18,8 @@
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore\9.0.6\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore\9.0.6\buildTransitive\net8.0\Microsoft.EntityFrameworkCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.props" Condition="Exists('$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore.design\9.0.6\build\net8.0\Microsoft.EntityFrameworkCore.Design.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore.design\9.0.6\build\net8.0\Microsoft.EntityFrameworkCore.Design.props')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.props')" />
<Import Project="$(NuGetPackageRoot)avalonia\11.3.2\buildTransitive\Avalonia.props" Condition="Exists('$(NuGetPackageRoot)avalonia\11.3.2\buildTransitive\Avalonia.props')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.props" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.props')" />
<Import Project="$(NuGetPackageRoot)avaloniaui.diagnosticssupport\2.0.4\buildTransitive\AvaloniaUI.DiagnosticsSupport.props" Condition="Exists('$(NuGetPackageRoot)avaloniaui.diagnosticssupport\2.0.4\buildTransitive\AvaloniaUI.DiagnosticsSupport.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
+2 -2
View File
@@ -8,9 +8,9 @@
<Import Project="$(NuGetPackageRoot)microsoft.extensions.options\9.0.6\buildTransitive\net8.0\Microsoft.Extensions.Options.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.options\9.0.6\buildTransitive\net8.0\Microsoft.Extensions.Options.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.6\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.logging.abstractions\9.0.6\buildTransitive\net8.0\Microsoft.Extensions.Logging.Abstractions.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.codeanalysis.analyzers\3.3.4\buildTransitive\Microsoft.CodeAnalysis.Analyzers.targets')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.targets" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.targets')" />
<Import Project="$(NuGetPackageRoot)communitytoolkit.mvvm\8.2.1\buildTransitive\netstandard2.1\CommunityToolkit.Mvvm.targets" Condition="Exists('$(NuGetPackageRoot)communitytoolkit.mvvm\8.2.1\buildTransitive\netstandard2.1\CommunityToolkit.Mvvm.targets')" />
<Import Project="$(NuGetPackageRoot)avalonia.buildservices\0.0.31\buildTransitive\Avalonia.BuildServices.targets" Condition="Exists('$(NuGetPackageRoot)avalonia.buildservices\0.0.31\buildTransitive\Avalonia.BuildServices.targets')" />
<Import Project="$(NuGetPackageRoot)avalonia\11.3.2\buildTransitive\Avalonia.targets" Condition="Exists('$(NuGetPackageRoot)avalonia\11.3.2\buildTransitive\Avalonia.targets')" />
<Import Project="$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.targets" Condition="Exists('$(NuGetPackageRoot)harfbuzzsharp.nativeassets.webassembly\8.3.1.1\buildTransitive\netstandard1.0\HarfBuzzSharp.NativeAssets.WebAssembly.targets')" />
<Import Project="$(NuGetPackageRoot)communitytoolkit.mvvm\8.2.1\buildTransitive\netstandard2.1\CommunityToolkit.Mvvm.targets" Condition="Exists('$(NuGetPackageRoot)communitytoolkit.mvvm\8.2.1\buildTransitive\netstandard2.1\CommunityToolkit.Mvvm.targets')" />
</ImportGroup>
</Project>
+150 -2
View File
@@ -2,6 +2,28 @@
"version": 3,
"targets": {
"net8.0": {
"AnimatedImage.Avalonia/2.0.0": {
"type": "package",
"dependencies": {
"Avalonia": "11.0.0"
},
"compile": {
"lib/net6.0/AnimatedImage.Avalonia.dll": {
"related": ".xml"
},
"lib/net6.0/AnimatedImage.dll": {
"related": ".Avalonia.xml;.xml"
}
},
"runtime": {
"lib/net6.0/AnimatedImage.Avalonia.dll": {
"related": ".xml"
},
"lib/net6.0/AnimatedImage.dll": {
"related": ".Avalonia.xml;.xml"
}
}
},
"Avalonia/11.3.2": {
"type": "package",
"dependencies": {
@@ -519,6 +541,46 @@
}
}
},
"Material.Avalonia/3.12.0": {
"type": "package",
"dependencies": {
"Avalonia": "11.1.0"
},
"compile": {
"lib/net8.0/Material.Avalonia.dll": {},
"lib/net8.0/Material.Colors.dll": {},
"lib/net8.0/Material.Ripple.dll": {},
"lib/net8.0/Material.Styles.dll": {}
},
"runtime": {
"lib/net8.0/Material.Avalonia.dll": {},
"lib/net8.0/Material.Colors.dll": {},
"lib/net8.0/Material.Ripple.dll": {},
"lib/net8.0/Material.Styles.dll": {}
}
},
"Material.Icons/2.4.1": {
"type": "package",
"compile": {
"lib/netstandard2.0/Material.Icons.dll": {}
},
"runtime": {
"lib/netstandard2.0/Material.Icons.dll": {}
}
},
"Material.Icons.Avalonia/2.4.1": {
"type": "package",
"dependencies": {
"Avalonia": "11.0.0",
"Material.Icons": "2.4.1"
},
"compile": {
"lib/netstandard2.0/Material.Icons.Avalonia.dll": {}
},
"runtime": {
"lib/netstandard2.0/Material.Icons.Avalonia.dll": {}
}
},
"MicroCom.Runtime/0.11.0": {
"type": "package",
"compile": {
@@ -1766,6 +1828,30 @@
}
},
"libraries": {
"AnimatedImage.Avalonia/2.0.0": {
"sha512": "Ts0lfQjbozqk1q1uoXBm/dRH8nmxTTmMunan8IBuHsIPKG1MUL+60KDmbCyurnE0rNJh24boGjhIj2Ec9W5Jbg==",
"type": "package",
"path": "animatedimage.avalonia/2.0.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"AnimatedImage.Avalonia.md",
"animatedimage.avalonia.2.0.0.nupkg.sha512",
"animatedimage.avalonia.nuspec",
"lib/net462/AnimatedImage.Avalonia.dll",
"lib/net462/AnimatedImage.Avalonia.xml",
"lib/net462/AnimatedImage.dll",
"lib/net462/AnimatedImage.xml",
"lib/net6.0/AnimatedImage.Avalonia.dll",
"lib/net6.0/AnimatedImage.Avalonia.xml",
"lib/net6.0/AnimatedImage.dll",
"lib/net6.0/AnimatedImage.xml",
"lib/netcoreapp3.1/AnimatedImage.Avalonia.dll",
"lib/netcoreapp3.1/AnimatedImage.Avalonia.xml",
"lib/netcoreapp3.1/AnimatedImage.dll",
"lib/netcoreapp3.1/AnimatedImage.xml"
]
},
"Avalonia/11.3.2": {
"sha512": "3w1v4/wEpHFq6WWVNyyrne2Jyz5bdQvnK3AW36rCto42L+AtdbnO/SG2SIqJ7ObXJl+Y3LXz2XDGx9Blzqduow==",
"type": "package",
@@ -2438,6 +2524,53 @@
"logo.png"
]
},
"Material.Avalonia/3.12.0": {
"sha512": "CtYyhPnP9+9UfKRGHjJGe6isxVjaM1F4cvjUHa0r7qtTskBjHNJAIJOtRMLwqD8/kl5zx1ZhS9Jtuuloqxg6Yg==",
"type": "package",
"path": "material.avalonia/3.12.0",
"files": [
".nupkg.metadata",
".signature.p7s",
"FavIcon.png",
"README.md",
"lib/net8.0/Material.Avalonia.dll",
"lib/net8.0/Material.Colors.dll",
"lib/net8.0/Material.Ripple.dll",
"lib/net8.0/Material.Styles.dll",
"lib/netstandard2.0/Material.Avalonia.dll",
"lib/netstandard2.0/Material.Colors.dll",
"lib/netstandard2.0/Material.Ripple.dll",
"lib/netstandard2.0/Material.Styles.dll",
"material.avalonia.3.12.0.nupkg.sha512",
"material.avalonia.nuspec"
]
},
"Material.Icons/2.4.1": {
"sha512": "5/8ekF4GXqpluBF+kPfv3TytBpV5Z+h4CUU5iNCDC7+A9hPQvtn08ZUjMUXtcRGxGyfScHYDqzshzTvYiPTCdA==",
"type": "package",
"path": "material.icons/2.4.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/netstandard2.0/Material.Icons.dll",
"material.icons.2.4.1.nupkg.sha512",
"material.icons.nuspec"
]
},
"Material.Icons.Avalonia/2.4.1": {
"sha512": "bJZzJCHfZDBg33ZyiSxvexMs2qMGkkv1XEgkAJkqLK9I8WNIUGLCnXcjoBrpSh2Sd2ytoD1IEjV72Zy54St3zA==",
"type": "package",
"path": "material.icons.avalonia/2.4.1",
"files": [
".nupkg.metadata",
".signature.p7s",
"README.md",
"lib/netstandard2.0/Material.Icons.Avalonia.dll",
"material.icons.avalonia.2.4.1.nupkg.sha512",
"material.icons.avalonia.nuspec"
]
},
"MicroCom.Runtime/0.11.0": {
"sha512": "MEnrZ3UIiH40hjzMDsxrTyi8dtqB5ziv3iBeeU4bXsL/7NLSal9F1lZKpK+tfBRnUoDSdtcW3KufE4yhATOMCA==",
"type": "package",
@@ -4695,6 +4828,7 @@
},
"projectFileDependencyGroups": {
"net8.0": [
"AnimatedImage.Avalonia >= 2.0.0",
"Avalonia >= 11.3.2",
"Avalonia.Controls.ItemsRepeater >= 11.1.5",
"Avalonia.Desktop >= 11.3.2",
@@ -4703,6 +4837,8 @@
"Avalonia.Themes.Fluent >= 11.3.2",
"AvaloniaUI.DiagnosticsSupport >= 2.0.4",
"CommunityToolkit.Mvvm >= 8.2.1",
"Material.Avalonia >= 3.12.0",
"Material.Icons.Avalonia >= 2.4.1",
"Microsoft.EntityFrameworkCore >= 9.0.6",
"Microsoft.EntityFrameworkCore.Design >= 9.0.6",
"Microsoft.EntityFrameworkCore.Sqlite >= 9.0.6"
@@ -4752,12 +4888,16 @@
"auditLevel": "low",
"auditMode": "direct"
},
"SdkAnalysisLevel": "9.0.200"
"SdkAnalysisLevel": "9.0.300"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"dependencies": {
"AnimatedImage.Avalonia": {
"target": "Package",
"version": "[2.0.0, )"
},
"Avalonia": {
"target": "Package",
"version": "[11.3.2, )"
@@ -4790,6 +4930,14 @@
"target": "Package",
"version": "[8.2.1, )"
},
"Material.Avalonia": {
"target": "Package",
"version": "[3.12.0, )"
},
"Material.Icons.Avalonia": {
"target": "Package",
"version": "[2.4.1, )"
},
"Microsoft.EntityFrameworkCore": {
"target": "Package",
"version": "[9.0.6, )"
@@ -4821,7 +4969,7 @@
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.204/PortableRuntimeIdentifierGraph.json"
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.302/PortableRuntimeIdentifierGraph.json"
}
}
}
+5 -1
View File
@@ -1,9 +1,10 @@
{
"version": 2,
"dgSpecHash": "jPpTgNZhtko=",
"dgSpecHash": "dxfLR4PjleQ=",
"success": true,
"projectFilePath": "D:\\RiderProjects\\GazpromApp\\GazpromApp.csproj",
"expectedPackageFiles": [
"C:\\Users\\retrd\\.nuget\\packages\\animatedimage.avalonia\\2.0.0\\animatedimage.avalonia.2.0.0.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\avalonia\\11.3.2\\avalonia.11.3.2.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\avalonia.angle.windows.natives\\2.1.25547.20250602\\avalonia.angle.windows.natives.2.1.25547.20250602.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\avalonia.buildservices\\0.0.31\\avalonia.buildservices.0.0.31.nupkg.sha512",
@@ -28,6 +29,9 @@
"C:\\Users\\retrd\\.nuget\\packages\\harfbuzzsharp.nativeassets.webassembly\\8.3.1.1\\harfbuzzsharp.nativeassets.webassembly.8.3.1.1.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\harfbuzzsharp.nativeassets.win32\\8.3.1.1\\harfbuzzsharp.nativeassets.win32.8.3.1.1.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\humanizer.core\\2.14.1\\humanizer.core.2.14.1.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\material.avalonia\\3.12.0\\material.avalonia.3.12.0.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\material.icons\\2.4.1\\material.icons.2.4.1.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\material.icons.avalonia\\2.4.1\\material.icons.avalonia.2.4.1.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\microcom.runtime\\0.11.0\\microcom.runtime.0.11.0.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\microsoft.bcl.asyncinterfaces\\7.0.0\\microsoft.bcl.asyncinterfaces.7.0.0.nupkg.sha512",
"C:\\Users\\retrd\\.nuget\\packages\\microsoft.build.framework\\17.8.3\\microsoft.build.framework.17.8.3.nupkg.sha512",
+1 -1
View File
@@ -1 +1 @@
"restore":{"projectUniqueName":"D:\\RiderProjects\\GazpromApp\\GazpromApp.csproj","projectName":"GazpromApp","projectPath":"D:\\RiderProjects\\GazpromApp\\GazpromApp.csproj","outputPath":"D:\\RiderProjects\\GazpromApp\\obj\\","projectStyle":"PackageReference","fallbackFolders":["C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"],"originalTargetFrameworks":["net8.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.200"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Avalonia":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Controls.ItemsRepeater":{"target":"Package","version":"[11.1.5, )"},"Avalonia.Desktop":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Diagnostics":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Fonts.Inter":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Themes.Fluent":{"target":"Package","version":"[11.3.2, )"},"AvaloniaUI.DiagnosticsSupport":{"target":"Package","version":"[2.0.4, )"},"CommunityToolkit.Mvvm":{"target":"Package","version":"[8.2.1, )"},"Microsoft.EntityFrameworkCore":{"target":"Package","version":"[9.0.6, )"},"Microsoft.EntityFrameworkCore.Design":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive","suppressParent":"All","target":"Package","version":"[9.0.6, )"},"Microsoft.EntityFrameworkCore.Sqlite":{"target":"Package","version":"[9.0.6, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\9.0.204/PortableRuntimeIdentifierGraph.json"}}
"restore":{"projectUniqueName":"D:\\RiderProjects\\GazpromApp\\GazpromApp.csproj","projectName":"GazpromApp","projectPath":"D:\\RiderProjects\\GazpromApp\\GazpromApp.csproj","outputPath":"D:\\RiderProjects\\GazpromApp\\obj\\","projectStyle":"PackageReference","fallbackFolders":["C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"],"originalTargetFrameworks":["net8.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"direct"},"SdkAnalysisLevel":"9.0.300"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"AnimatedImage.Avalonia":{"target":"Package","version":"[2.0.0, )"},"Avalonia":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Controls.ItemsRepeater":{"target":"Package","version":"[11.1.5, )"},"Avalonia.Desktop":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Diagnostics":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Fonts.Inter":{"target":"Package","version":"[11.3.2, )"},"Avalonia.Themes.Fluent":{"target":"Package","version":"[11.3.2, )"},"AvaloniaUI.DiagnosticsSupport":{"target":"Package","version":"[2.0.4, )"},"CommunityToolkit.Mvvm":{"target":"Package","version":"[8.2.1, )"},"Material.Avalonia":{"target":"Package","version":"[3.12.0, )"},"Material.Icons.Avalonia":{"target":"Package","version":"[2.4.1, )"},"Microsoft.EntityFrameworkCore":{"target":"Package","version":"[9.0.6, )"},"Microsoft.EntityFrameworkCore.Design":{"include":"Runtime, Build, Native, ContentFiles, Analyzers, BuildTransitive","suppressParent":"All","target":"Package","version":"[9.0.6, )"},"Microsoft.EntityFrameworkCore.Sqlite":{"target":"Package","version":"[9.0.6, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\9.0.302/PortableRuntimeIdentifierGraph.json"}}
+1 -1
View File
@@ -1 +1 @@
17514599119483488
17536846459734642
+1 -1
View File
@@ -1 +1 @@
17514599119483488
17536846459734642