qwer
This commit is contained in:
Generated
+4
@@ -4,8 +4,12 @@
|
||||
<option name="projectPerEditor">
|
||||
<map>
|
||||
<entry key="MCCAD/App.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/DrawingView.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/DrawingsCollectionView.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/LoginView.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/MainWindow.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/PositiionControl.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
<entry key="MCCAD/Views/TeamsView.axaml" value="MCCAD/MCCAD.csproj" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
|
||||
@@ -21,6 +21,17 @@
|
||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.14">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.14">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageReference Include="ReactiveUI.Avalonia" Version="11.4.12" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MCCAD.Models;
|
||||
|
||||
public class CadDBContext : DbContext
|
||||
{
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.UseLazyLoadingProxies()
|
||||
.UseNpgsql("Host=localhost;User id=postgres;Password=1234;Database=cad_db");
|
||||
}
|
||||
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<Drawing> Drawings { get; set; }
|
||||
public DbSet<Collaborators> Collaborators { get; set; }
|
||||
public DbSet<Team> Teams { get; set; }
|
||||
public DbSet<Membership> Memberships { get; set; }
|
||||
|
||||
public static readonly CadDBContext Instance = new();
|
||||
public static User User;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace MCCAD.Models;
|
||||
|
||||
|
||||
public class Collaborators
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[ForeignKey(nameof(User))]
|
||||
public int UserId { get; set; }
|
||||
public virtual User User { get; set; }
|
||||
[ForeignKey(nameof(Drawing))]
|
||||
public int DrawingId { get; set; }
|
||||
public virtual Drawing Drawing { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MCCAD.Models;
|
||||
|
||||
public class Drawing: INotifyPropertyChanged
|
||||
{
|
||||
private string _name;
|
||||
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (value == _name) return;
|
||||
_name = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string Data { get; set; } = "[]";
|
||||
[ForeignKey(nameof(User))]
|
||||
public int UserId { get; set; }
|
||||
public virtual User User { get; set; }
|
||||
public DateTime CreationDate { get; set; }
|
||||
public DateTime LastChange { get; set; }
|
||||
public double Size => double.Round(Data.Length / 1024.0, 2);
|
||||
|
||||
public Drawing()
|
||||
{
|
||||
CreationDate = DateTime.Now.ToUniversalTime();
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
|
||||
field = value;
|
||||
OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace MCCAD.Models;
|
||||
|
||||
public class Membership
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[ForeignKey(nameof(User))]
|
||||
public int UserId { get; set; }
|
||||
public virtual User User { get; set; }
|
||||
[ForeignKey(nameof(Team))]
|
||||
public int TeamId { get; set; }
|
||||
public virtual Team Team { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
|
||||
namespace MCCAD.Models;
|
||||
|
||||
public class Team
|
||||
{
|
||||
public int Id { get; set; }
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Description { get; set; } = "";
|
||||
[ForeignKey(nameof(Creator))]
|
||||
public int CreatorId { get; set; }
|
||||
public virtual User Creator { get; set; }
|
||||
public int MemberCount => CadDBContext.Instance.Memberships.Count(i => i.TeamId == Id);
|
||||
public DateTime CreatedAt { get; set; } = DateTime.Now.ToUniversalTime();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace MCCAD.Models;
|
||||
|
||||
public class User
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Login { get; set; }
|
||||
public string Password { get; set; }
|
||||
public int RoleId { get; set; }
|
||||
public string Description { get; set; } = "";
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Templates;
|
||||
using MCCAD.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD;
|
||||
|
||||
@@ -35,3 +36,18 @@ public class ViewLocator : IDataTemplate
|
||||
return data is ViewModelBase;
|
||||
}
|
||||
}
|
||||
|
||||
public class MainViewLocator : IViewLocator
|
||||
{
|
||||
|
||||
private ViewLocator _locator = new ViewLocator();
|
||||
public IViewFor<TViewModel>? ResolveView<TViewModel>(string? contract = null) where TViewModel : class
|
||||
{
|
||||
return _locator.Build(contract) as IViewFor<TViewModel>;
|
||||
}
|
||||
|
||||
public IViewFor? ResolveView(object? instance, string? contract = null)
|
||||
{
|
||||
return _locator.Build(instance) as IViewFor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Windows.Input;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
public class DrawingViewModel : ViewModelBase, IRoutableViewModel
|
||||
{
|
||||
private OvalView _ov;
|
||||
private PolygonView _pv;
|
||||
private LineView _lv;
|
||||
private Drawing _inner;
|
||||
|
||||
private static readonly List<IFigureDeserializer> _deserializers =
|
||||
[new LineView.Deserializer(), new PolygonView.Deserializer(), new OvalView.Deserializer()];
|
||||
|
||||
public DrawingViewModel(IScreen hostScreen, Drawing drawing)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
_inner = drawing;
|
||||
LoadFigures();
|
||||
}
|
||||
|
||||
private void LoadFigures()
|
||||
{
|
||||
foreach (var figure in JsonSerializer.Deserialize<List<string>>(_inner.Data))
|
||||
foreach (var deserializer in _deserializers)
|
||||
{
|
||||
if (deserializer.TryDeserialize(figure, out var view))
|
||||
{
|
||||
Figures.Add(view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public OvalView Ov
|
||||
{
|
||||
get => _ov;
|
||||
set => this.RaiseAndSetIfChanged(ref _ov, value);
|
||||
}
|
||||
|
||||
public PolygonView Pv
|
||||
{
|
||||
get => _pv;
|
||||
set => this.RaiseAndSetIfChanged(ref _pv, value);
|
||||
}
|
||||
|
||||
public LineView Lv
|
||||
{
|
||||
get => _lv;
|
||||
set => this.RaiseAndSetIfChanged(ref _lv, value);
|
||||
}
|
||||
|
||||
public ObservableCollection<IFigureView> Figures { get; set; } = [];
|
||||
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
|
||||
public IScreen HostScreen { get; }
|
||||
|
||||
public ICommand OnSave => ReactiveCommand.Create(() =>
|
||||
{
|
||||
_inner.Data = JsonSerializer.Serialize(Figures.Select(i => i.Save()));
|
||||
_inner.LastChange = DateTime.Now.ToUniversalTime();
|
||||
CadDBContext.Instance.SaveChanges();
|
||||
});
|
||||
|
||||
public ICommand Back => ReactiveCommand.Create(() => { HostScreen.Router.NavigateBack.Execute(); }
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
public class DrawingsCollectionViewModel : ViewModelBase, IRoutableViewModel
|
||||
{
|
||||
public DrawingsCollectionViewModel(IScreen hostScreen)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
User = CadDBContext.User;
|
||||
}
|
||||
|
||||
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
|
||||
public IScreen HostScreen { get; }
|
||||
|
||||
public User User { get; set; }
|
||||
public ObservableCollection<Drawing> Drawings { get; set; } = [];
|
||||
public Drawing? SelectedDrawing { get; set; }
|
||||
public ICommand Exit => ReactiveCommand.Create(() => HostScreen.Router.NavigateBack.Execute());
|
||||
|
||||
public ICommand Open => ReactiveCommand.Create(() =>
|
||||
{
|
||||
if (SelectedDrawing != null)
|
||||
HostScreen.Router.Navigate.Execute(new DrawingViewModel(HostScreen, SelectedDrawing!));
|
||||
});
|
||||
|
||||
public ICommand Delete => ReactiveCommand.Create(() =>
|
||||
{
|
||||
if (SelectedDrawing != null)
|
||||
{
|
||||
if (SelectedDrawing.Id != 0)
|
||||
{
|
||||
CadDBContext.Instance.Drawings.Remove(SelectedDrawing);
|
||||
CadDBContext.Instance.SaveChanges();
|
||||
}
|
||||
|
||||
Drawings.Remove(SelectedDrawing);
|
||||
}
|
||||
});
|
||||
|
||||
public ICommand Save => ReactiveCommand.Create(() =>
|
||||
{
|
||||
if (SelectedDrawing == null) return;
|
||||
if (SelectedDrawing.Id == 0)
|
||||
{
|
||||
CadDBContext.Instance.Drawings.Add(SelectedDrawing);
|
||||
}
|
||||
else
|
||||
{
|
||||
CadDBContext.Instance.Drawings.Update(SelectedDrawing);
|
||||
}
|
||||
|
||||
CadDBContext.Instance.SaveChanges();
|
||||
});
|
||||
|
||||
public ICommand Create => ReactiveCommand.Create(() =>
|
||||
{
|
||||
var dr = new Drawing();
|
||||
dr.User = User;
|
||||
Drawings.Add(dr);
|
||||
SelectedDrawing = dr;
|
||||
});
|
||||
|
||||
public string SelectedDrawingName
|
||||
{
|
||||
get => (SelectedDrawing ?? new Drawing()).Name;
|
||||
set
|
||||
{
|
||||
if (SelectedDrawing != null)
|
||||
SelectedDrawing.Name = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text.Json;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
using Line = MCCAD.Models.Line;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
@@ -17,23 +20,37 @@ public interface IFigureView
|
||||
public event ShemeUpdate OnNewSheme;
|
||||
PositionVM Position { get; set; }
|
||||
public string Name { get; set; }
|
||||
string Save();
|
||||
}
|
||||
|
||||
public interface IFigureDeserializer
|
||||
{
|
||||
bool TryDeserialize(string data, out IFigureView view);
|
||||
}
|
||||
|
||||
public class LineView : ReactiveObject, IFigureView
|
||||
{
|
||||
private static int _counter = 1;
|
||||
|
||||
public LineView () {
|
||||
public LineView()
|
||||
{
|
||||
Position = new PositionVM
|
||||
{
|
||||
Chanded = Rebuild
|
||||
};
|
||||
Name = "Line " + _counter++;
|
||||
}
|
||||
|
||||
public event ShemeUpdate OnNewSheme;
|
||||
public PositionVM Position { get; set; } = new ();
|
||||
public PositionVM Position { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Save()
|
||||
{
|
||||
var data = new Data() { Angle = Angle, Lenght = lenght, Position = Position, Name = Name };
|
||||
return "line " + JsonSerializer.Serialize(data);
|
||||
}
|
||||
|
||||
private double angle = 45;
|
||||
private int lenght = 10;
|
||||
|
||||
@@ -67,7 +84,32 @@ public class LineView : ReactiveObject, IFigureView
|
||||
shape = shape.Select(i => new IntPoint(i.X, -i.Y)).ToList();
|
||||
var yMove = shape.Select(p => p.Y).Min();
|
||||
shape = shape.Select(p => new IntPoint(p.X, p.Y - yMove)).ToList();
|
||||
OnNewSheme.Invoke(shape, this);
|
||||
OnNewSheme?.Invoke(shape, this);
|
||||
}
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Angle { get; set; }
|
||||
public int Lenght { get; set; }
|
||||
public PositionVM Position { get; set; }
|
||||
}
|
||||
|
||||
public class Deserializer : IFigureDeserializer
|
||||
{
|
||||
public bool TryDeserialize(string data, out IFigureView? view)
|
||||
{
|
||||
if (!data.StartsWith("line"))
|
||||
{
|
||||
view = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsed = JsonSerializer.Deserialize<Data>(data.Substring(data.IndexOf(' ') + 1));
|
||||
view = new LineView()
|
||||
{ Name = parsed.Name, Lenght = parsed.Lenght, Position = parsed.Position, Angle = parsed.Angle };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,13 +118,47 @@ public class PolygonView : ReactiveObject, IFigureView
|
||||
public event ShemeUpdate OnNewSheme;
|
||||
public PositionVM Position { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Corners { get; set; }
|
||||
public int Radius { get; set; }
|
||||
public PositionVM Position { get; set; }
|
||||
}
|
||||
|
||||
public class Deserializer : IFigureDeserializer
|
||||
{
|
||||
public bool TryDeserialize(string data, out IFigureView? view)
|
||||
{
|
||||
if (!data.StartsWith("polygon"))
|
||||
{
|
||||
view = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsed = JsonSerializer.Deserialize<Data>(data.Substring(data.IndexOf(' ') + 1));
|
||||
|
||||
view = new PolygonView()
|
||||
{ Name = parsed.Name, radius = parsed.Radius, Position = parsed.Position, corners = parsed.Corners };
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public string Save()
|
||||
{
|
||||
var data = new Data { Corners = corners, Radius = Radius, Position = Position, Name = Name };
|
||||
return "polygon " + JsonSerializer.Serialize(data);
|
||||
}
|
||||
|
||||
private int corners = 3;
|
||||
private int radius = 5;
|
||||
private int rotate;
|
||||
|
||||
private static int _counter = 1;
|
||||
|
||||
public PolygonView() {
|
||||
public PolygonView()
|
||||
{
|
||||
Position = new PositionVM
|
||||
{
|
||||
Chanded = Rebuild
|
||||
@@ -163,7 +239,7 @@ public class PolygonView : ReactiveObject, IFigureView
|
||||
// start = start.Next;
|
||||
//}
|
||||
//DrawFromTo(vecs.First.Value, vecs.Last.Value);
|
||||
OnNewSheme.Invoke(shape, this);
|
||||
OnNewSheme?.Invoke(shape, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,10 +316,58 @@ public class OvalView : ReactiveObject, IFigureView
|
||||
}
|
||||
}
|
||||
|
||||
public event ShemeUpdate OnNewSheme;
|
||||
public event ShemeUpdate? OnNewSheme;
|
||||
public PositionVM Position { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public class Data
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Top { get; set; }
|
||||
public int Bottom { get; set; }
|
||||
public int Left { get; set; }
|
||||
public int Right { get; set; }
|
||||
public PositionVM Position { get; set; }
|
||||
}
|
||||
|
||||
public class Deserializer : IFigureDeserializer
|
||||
{
|
||||
public bool TryDeserialize(string data, out IFigureView? view)
|
||||
{
|
||||
if (!data.StartsWith("oval"))
|
||||
{
|
||||
view = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var parsed = JsonSerializer.Deserialize<Data>(data.Substring(data.IndexOf(' ') + 1));
|
||||
view = new OvalView
|
||||
{
|
||||
Name = parsed.Name,
|
||||
bottom = parsed.Bottom,
|
||||
top = parsed.Top,
|
||||
heigh = parsed.Height,
|
||||
left = parsed.Left,
|
||||
right = parsed.Right,
|
||||
Position = parsed.Position,
|
||||
width = parsed.Width,
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public string Save()
|
||||
{
|
||||
var data = new Data
|
||||
{
|
||||
Height = heigh, Width = width, Position = Position, Name = Name, Top = top, Bottom = bottom, Left = left,
|
||||
Right = right
|
||||
};
|
||||
return "oval " + JsonSerializer.Serialize(data);
|
||||
}
|
||||
|
||||
public double NormalizedLenth(double x, double y)
|
||||
{
|
||||
var hWidth = width / 2;
|
||||
@@ -261,6 +385,7 @@ public class OvalView : ReactiveObject, IFigureView
|
||||
};
|
||||
Name = "Oval " + _counter++;
|
||||
}
|
||||
|
||||
public void Rebuild()
|
||||
{
|
||||
int RoundToInt(double value) => (int)Math.Round(value);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
public class LoginViewModel : ViewModelBase, IRoutableViewModel
|
||||
{
|
||||
public LoginViewModel(IScreen hostScreen)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
}
|
||||
|
||||
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
|
||||
public IScreen HostScreen { get; }
|
||||
public bool InvalidData { get; set; }
|
||||
public string Login { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public ICommand TryAuth => ReactiveCommand.Create(() =>
|
||||
{
|
||||
if (CadDBContext.Instance.Users.FirstOrDefault(x => x.Login == Login && Password == x.Password) is { } user)
|
||||
{
|
||||
CadDBContext.User = user;
|
||||
switch (user.RoleId)
|
||||
{
|
||||
case 1:
|
||||
HostScreen.Router.Navigate.Execute(new DrawingsCollectionViewModel(HostScreen));
|
||||
break;
|
||||
case 2:
|
||||
HostScreen.Router.Navigate.Execute(new TeamsViewModel(HostScreen));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,35 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
public class MainWindowViewModel : ViewModelBase, IScreen
|
||||
{
|
||||
private OvalView _ov;
|
||||
private PolygonView _pv;
|
||||
private LineView _lv;
|
||||
public RoutingState Router { get; private set; }
|
||||
|
||||
public OvalView Ov
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
get => _ov;
|
||||
set => this.RaiseAndSetIfChanged(ref _ov, value);
|
||||
Router = new RoutingState();
|
||||
Router.Navigate.Execute(new LoginViewModel(this));
|
||||
}
|
||||
|
||||
public PolygonView Pv
|
||||
{
|
||||
get => _pv;
|
||||
set => this.RaiseAndSetIfChanged(ref _pv, value);
|
||||
}
|
||||
public static string test_data = """
|
||||
[ "oval {\"Name\":\"Oval 1\",\"Height\":10,\"Width\":10,\"Top\":0,\"Bottom\":10,\"Left\":0,\"Right\":10,\"Position\":{\"X\":0,\"Y\":0}}", "polygon {\"Name\":\"Polygon 1\",\"Corners\":7,\"Radius\":32,\"Position\":{\"X\":0,\"Y\":0}}", "line {\"Name\":\"Line 1\",\"Angle\":45,\"Lenght\":10,\"Position\":{\"X\":0,\"Y\":0}}" ]
|
||||
""";
|
||||
|
||||
public LineView Lv
|
||||
{
|
||||
get => _lv;
|
||||
set => this.RaiseAndSetIfChanged(ref _lv, value);
|
||||
}
|
||||
|
||||
public int A { get; set; }
|
||||
public string Greeting { get; set; }
|
||||
|
||||
public ObservableCollection<IFigureView> Figures { get; set; } = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Windows.Input;
|
||||
using DynamicData;
|
||||
using MCCAD.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace MCCAD.ViewModels;
|
||||
|
||||
public class TeamsViewModel : ViewModelBase, IRoutableViewModel
|
||||
{
|
||||
private string _searchString = "";
|
||||
|
||||
public TeamsViewModel(IScreen hostScreen)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
teams = CadDBContext.Instance.Teams.Where(i => i.CreatorId == CadDBContext.User.Id).ToList();
|
||||
Teams.AddRange(teams);
|
||||
}
|
||||
|
||||
private List<Team> teams;
|
||||
public ObservableCollection<Team> Teams { get; set; } = [];
|
||||
public string? UrlPathSegment { get; } = Guid.NewGuid().ToString();
|
||||
public IScreen HostScreen { get; }
|
||||
public ICommand Exit => ReactiveCommand.Create(() => HostScreen.Router.NavigateBack.Execute());
|
||||
|
||||
public string SearchString
|
||||
{
|
||||
get => _searchString;
|
||||
set
|
||||
{
|
||||
_searchString = value;
|
||||
Teams.Clear();
|
||||
Teams.AddRange(string.IsNullOrWhiteSpace(_searchString)
|
||||
? teams
|
||||
: teams.Where(i => i.Name.Contains(SearchString, StringComparison.CurrentCultureIgnoreCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<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:viewModels="clr-namespace:MCCAD.ViewModels"
|
||||
xmlns:views="clr-namespace:MCCAD.Views"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="MCCAD.Views.DrawingView"
|
||||
x:DataType="viewModels:DrawingViewModel">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="250" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="250"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="125" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="5,5,5,5">
|
||||
<Button Command="{Binding Back}">← Назад</Button>
|
||||
<HyperlinkButton Click="CreateShape" Tag="Ov">Новый элипс</HyperlinkButton>
|
||||
<HyperlinkButton Click="CreateShape" Tag="Pv">Новый многоугольник</HyperlinkButton>
|
||||
<HyperlinkButton Click="CreateShape" Tag="Lv">Новая линия</HyperlinkButton>
|
||||
<Panel Name="ToolsTab" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ScrollViewer DataContext="{Binding Path=Ov}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Размеры">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Ширина" />
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider Minimum="3" Maximum="50" VerticalAlignment="Center"
|
||||
Value="{Binding Width}" />
|
||||
<TextBox x:Name="WStr" Grid.Column="1" Margin="3" MaxLength="4"
|
||||
Text="{Binding Width}" />
|
||||
</Grid>
|
||||
<TextBlock Text="Высота" />
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider Minimum="3" Maximum="50" VerticalAlignment="Center"
|
||||
Value="{Binding Heigth}" />
|
||||
<TextBox x:Name="HStr" Grid.Column="1" Margin="3" MaxLength="4"
|
||||
Text="{Binding Heigth}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Ограничения">
|
||||
<DockPanel LastChildFill="False" Name="LimitsDP">
|
||||
<StackPanel DockPanel.Dock="Top">
|
||||
<Slider Minimum="0" Maximum="{Binding Heigth}" Width="85" Margin="3"
|
||||
Value="{Binding TopLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="TopTB"
|
||||
Text="{Binding TopLimit, StringFormat={}от {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom">
|
||||
<Slider Minimum="0" Maximum="{Binding Heigth}" Width="85" Margin="3"
|
||||
Value="{Binding BottomLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="BotTB"
|
||||
Text="{Binding BottomLimit, StringFormat={}до {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<Slider Minimum="0" Maximum="{Binding Width}" Width="85" Margin="3"
|
||||
Value="{Binding LeftLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="LeftTB"
|
||||
Text="{Binding LeftLimit, StringFormat={}от {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Width="85">
|
||||
<Slider Minimum="0" Maximum="{Binding Width}" Width="85" Margin="3"
|
||||
Value="{Binding RightLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="RightTB"
|
||||
Text="{Binding RightLimit, StringFormat={}до {0}}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Margin="5" DataContext="{Binding Pv}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Сторона" />
|
||||
<Slider Minimum="5" Maximum="100" VerticalAlignment="Center" Value="{Binding Radius}" />
|
||||
<TextBlock Text="{Binding Radius}" />
|
||||
<TextBlock Text="Углы" />
|
||||
<Slider Minimum="3" Maximum="10" VerticalAlignment="Center" Value="{Binding Corners}" />
|
||||
<TextBlock Text="{Binding Corners}" />
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<StackPanel Margin="5" DataContext="{Binding Lv}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<TextBlock>Угол</TextBlock>
|
||||
<Slider Value="{Binding Angle}" Minimum="0" Maximum="90" />
|
||||
<TextBlock Text="{Binding Angle}" />
|
||||
<TextBlock>Длина</TextBlock>
|
||||
<Slider Value="{Binding Lenght}" Minimum="5" Maximum="90" />
|
||||
<TextBlock Text="{Binding Lenght}" />
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</Panel>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" VerticalAlignment="Top">
|
||||
<TextBlock x:Name="CurrentBlock" Margin="5" />
|
||||
<Slider Minimum="50" Maximum="500" TickFrequency="5" ValueChanged="Slider_ValueChanged" Value="100" />
|
||||
<TextBlock x:Name="ScaleTB" />
|
||||
<TextBlock x:Name="TotalTB" Text="0" Margin="5" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Column="1" Margin="5,5,5,5" HorizontalScrollBarVisibility="Visible"
|
||||
VerticalScrollBarVisibility="Visible">
|
||||
<Grid Name="SchemePanel">
|
||||
<Ellipse x:Name="BaseElipse" Stroke="Black" StrokeThickness="10" Height="150" Margin="15" Width="150"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" IsVisible="False" />
|
||||
<Canvas Name="SchemeCanvas" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="15" />
|
||||
</Grid>
|
||||
|
||||
</ScrollViewer>
|
||||
<Grid Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"
|
||||
RowDefinitions="Auto * Auto">
|
||||
<TextBlock>Слои</TextBlock>
|
||||
<ListBox Margin="0,5" Grid.Row="1" SelectionChanged="SetupSelected" ItemsSource="{Binding Figures}"
|
||||
Name="Layers">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="Auto *">
|
||||
<TextBox Grid.Column="1" Text="{Binding Name}" HorizontalAlignment="Stretch"></TextBox>
|
||||
<Border Margin="5" Background="OrangeRed" Width="30"></Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button Command="{Binding OnSave}" Grid.Row="2">Сохранить</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using MCCAD.Models;
|
||||
using MCCAD.ViewModels;
|
||||
using ReactiveUI.Avalonia;
|
||||
|
||||
namespace MCCAD.Views;
|
||||
|
||||
public partial class DrawingView : ReactiveUserControl<DrawingViewModel>
|
||||
{
|
||||
public Dictionary<IFigureView, Canvas> _cache = new();
|
||||
public bool mark = true;
|
||||
private const int BlockSize = 15;
|
||||
|
||||
private bool _switching;
|
||||
|
||||
public DrawingView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
if (ViewModel != null)
|
||||
{
|
||||
foreach (var viewModelFigure in ViewModel.Figures)
|
||||
{
|
||||
viewModelFigure.OnNewSheme += DrawShape;
|
||||
viewModelFigure.Rebuild();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DrawShape(List<IntPoint> points, IFigureView view)
|
||||
{
|
||||
if (!_cache.TryGetValue(view, out Canvas canvas))
|
||||
{
|
||||
canvas = new Canvas();
|
||||
_cache.Add(view, canvas);
|
||||
SchemeCanvas.Children.Add(canvas);
|
||||
}
|
||||
|
||||
canvas.Children.Clear();
|
||||
|
||||
canvas.Width = points.Select(i => i.X).Max() * BlockSize;
|
||||
canvas.Height = points.Select(i => i.Y).Max() * BlockSize;
|
||||
Dictionary<IntPoint, string> markup = new Dictionary<IntPoint, string>();
|
||||
|
||||
if (mark)
|
||||
{
|
||||
var lined = points.OrderBy(i => i.Y).GroupBy(i => i.Y);
|
||||
foreach (var l in lined)
|
||||
{
|
||||
if (l.Count() < 3)
|
||||
continue;
|
||||
var line = l.OrderBy(i => i.X).ToList();
|
||||
var linePoint = new List<int> { 0 };
|
||||
for (int i = 0; i < line.Count; i++)
|
||||
{
|
||||
if (i != line.Count - 1 && line[i].X != line[i + 1].X - 1)
|
||||
{
|
||||
linePoint.Add(i);
|
||||
linePoint.Add(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
linePoint.Add(line.Count - 1);
|
||||
|
||||
var linesIds = linePoint.Chunk(2);
|
||||
foreach (var microLineId in linesIds)
|
||||
{
|
||||
var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList();
|
||||
if (micloLine.Count > 2)
|
||||
{
|
||||
markup.Add(micloLine.First(), "←");
|
||||
markup.Add(micloLine.Last(), "→");
|
||||
markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lined = points.OrderBy(i => i.X).GroupBy(i => i.X);
|
||||
foreach (var l in lined)
|
||||
{
|
||||
if (l.Count() < 3)
|
||||
continue;
|
||||
var line = l.OrderBy(i => i.Y).ToList();
|
||||
var linePoint = new List<int>() { 0 };
|
||||
for (int i = 0; i < line.Count; i++)
|
||||
{
|
||||
if (i != line.Count - 1 && line[i].Y != line[i + 1].Y - 1)
|
||||
{
|
||||
linePoint.Add(i);
|
||||
linePoint.Add(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
linePoint.Add(line.Count - 1);
|
||||
|
||||
var linesIds = linePoint.Chunk(2);
|
||||
foreach (var microLineId in linesIds)
|
||||
{
|
||||
var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList();
|
||||
if (micloLine.Count > 2)
|
||||
{
|
||||
if (!markup.TryAdd(micloLine.First(), "↑"))
|
||||
{
|
||||
markup[micloLine.First()] = "+";
|
||||
}
|
||||
|
||||
if (!markup.TryAdd(micloLine.Last(), "↓"))
|
||||
{
|
||||
markup[micloLine.Last()] = "+";
|
||||
}
|
||||
|
||||
markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
Border block = new Border();
|
||||
block.Height = BlockSize;
|
||||
block.Width = BlockSize;
|
||||
block.BorderThickness = new Thickness(2);
|
||||
block.Background = new SolidColorBrush(Colors.LightGray);
|
||||
block.DataContext = point;
|
||||
block.PointerEntered += (sender, e) => { CurrentBlock.Text = (sender as Border).DataContext.ToString(); };
|
||||
if (mark)
|
||||
{
|
||||
if (markup.TryGetValue(point, out var text))
|
||||
block.Child = new TextBlock
|
||||
{
|
||||
Text = text, HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center, FontSize = 10
|
||||
};
|
||||
}
|
||||
|
||||
Canvas.SetLeft(block, (point.X + view.Position.X) * BlockSize);
|
||||
Canvas.SetTop(block, (point.Y + view.Position.Y) * BlockSize);
|
||||
canvas.Children.Add(block);
|
||||
}
|
||||
|
||||
canvas.Width = BlockSize * (points.Select(i => i.X).Max() + 5);
|
||||
canvas.Height = BlockSize * (points.Select(i => i.Y).Max() + 5);
|
||||
|
||||
TotalTB.Text = points.Count.ToString();
|
||||
}
|
||||
|
||||
|
||||
private void Slider_ValueChanged(object? sender, RangeBaseValueChangedEventArgs rangeBaseValueChangedEventArgs)
|
||||
{
|
||||
if (SchemeCanvas == null)
|
||||
return;
|
||||
var e = rangeBaseValueChangedEventArgs;
|
||||
SchemeCanvas.RenderTransform = new ScaleTransform() { ScaleX = e.NewValue / 100, ScaleY = e.NewValue / 100 };
|
||||
ScaleTB.Text = Math.Round(rangeBaseValueChangedEventArgs.NewValue) + "%";
|
||||
}
|
||||
|
||||
private void CreateShape(object? sender, RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var x = (sender as Control).Tag;
|
||||
switch (x)
|
||||
{
|
||||
case "Ov":
|
||||
ViewModel.Ov = new OvalView();
|
||||
ViewModel.Ov.OnNewSheme += DrawShape;
|
||||
ViewModel.Ov.Rebuild();
|
||||
ViewModel.Figures.Add(ViewModel.Ov);
|
||||
SetupVisiblePanel(0);
|
||||
break;
|
||||
case "Pv":
|
||||
ViewModel.Pv = new PolygonView();
|
||||
ViewModel.Pv.OnNewSheme += DrawShape;
|
||||
ViewModel.Pv.Rebuild();
|
||||
ViewModel.Figures.Add(ViewModel.Pv);
|
||||
SetupVisiblePanel(1);
|
||||
break;
|
||||
case "Lv":
|
||||
ViewModel.Lv = new LineView();
|
||||
ViewModel.Lv.OnNewSheme += DrawShape;
|
||||
ViewModel.Lv.Rebuild();
|
||||
ViewModel.Figures.Add(ViewModel.Lv);
|
||||
SetupVisiblePanel(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupSelected(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (Layers.SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_switching = true;
|
||||
switch (Layers.SelectedItem)
|
||||
{
|
||||
case OvalView ov:
|
||||
ViewModel.Ov = ov;
|
||||
SetupVisiblePanel(0);
|
||||
break;
|
||||
case PolygonView pv:
|
||||
ViewModel.Pv = pv;
|
||||
SetupVisiblePanel(1);
|
||||
break;
|
||||
case LineView lv:
|
||||
ViewModel.Lv = lv;
|
||||
SetupVisiblePanel(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupVisiblePanel(int index)
|
||||
{
|
||||
for (var i = 0; i < ToolsTab.Children.Count; i++)
|
||||
{
|
||||
ToolsTab.Children[i].IsVisible = i == index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<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:viewModels="clr-namespace:MCCAD.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="MCCAD.Views.DrawingsCollectionView"
|
||||
x:DataType="viewModels:DrawingsCollectionViewModel">
|
||||
<Grid RowDefinitions="Auto * Auto" ColumnDefinitions="* *">
|
||||
<TextBlock Text="{Binding User.Name, StringFormat={}Добро пожаловать {1}}"></TextBlock>
|
||||
<Button Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" Command="{Binding Exit}">Выйти</Button>
|
||||
<ListBox Margin="10" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Drawings}"
|
||||
SelectedItem="{Binding SelectedDrawing}"
|
||||
Grid.Column="0" Grid.Row="1">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding Name}" FontSize="20" FontWeight="Bold"></TextBlock>
|
||||
<TextBlock Text="{Binding Size, StringFormat={}{0} кб.}"></TextBlock>
|
||||
<DockPanel HorizontalAlignment="Stretch" LastChildFill="False">
|
||||
<TextBlock DockPanel.Dock="Right"
|
||||
Text="{Binding LastChange, StringFormat={}Дата последнего изменения: {0}}"
|
||||
FontSize="18">
|
||||
</TextBlock>
|
||||
<TextBlock DockPanel.Dock="Left" Text="{Binding Size, StringFormat={}Дата создания: {0}}"
|
||||
FontSize="18">
|
||||
</TextBlock>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<ScrollViewer Grid.Row="1" Grid.Column="1">
|
||||
<StackPanel Spacing="10">
|
||||
<TextBlock>Название</TextBlock>
|
||||
<TextBox Text="{Binding SelectedDrawingName, Mode=TwoWay}"></TextBox>
|
||||
<Button Command="{Binding Open}">Открыть</Button>
|
||||
<Button Command="{Binding Save}">Сохранить</Button>
|
||||
<Button Background="OrangeRed" Command="{Binding Delete}">Удалить</Button>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<Button Grid.Row="2" Grid.Column="0" Command="{Binding Create}">Создать чертеж</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using MCCAD.ViewModels;
|
||||
using ReactiveUI.Avalonia;
|
||||
|
||||
namespace MCCAD.Views;
|
||||
|
||||
public partial class DrawingsCollectionView : ReactiveUserControl<DrawingsCollectionViewModel>
|
||||
{
|
||||
public DrawingsCollectionView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<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:viewModels="clr-namespace:MCCAD.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="MCCAD.Views.LoginView"
|
||||
x:DataType="viewModels:LoginViewModel">
|
||||
<UserControl.Styles>
|
||||
<Style Selector="Button.LoginButton">
|
||||
<Setter Property="Margin" Value="20, 5" />
|
||||
<Setter Property="Transitions">
|
||||
<Transitions>
|
||||
<DoubleTransition Property="Height" Duration="0:0:0.3" />
|
||||
</Transitions>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style Selector="TextBlock.AnimateHeight">
|
||||
<Setter Property="Transitions">
|
||||
<Transitions>
|
||||
<DoubleTransition Property="Height" Duration="0:0:0.3" />
|
||||
</Transitions>
|
||||
</Setter>
|
||||
</Style>
|
||||
</UserControl.Styles>
|
||||
<StackPanel Width="250" Classes="Centred" HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="10">
|
||||
<TextBlock FontSize="24">Авторизация</TextBlock>
|
||||
<TextBlock>Введите ваш логин и пароль</TextBlock>
|
||||
<TextBlock Classes="AnimateHeight" Foreground="Red" IsVisible="{Binding InvalidData}">Логин или пароль неверны</TextBlock>
|
||||
<TextBox TextChanged="UpdateLoginVisibility" Text="{Binding Login}" Name="LoginText" Watermark="Логин"
|
||||
HorizontalAlignment="Stretch" />
|
||||
<TextBox TextChanged="UpdateLoginVisibility" Text="{Binding Password}" Name="PasswordText"
|
||||
HorizontalAlignment="Stretch" PasswordChar="~"
|
||||
Watermark="Пароль" />
|
||||
<Button Height="0" Name="LoginButton" VerticalAlignment="Top" Command="{Binding TryAuth}"
|
||||
Classes="Long LoginButton" HorizontalAlignment="Center">
|
||||
Войти
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
using Avalonia.VisualTree;
|
||||
using MCCAD.ViewModels;
|
||||
using ReactiveUI.Avalonia;
|
||||
|
||||
namespace MCCAD.Views;
|
||||
|
||||
public partial class LoginView : ReactiveUserControl<LoginViewModel>
|
||||
{
|
||||
private const double Button_VISIBLE = 30;
|
||||
|
||||
public LoginView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void UpdateLoginVisibility(object? sender, TextChangedEventArgs e)
|
||||
{
|
||||
LoginButton.Height = string.IsNullOrWhiteSpace(LoginText.Text) ||
|
||||
string.IsNullOrWhiteSpace(PasswordText.Text) || PasswordText.Text.Length < 6
|
||||
? 0
|
||||
: Button_VISIBLE;
|
||||
}
|
||||
}
|
||||
@@ -4,152 +4,17 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
xmlns:mcd="using:MCCAD.ViewModels"
|
||||
xmlns:views="clr-namespace:MCCAD.Views"
|
||||
x:Class="MCCAD.Views.MainWindow"
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
xmlns:rui="clr-namespace:ReactiveUI.Avalonia;assembly=ReactiveUI.Avalonia"
|
||||
xmlns:mccad="clr-namespace:MCCAD"
|
||||
Icon="/Assets/avalonia-logo.ico"
|
||||
Title="MCCAD">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="250" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="250"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="125" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="5,5,5,5">
|
||||
<HyperlinkButton Click="CreateShape" Tag="Ov">Новый элипс</HyperlinkButton>
|
||||
<HyperlinkButton Click="CreateShape" Tag="Pv">Новый многоугольник</HyperlinkButton>
|
||||
<HyperlinkButton Click="CreateShape" Tag="Lv">Новая линия</HyperlinkButton>
|
||||
<Panel Name="ToolsTab" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<ScrollViewer DataContext="{Binding Path=Ov}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Размеры">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Ширина" />
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider Minimum="3" Maximum="50" VerticalAlignment="Center"
|
||||
Value="{Binding Width}" />
|
||||
<TextBox x:Name="WStr" Grid.Column="1" Margin="3" MaxLength="4"
|
||||
Text="{Binding Width}" />
|
||||
</Grid>
|
||||
<TextBlock Text="Высота" />
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider Minimum="3" Maximum="50" VerticalAlignment="Center"
|
||||
Value="{Binding Heigth}" />
|
||||
<TextBox x:Name="HStr" Grid.Column="1" Margin="3" MaxLength="4"
|
||||
Text="{Binding Heigth}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Ограничения">
|
||||
<DockPanel LastChildFill="False" Name="LimitsDP">
|
||||
<StackPanel DockPanel.Dock="Top">
|
||||
<Slider Minimum="0" Maximum="{Binding Heigth}" Width="85" Margin="3"
|
||||
Value="{Binding TopLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="TopTB"
|
||||
Text="{Binding TopLimit, StringFormat={}от {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Bottom">
|
||||
<Slider Minimum="0" Maximum="{Binding Heigth}" Width="85" Margin="3"
|
||||
Value="{Binding BottomLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="BotTB"
|
||||
Text="{Binding BottomLimit, StringFormat={}до {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<Slider Minimum="0" Maximum="{Binding Width}" Width="85" Margin="3"
|
||||
Value="{Binding LeftLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="LeftTB"
|
||||
Text="{Binding LeftLimit, StringFormat={}от {0}}" />
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Width="85">
|
||||
<Slider Minimum="0" Maximum="{Binding Width}" Width="85" Margin="3"
|
||||
Value="{Binding RightLimit}" />
|
||||
<TextBlock HorizontalAlignment="Center" Name="RightTB"
|
||||
Text="{Binding RightLimit, StringFormat={}до {0}}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Expander>
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<ScrollViewer Margin="5" DataContext="{Binding Pv}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Сторона" />
|
||||
<Slider Minimum="5" Maximum="100" VerticalAlignment="Center" Value="{Binding Radius}" />
|
||||
<TextBlock Text="{Binding Radius}" />
|
||||
<TextBlock Text="Углы" />
|
||||
<Slider Minimum="3" Maximum="10" VerticalAlignment="Center" Value="{Binding Corners}" />
|
||||
<TextBlock Text="{Binding Corners}" />
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<StackPanel Margin="5" DataContext="{Binding Lv}" IsVisible="False">
|
||||
<StackPanel>
|
||||
<TextBlock>Угол</TextBlock>
|
||||
<Slider Value="{Binding Angle}" Minimum="0" Maximum="90" />
|
||||
<TextBlock Text="{Binding Angle}" />
|
||||
<TextBlock>Длина</TextBlock>
|
||||
<Slider Value="{Binding Lenght}" Minimum="5" Maximum="90" />
|
||||
<TextBlock Text="{Binding Lenght}" />
|
||||
<Expander HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
Header="Расположение">
|
||||
<views:PositionControl DataContext="{Binding Position}" />
|
||||
</Expander>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</Panel>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="1" VerticalAlignment="Top">
|
||||
<TextBlock x:Name="CurrentBlock" Margin="5" />
|
||||
<Slider Minimum="50" Maximum="500" TickFrequency="5" ValueChanged="Slider_ValueChanged" Value="100" />
|
||||
<TextBlock x:Name="ScaleTB" />
|
||||
<TextBlock x:Name="TotalTB" Text="0" Margin="5" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Column="1" Margin="5,5,5,5" HorizontalScrollBarVisibility="Visible">
|
||||
<Grid>
|
||||
<Ellipse x:Name="BaseElipse" Stroke="Black" StrokeThickness="10" Height="150" Margin="15" Width="150"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left" IsVisible="False" />
|
||||
<Canvas Name="ShemeChanvas" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="15" />
|
||||
</Grid>
|
||||
|
||||
</ScrollViewer>
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" Spacing="10">
|
||||
<TextBlock>Слои</TextBlock>
|
||||
<ListBox SelectionChanged="SetupSelected" ItemsSource="{Binding Figures}" Name="Layers">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="Auto *">
|
||||
<TextBox Grid.Column="1" Text="{Binding Name}" HorizontalAlignment="Stretch"></TextBox>
|
||||
<Border Margin="5" Background="OrangeRed" Width="30"></Border>
|
||||
</Grid>
|
||||
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</StackPanel>
|
||||
<rui:RoutedViewHost Margin="10" Router="{Binding Router}">
|
||||
<rui:RoutedViewHost.ViewLocator>
|
||||
<mccad:MainViewLocator />
|
||||
</rui:RoutedViewHost.ViewLocator>
|
||||
</rui:RoutedViewHost>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -14,217 +14,8 @@ namespace MCCAD.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public Dictionary<IFigureView, Canvas> _cache = new();
|
||||
public bool mark = true;
|
||||
int blockSize = 15;
|
||||
|
||||
private bool switching = false;
|
||||
private MainWindowViewModel DC => DataContext as MainWindowViewModel;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnDataContextChanged(EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DrawShape(List<IntPoint> points, IFigureView view)
|
||||
{
|
||||
if (!_cache.TryGetValue(view, out Canvas canvas))
|
||||
{
|
||||
canvas = new Canvas();
|
||||
_cache.Add(view, canvas);
|
||||
ShemeChanvas.Children.Add(canvas);
|
||||
}
|
||||
canvas.Children.Clear();
|
||||
|
||||
canvas.Width = points.Select(i => i.X).Max() * blockSize;
|
||||
canvas.Height = points.Select(i => i.Y).Max() * blockSize;
|
||||
Dictionary<IntPoint, string> markup = new Dictionary<IntPoint, string>();
|
||||
|
||||
if (mark)
|
||||
{
|
||||
var lined = points.OrderBy(i => i.Y).GroupBy(i => i.Y);
|
||||
foreach (var l in lined)
|
||||
{
|
||||
if (l.Count() < 3)
|
||||
continue;
|
||||
var line = l.OrderBy(i => i.X).ToList();
|
||||
var linePoint = new List<int> { 0 };
|
||||
for (int i = 0; i < line.Count; i++)
|
||||
{
|
||||
if (i != line.Count - 1 && line[i].X != line[i + 1].X - 1)
|
||||
{
|
||||
linePoint.Add(i);
|
||||
linePoint.Add(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
linePoint.Add(line.Count - 1);
|
||||
|
||||
var linesIds = linePoint.Chunk(2);
|
||||
foreach (var microLineId in linesIds)
|
||||
{
|
||||
var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList();
|
||||
if (micloLine.Count > 2)
|
||||
{
|
||||
markup.Add(micloLine.First(), "←");
|
||||
markup.Add(micloLine.Last(), "→");
|
||||
markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lined = points.OrderBy(i => i.X).GroupBy(i => i.X);
|
||||
foreach (var l in lined)
|
||||
{
|
||||
if (l.Count() < 3)
|
||||
continue;
|
||||
var line = l.OrderBy(i => i.Y).ToList();
|
||||
var linePoint = new List<int>() { 0 };
|
||||
for (int i = 0; i < line.Count; i++)
|
||||
{
|
||||
if (i != line.Count - 1 && line[i].Y != line[i + 1].Y - 1)
|
||||
{
|
||||
linePoint.Add(i);
|
||||
linePoint.Add(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
linePoint.Add(line.Count - 1);
|
||||
|
||||
var linesIds = linePoint.Chunk(2);
|
||||
foreach (var microLineId in linesIds)
|
||||
{
|
||||
var micloLine = line.Skip(microLineId[0]).Take(microLineId[1] - microLineId[0] + 1).ToList();
|
||||
if (micloLine.Count > 2)
|
||||
{
|
||||
if (!markup.TryAdd(micloLine.First(), "↑"))
|
||||
{
|
||||
markup[micloLine.First()] = "+";
|
||||
}
|
||||
|
||||
if (!markup.TryAdd(micloLine.Last(), "↓"))
|
||||
{
|
||||
markup[micloLine.Last()] = "+";
|
||||
}
|
||||
|
||||
markup.Add(micloLine[micloLine.Count / 2], micloLine.Count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
Border block = new Border();
|
||||
block.Height = blockSize;
|
||||
block.Width = blockSize;
|
||||
block.BorderThickness = new Thickness(2);
|
||||
block.Background = new SolidColorBrush(Colors.LightGray);
|
||||
block.DataContext = point;
|
||||
block.PointerEntered += (sender, e) => { CurrentBlock.Text = (sender as Border).DataContext.ToString(); };
|
||||
if (mark)
|
||||
{
|
||||
if (markup.TryGetValue(point, out var text))
|
||||
block.Child = new TextBlock
|
||||
{
|
||||
Text = text, HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center, FontSize = 10
|
||||
};
|
||||
}
|
||||
|
||||
Canvas.SetLeft(block, (point.X + view.Position.X) * blockSize);
|
||||
Canvas.SetTop(block, (point.Y + view.Position.Y) * blockSize);
|
||||
canvas.Children.Add(block);
|
||||
}
|
||||
|
||||
canvas.Width = blockSize * (points.Select(i => i.X).Max() + 5);
|
||||
canvas.Height = blockSize * (points.Select(i => i.Y).Max() + 5);
|
||||
|
||||
TotalTB.Text = points.Count.ToString();
|
||||
}
|
||||
|
||||
|
||||
private void Slider_ValueChanged(object? sender, RangeBaseValueChangedEventArgs rangeBaseValueChangedEventArgs)
|
||||
{
|
||||
if (ShemeChanvas == null)
|
||||
return;
|
||||
var e = rangeBaseValueChangedEventArgs;
|
||||
ShemeChanvas.RenderTransform = new ScaleTransform() { ScaleX = e.NewValue / 100, ScaleY = e.NewValue / 100 };
|
||||
// ShemeChanvas.transf.LayoutTransform = new ScaleTransform() { ScaleX = e.NewValue / 95, ScaleY = e.NewValue / 95 };
|
||||
ScaleTB.Text = Math.Round(rangeBaseValueChangedEventArgs.NewValue) + "%";
|
||||
}
|
||||
|
||||
private void CreateShape(object? sender, RoutedEventArgs routedEventArgs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var x = (sender as Control).Tag;
|
||||
switch (x)
|
||||
{
|
||||
case "Ov":
|
||||
DC.Ov = new OvalView();
|
||||
DC.Ov.OnNewSheme += DrawShape;
|
||||
DC.Ov.Rebuild();
|
||||
DC.Figures.Add(DC.Ov);
|
||||
SetupVisiblePanel(0);
|
||||
break;
|
||||
case "Pv":
|
||||
DC.Pv = new PolygonView();
|
||||
DC.Pv.OnNewSheme += DrawShape;
|
||||
DC.Pv.Rebuild();
|
||||
DC.Figures.Add(DC.Pv);
|
||||
SetupVisiblePanel(1);
|
||||
break;
|
||||
case "Lv":
|
||||
DC.Lv = new LineView();
|
||||
DC.Lv.OnNewSheme += DrawShape;
|
||||
DC.Lv.Rebuild();
|
||||
DC.Figures.Add(DC.Lv);
|
||||
SetupVisiblePanel(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupSelected(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (Layers.SelectedItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switching = true;
|
||||
switch (Layers.SelectedItem)
|
||||
{
|
||||
case OvalView ov:
|
||||
DC.Ov = ov;
|
||||
SetupVisiblePanel(0);
|
||||
break;
|
||||
case PolygonView pv:
|
||||
DC.Pv = pv;
|
||||
SetupVisiblePanel(1);
|
||||
break;
|
||||
case LineView lv:
|
||||
DC.Lv = lv;
|
||||
SetupVisiblePanel(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupVisiblePanel(int index)
|
||||
{
|
||||
for (var i = 0; i < ToolsTab.Children.Count; i++)
|
||||
{
|
||||
ToolsTab.Children[i].IsVisible = i == index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<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:viewModels="clr-namespace:MCCAD.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="MCCAD.Views.TeamsView"
|
||||
x:DataType="viewModels:TeamsViewModel">
|
||||
<Grid RowDefinitions="35 Auto * Auto">
|
||||
<TextBox Text="{Binding SearchString}" Margin="5" Grid.Row="1" HorizontalAlignment="Stretch"></TextBox>
|
||||
<ListBox Margin="5" ItemsSource="{Binding Teams}" SelectionChanged="SelectingItemsControl_OnSelectionChanged">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Right"
|
||||
Text="{Binding MemberCount, StringFormat={}Количество членов: {0}}">
|
||||
</TextBlock>
|
||||
<StackPanel DockPanel.Dock="Left">
|
||||
<TextBlock Text="{Binding Name}" FontSize="20" FontWeight="Bold"></TextBlock>
|
||||
<TextBlock Text="{Binding CreatedAt, StringFormat={}Создана {0}}"></TextBlock>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<Button Grid.Row="3">Создать команду</Button>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,20 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using MCCAD.ViewModels;
|
||||
using ReactiveUI.Avalonia;
|
||||
|
||||
namespace MCCAD.Views;
|
||||
|
||||
public partial class TeamsView : ReactiveUserControl<TeamsViewModel>
|
||||
{
|
||||
public TeamsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void SelectingItemsControl_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user