Files
InternalSortMethods/InternalSortMethods/ViewModels/MainViewModel.cs
2026-04-12 19:40:01 +03:00

262 lines
8.4 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using InternalSortMethods.Models;
namespace InternalSortMethods.ViewModels;
public partial class MainViewModel : ViewModelBase
{
private CancellationTokenSource? _cancellationTokenSource;
private SortingResult? _currentResult;
private int _currentStepIndex;
private readonly ManualResetEventSlim _pauseEvent = new(true);
[ObservableProperty] private ObservableCollection<ArrayItemModel> _arrayItems = [];
[ObservableProperty] private ObservableCollection<SortingAlgorithm> _algorithms = [];
[ObservableProperty] private SortingAlgorithm? _selectedAlgorithm;
[ObservableProperty] private int _arraySize = 20;
[ObservableProperty] private double _animationSpeed = 500;
[ObservableProperty] private bool _isRunning;
[ObservableProperty] private bool _isPaused;
[ObservableProperty] private bool _isComplete;
[ObservableProperty] private string _statusText = "Готов";
public MainViewModel()
{
foreach (var algo in SortAlgorithmsProvider.Algorithms)
Algorithms.Add(algo);
SelectedAlgorithm = Algorithms[0];
GenerateArray();
}
partial void OnSelectedAlgorithmChanged(SortingAlgorithm? value)
{
if (value != null && !IsRunning)
ResetCommand.Execute(null);
}
partial void OnArraySizeChanged(int value)
{
if (!IsRunning)
GenerateArray();
}
[RelayCommand]
private void GenerateArray()
{
ArrayItems.Clear();
var random = new Random();
int maxVal = 100;
for (int i = 0; i < ArraySize; i++)
{
ArrayItems.Add(new ArrayItemModel
{
Value = random.Next(10, maxVal),
Index = i,
State = ArrayItemState.Normal
});
}
ResetStates();
StatusText = "Массив сгенерирован";
}
[RelayCommand(CanExecute = nameof(CanStart))]
private async Task StartAsync()
{
if (IsComplete || _currentResult == null)
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
var token = _cancellationTokenSource.Token;
IsRunning = true;
IsComplete = false;
StatusText = $"Сортировка: {SelectedAlgorithm?.NameRu}";
var arr = GetCurrentArray();
_currentResult = SelectedAlgorithm!.Sort(arr);
_currentStepIndex = 0;
_ = Task.Run(() => ProcessStepsAsync(token), token);
}
else
{
_pauseEvent.Set();
IsPaused = false;
StatusText = $"Продолжено";
}
StartCommand.NotifyCanExecuteChanged();
PauseCommand.NotifyCanExecuteChanged();
StepForwardCommand.NotifyCanExecuteChanged();
ResetCommand.NotifyCanExecuteChanged();
}
private bool CanStart() => !IsRunning || IsPaused || IsComplete;
[RelayCommand(CanExecute = nameof(CanPause))]
private void Pause()
{
_pauseEvent.Reset();
IsPaused = true;
StatusText = "Пауза";
StartCommand.NotifyCanExecuteChanged();
PauseCommand.NotifyCanExecuteChanged();
StepForwardCommand.NotifyCanExecuteChanged();
}
private bool CanPause() => IsRunning && !IsPaused;
[RelayCommand(CanExecute = nameof(CanStep))]
private async Task StepForward()
{
if (_currentResult == null || _currentStepIndex >= _currentResult.Steps.Count)
return;
_pauseEvent.Reset();
IsPaused = true;
await ApplyStepAsync(_currentResult.Steps[_currentStepIndex]);
_currentStepIndex++;
if (_currentStepIndex >= _currentResult.Steps.Count)
Complete();
StartCommand.NotifyCanExecuteChanged();
PauseCommand.NotifyCanExecuteChanged();
StepForwardCommand.NotifyCanExecuteChanged();
}
private bool CanStep() => IsRunning && _currentResult != null && _currentStepIndex < _currentResult.Steps.Count;
[RelayCommand]
private void Reset()
{
_cancellationTokenSource?.Cancel();
_cancellationTokenSource = null;
_currentResult = null;
_currentStepIndex = 0;
IsRunning = false;
IsPaused = false;
IsComplete = false;
_pauseEvent.Set();
ResetStates();
StatusText = "Сброшено";
StartCommand.NotifyCanExecuteChanged();
PauseCommand.NotifyCanExecuteChanged();
StepForwardCommand.NotifyCanExecuteChanged();
ResetCommand.NotifyCanExecuteChanged();
}
private async Task ProcessStepsAsync(CancellationToken token)
{
try
{
while (_currentStepIndex < _currentResult!.Steps.Count && !token.IsCancellationRequested)
{
_pauseEvent.Wait(token);
if (token.IsCancellationRequested) break;
await ApplyStepAsync(_currentResult.Steps[_currentStepIndex]);
_currentStepIndex++;
await Task.Delay((int)AnimationSpeed, token);
}
if (!token.IsCancellationRequested)
Complete();
}
catch (OperationCanceledException) { }
}
private async Task ApplyStepAsync(SortStep step)
{
await Dispatcher.UIThread.InvokeAsync(() =>
{
for (int i = 0; i < ArrayItems.Count; i++)
{
if (ArrayItems[i].State != ArrayItemState.Sorted)
ArrayItems[i].State = ArrayItemState.Normal;
}
int i1 = step.Index1;
int i2 = step.Index2;
switch (step.Action)
{
case SortActionType.Compare:
if (i1 >= 0 && i1 < ArrayItems.Count)
ArrayItems[i1].State = ArrayItemState.Comparing;
if (i2 >= 0 && i2 < ArrayItems.Count)
ArrayItems[i2].State = ArrayItemState.Comparing;
break;
case SortActionType.Swap:
if (i1 >= 0 && i1 < ArrayItems.Count && i2 >= 0 && i2 < ArrayItems.Count)
{
(ArrayItems[i1].Value, ArrayItems[i2].Value) = (ArrayItems[i2].Value, ArrayItems[i1].Value);
ArrayItems[i1].State = ArrayItemState.Swapping;
ArrayItems[i2].State = ArrayItemState.Swapping;
}
break;
case SortActionType.Set:
if (i1 >= 0 && i1 < ArrayItems.Count && step.ArraySnapshot != null && i1 < step.ArraySnapshot.Length)
ArrayItems[i1].Value = step.ArraySnapshot[i1];
break;
case SortActionType.MarkSorted:
if (i1 >= 0 && i1 < ArrayItems.Count)
ArrayItems[i1].State = ArrayItemState.Sorted;
break;
case SortActionType.MarkPivot:
if (i1 >= 0 && i1 < ArrayItems.Count)
ArrayItems[i1].State = ArrayItemState.Pivot;
break;
}
});
}
private void Complete()
{
IsRunning = false;
IsComplete = true;
Dispatcher.UIThread.Post(() =>
{
foreach (var item in ArrayItems)
item.State = ArrayItemState.Sorted;
StatusText = "Сортировка завершена!";
StartCommand.NotifyCanExecuteChanged();
PauseCommand.NotifyCanExecuteChanged();
StepForwardCommand.NotifyCanExecuteChanged();
ResetCommand.NotifyCanExecuteChanged();
});
}
private int[] GetCurrentArray()
{
int[] arr = new int[ArrayItems.Count];
for (int i = 0; i < ArrayItems.Count; i++)
arr[i] = ArrayItems[i].Value;
return arr;
}
private void ResetStates()
{
foreach (var item in ArrayItems)
item.State = ArrayItemState.Normal;
}
}