Kompetenzen fast fertig
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using LehrerApp.Core.Interfaces;
|
||||
using LehrerApp.Core.Models;
|
||||
using LehrerApp.Core.Services;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace LehrerApp.Desktop.ViewModels.Groups;
|
||||
|
||||
public partial class CompetencyOverviewTabViewModel : ObservableObject
|
||||
{
|
||||
private readonly IUnitRepository _units;
|
||||
private readonly IExamRepository _exams;
|
||||
private readonly IExamResultRepository _results;
|
||||
private readonly ICompetencyDomainRepository _catalog;
|
||||
private readonly IStudentRepository _students;
|
||||
private readonly CompetencyAnalysisService _analysis;
|
||||
private LearningGroup? _group;
|
||||
|
||||
[ObservableProperty] private CompetencyStudentOption? _selectedStudent;
|
||||
[ObservableProperty] private double _reviewThreshold = 60;
|
||||
[ObservableProperty] private string _summary = "";
|
||||
[ObservableProperty] private string _emptyMessage = "";
|
||||
|
||||
public ObservableCollection<CompetencyStudentOption> StudentOptions { get; } = [];
|
||||
public ObservableCollection<CompetencyOverviewRow> Rows { get; } = [];
|
||||
public bool HasRows => Rows.Count > 0;
|
||||
public bool HasStudents => StudentOptions.Count > 0;
|
||||
public string ThresholdLabel => $"Wiederholungsbedarf unter {ReviewThreshold:0} %";
|
||||
|
||||
public CompetencyOverviewTabViewModel(IUnitRepository units, IExamRepository exams,
|
||||
IExamResultRepository results, ICompetencyDomainRepository catalog,
|
||||
IStudentRepository students, CompetencyAnalysisService analysis)
|
||||
{
|
||||
_units = units;
|
||||
_exams = exams;
|
||||
_results = results;
|
||||
_catalog = catalog;
|
||||
_students = students;
|
||||
_analysis = analysis;
|
||||
}
|
||||
|
||||
public void Initialize(LearningGroup group)
|
||||
{
|
||||
_group = group;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void Refresh()
|
||||
{
|
||||
if (_group is null) return;
|
||||
var selectedStudentId = SelectedStudent?.Id;
|
||||
var domains = _group.SubjectId is Guid subjectId
|
||||
? _catalog.GetBySubjectAndGrade(subjectId, _group.GradeLevel)
|
||||
: [];
|
||||
var units = _units.GetByGroup(_group.Id);
|
||||
var exams = _exams.GetByGroup(_group.Id);
|
||||
var results = exams.SelectMany(x => _results.GetByExam(x.Id)).ToList();
|
||||
var analysis = _analysis.Analyze(domains, units, exams, results);
|
||||
|
||||
StudentOptions.Clear();
|
||||
foreach (var student in _students.GetByGroup(_group.Id)
|
||||
.OrderBy(x => x.LastName).ThenBy(x => x.FirstName))
|
||||
StudentOptions.Add(new CompetencyStudentOption(student.Id, student.FullName));
|
||||
SelectedStudent = StudentOptions.FirstOrDefault(x => x.Id == selectedStudentId)
|
||||
?? StudentOptions.FirstOrDefault();
|
||||
|
||||
Rows.Clear();
|
||||
foreach (var item in analysis)
|
||||
Rows.Add(new CompetencyOverviewRow(item, SelectedStudent?.Id, ReviewThreshold));
|
||||
|
||||
var treated = analysis.Count(x => x.TaughtUnitCount > 0);
|
||||
var assessed = analysis.Count(x => x.AssessedExamCount > 0);
|
||||
var evaluated = analysis.Count(x => x.GroupScore is not null);
|
||||
Summary = $"{treated} von {analysis.Count} behandelt · {assessed} geprüft · {evaluated} mit Ergebnisdaten";
|
||||
EmptyMessage = analysis.Count == 0
|
||||
? "Noch keine Kompetenzen im Katalog oder in Unterrichtseinheiten und Klausuren zugeordnet."
|
||||
: "";
|
||||
OnPropertyChanged(nameof(HasRows));
|
||||
OnPropertyChanged(nameof(HasStudents));
|
||||
}
|
||||
|
||||
partial void OnSelectedStudentChanged(CompetencyStudentOption? value)
|
||||
{
|
||||
foreach (var row in Rows) row.SetStudent(value?.Id);
|
||||
}
|
||||
|
||||
partial void OnReviewThresholdChanged(double value)
|
||||
{
|
||||
OnPropertyChanged(nameof(ThresholdLabel));
|
||||
foreach (var row in Rows) row.SetThreshold(value);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record CompetencyStudentOption(Guid Id, string DisplayName);
|
||||
|
||||
public partial class CompetencyOverviewRow : ObservableObject
|
||||
{
|
||||
private readonly CompetencyAnalysisItem _item;
|
||||
private double _threshold;
|
||||
|
||||
[ObservableProperty] private string _studentResult = "–";
|
||||
[ObservableProperty] private string _recommendation = "Noch keine Bewertung";
|
||||
[ObservableProperty] private string _recommendationColor = "#6B7280";
|
||||
|
||||
public string Domain => string.IsNullOrWhiteSpace(_item.DomainCode)
|
||||
? _item.DomainName
|
||||
: $"{_item.DomainName} ({_item.DomainCode})";
|
||||
public string Code => string.IsNullOrWhiteSpace(_item.Code) ? "–" : _item.Code;
|
||||
public string Description => _item.Description;
|
||||
public string InstructionCoverage => CoverageText(
|
||||
_item.TaughtUnitCount, "behandelt", _item.PlannedUnitCount, "geplant");
|
||||
public string ExamCoverage => CoverageText(
|
||||
_item.AssessedExamCount, "geprüft", _item.PlannedExamCount, "geplant");
|
||||
public string GroupResult => ScoreText(_item.GroupScore, includeParticipants: true);
|
||||
|
||||
public CompetencyOverviewRow(CompetencyAnalysisItem item, Guid? studentId, double threshold)
|
||||
{
|
||||
_item = item;
|
||||
_threshold = threshold;
|
||||
SetStudent(studentId);
|
||||
UpdateRecommendation();
|
||||
}
|
||||
|
||||
public void SetStudent(Guid? studentId)
|
||||
{
|
||||
StudentResult = studentId is Guid id && _item.StudentScores.TryGetValue(id, out var score)
|
||||
? ScoreText(score, includeParticipants: false)
|
||||
: "–";
|
||||
}
|
||||
|
||||
public void SetThreshold(double threshold)
|
||||
{
|
||||
_threshold = threshold;
|
||||
UpdateRecommendation();
|
||||
}
|
||||
|
||||
private void UpdateRecommendation()
|
||||
{
|
||||
if (_item.GroupScore is null)
|
||||
{
|
||||
Recommendation = "Noch keine Bewertung";
|
||||
RecommendationColor = "#6B7280";
|
||||
}
|
||||
else if (_item.GroupScore.Percent < _threshold)
|
||||
{
|
||||
Recommendation = "Wiederholungsbedarf";
|
||||
RecommendationColor = "#C62828";
|
||||
}
|
||||
else
|
||||
{
|
||||
Recommendation = "Stand solide";
|
||||
RecommendationColor = "#2E7D32";
|
||||
}
|
||||
}
|
||||
|
||||
private static string CoverageText(int completed, string completedLabel, int planned, string plannedLabel)
|
||||
{
|
||||
if (completed == 0 && planned == 0) return "–";
|
||||
if (completed == 0) return $"{planned}× {plannedLabel}";
|
||||
if (planned == 0) return $"{completed}× {completedLabel}";
|
||||
return $"{completed}× {completedLabel} · {planned}× {plannedLabel}";
|
||||
}
|
||||
|
||||
private static string ScoreText(CompetencyScore? score, bool includeParticipants)
|
||||
{
|
||||
if (score is null) return "–";
|
||||
var evidence = score.EvidenceCount == 1 ? "1 Aufgabenwert" : $"{score.EvidenceCount} Aufgabenwerte";
|
||||
return includeParticipants
|
||||
? $"{score.Percent:0.#} % · {score.ParticipantCount} Schüler · {evidence}"
|
||||
: $"{score.Percent:0.#} % · {evidence}";
|
||||
}
|
||||
}
|
||||
@@ -206,6 +206,10 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
NotifyWriteCommands();
|
||||
}
|
||||
partial void OnShowFormerStudentsChanged(bool value) => LoadStudents();
|
||||
partial void OnActiveTabIndexChanged(int value)
|
||||
{
|
||||
if (value == 6) CompetencyOverviewTab.Refresh();
|
||||
}
|
||||
|
||||
public ObservableCollection<StudentSummary> Students { get; } = [];
|
||||
public ObservableCollection<ExamSummary> Exams { get; } = [];
|
||||
@@ -213,6 +217,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
public ParticipationTabViewModel ParticipationTab { get; }
|
||||
public GradeOverviewTabViewModel GradeOverviewTab { get; }
|
||||
public PlanningTabViewModel PlanningTab { get; }
|
||||
public CompetencyOverviewTabViewModel CompetencyOverviewTab { get; }
|
||||
public Func<Task<bool>>? OnAddStudent { get; set; }
|
||||
public Func<StudentSummary, Task<bool>>? OnWithdrawStudent { get; set; }
|
||||
public Func<Guid, Task<bool>>? OnAddExam { get; set; }
|
||||
@@ -227,13 +232,14 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
IGroupMembershipRepository memberships, ISubjectRepository subjects,
|
||||
IExamRepository exams, IGradeRepository grades, IWorkTaskRepository tasks,
|
||||
ParticipationTabViewModel participationTab, GradeOverviewTabViewModel gradeOverviewTab,
|
||||
PlanningTabViewModel planningTab)
|
||||
PlanningTabViewModel planningTab, CompetencyOverviewTabViewModel competencyOverviewTab)
|
||||
{
|
||||
_groups = groups; _students = students; _memberships = memberships; _subjects = subjects;
|
||||
_exams = exams; _grades = grades; _tasks = tasks;
|
||||
ParticipationTab = participationTab;
|
||||
GradeOverviewTab = gradeOverviewTab;
|
||||
PlanningTab = planningTab;
|
||||
CompetencyOverviewTab = competencyOverviewTab;
|
||||
}
|
||||
|
||||
public void LoadGroup(Guid id)
|
||||
@@ -252,6 +258,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
ParticipationTab.Initialize(Group.Id, Group.SchoolYear, IsReadOnly);
|
||||
GradeOverviewTab.Initialize(Group.Id, Group.GradingSystem, Group.Type, GroupTitle, Group.SchoolYear, IsReadOnly);
|
||||
PlanningTab.Initialize(Group.Id, IsReadOnly);
|
||||
CompetencyOverviewTab.Initialize(Group);
|
||||
}
|
||||
|
||||
private void ReloadExams()
|
||||
@@ -261,6 +268,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
Exams.Clear();
|
||||
foreach (var e in _exams.GetByGroup(Group.Id)) Exams.Add(new ExamSummary(e));
|
||||
SelectedExam = Exams.FirstOrDefault(e => e.Id == selectedId);
|
||||
CompetencyOverviewTab.Refresh();
|
||||
}
|
||||
|
||||
public void LoadStudents()
|
||||
@@ -368,6 +376,7 @@ public partial class GroupDetailViewModel : ObservableObject
|
||||
var exam = _exams.GetById(SelectedExam.Id);
|
||||
if (exam is null) return;
|
||||
await OnGradeExam(exam);
|
||||
CompetencyOverviewTab.Refresh();
|
||||
}
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanEditSelectedExam))]
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace LehrerApp.Desktop.ViewModels.Settings;
|
||||
|
||||
public partial class CompetencyCatalogCopyTargetViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty] private int _targetGradeLevel;
|
||||
[ObservableProperty] private string _error = "";
|
||||
|
||||
public string SourceLabel { get; }
|
||||
public int SourceGradeLevel { get; }
|
||||
|
||||
public CompetencyCatalogCopyTargetViewModel(string subjectName, int sourceGradeLevel)
|
||||
{
|
||||
SourceGradeLevel = sourceGradeLevel;
|
||||
SourceLabel = $"{subjectName} · Klassenstufe {sourceGradeLevel}";
|
||||
_targetGradeLevel = sourceGradeLevel < 13 ? sourceGradeLevel + 1 : sourceGradeLevel - 1;
|
||||
}
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
Error = TargetGradeLevel == SourceGradeLevel
|
||||
? "Quell- und Zielklassenstufe müssen verschieden sein."
|
||||
: TargetGradeLevel is < 1 or > 13
|
||||
? "Die Klassenstufe muss zwischen 1 und 13 liegen."
|
||||
: "";
|
||||
return Error.Length == 0;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ public partial class CompetencyCatalogImportViewModel : ObservableObject
|
||||
public IReadOnlyList<ImportModeOption> Modes { get; }
|
||||
public ObservableCollection<CompetencyImportConflictItem> Conflicts { get; } = [];
|
||||
public IReadOnlyList<string> Warnings => _preview.Warnings;
|
||||
public string Heading { get; }
|
||||
public string Target => $"{_preview.SubjectName} · Klassenstufe {_preview.GradeLevel}";
|
||||
public string Summary =>
|
||||
$"{_preview.NewDomains} neue Bereiche · {_preview.NewCompetencies} neue Kompetenzen · " +
|
||||
@@ -26,10 +27,12 @@ public partial class CompetencyCatalogImportViewModel : ObservableObject
|
||||
public bool IsReplace => SelectedMode.Mode == CompetencyCatalogImportMode.Replace;
|
||||
|
||||
public CompetencyCatalogImportViewModel(
|
||||
SettingsViewModel settings, CompetencyCatalogImportPreview preview)
|
||||
SettingsViewModel settings, CompetencyCatalogImportPreview preview,
|
||||
string heading = "Import prüfen")
|
||||
{
|
||||
_settings = settings;
|
||||
_preview = preview;
|
||||
Heading = heading;
|
||||
Modes =
|
||||
[
|
||||
new(CompetencyCatalogImportMode.Merge, "Zusammenführen (empfohlen)"),
|
||||
|
||||
@@ -733,7 +733,8 @@ public partial class SettingsViewModel : ObservableObject
|
||||
CatalogValidation = "";
|
||||
if (CatalogSubject is null) return;
|
||||
foreach (var d in _domainRepo.GetBySubjectAndGrade(CatalogSubject.Id, CatalogGradeLevel))
|
||||
Domains.Add(new DomainEditItem(d, _domainRepo));
|
||||
Domains.Add(CreateDomainEditItem(d));
|
||||
RefreshDomainMoveState();
|
||||
}
|
||||
|
||||
// ── Katalog: Bereich hinzufügen / löschen ────────────────────────────────
|
||||
@@ -753,7 +754,8 @@ public partial class SettingsViewModel : ObservableObject
|
||||
SortOrder = Domains.Count,
|
||||
};
|
||||
_domainRepo.Save(domain);
|
||||
Domains.Add(new DomainEditItem(domain, _domainRepo));
|
||||
Domains.Add(CreateDomainEditItem(domain));
|
||||
RefreshDomainMoveState();
|
||||
NewDomainName = ""; NewDomainCode = ""; CatalogValidation = "";
|
||||
}
|
||||
|
||||
@@ -763,6 +765,31 @@ public partial class SettingsViewModel : ObservableObject
|
||||
if (item is null) return;
|
||||
_domainRepo.Delete(item.Id);
|
||||
Domains.Remove(item);
|
||||
PersistDomainOrder();
|
||||
}
|
||||
|
||||
private DomainEditItem CreateDomainEditItem(CompetencyDomain domain) =>
|
||||
new(domain, _domainRepo, item => MoveDomain(item, -1), item => MoveDomain(item, 1));
|
||||
|
||||
private void MoveDomain(DomainEditItem item, int offset)
|
||||
{
|
||||
var oldIndex = Domains.IndexOf(item);
|
||||
var newIndex = oldIndex + offset;
|
||||
if (oldIndex < 0 || newIndex < 0 || newIndex >= Domains.Count) return;
|
||||
Domains.Move(oldIndex, newIndex);
|
||||
PersistDomainOrder();
|
||||
}
|
||||
|
||||
private void PersistDomainOrder()
|
||||
{
|
||||
for (var i = 0; i < Domains.Count; i++) Domains[i].SetSortOrder(i);
|
||||
RefreshDomainMoveState();
|
||||
}
|
||||
|
||||
private void RefreshDomainMoveState()
|
||||
{
|
||||
for (var i = 0; i < Domains.Count; i++)
|
||||
Domains[i].SetMoveState(i > 0, i < Domains.Count - 1);
|
||||
}
|
||||
|
||||
// ── JSON Import / Export ──────────────────────────────────────────────────
|
||||
@@ -798,11 +825,40 @@ public partial class SettingsViewModel : ObservableObject
|
||||
}
|
||||
|
||||
public string ExportCatalog()
|
||||
=> SerializeCatalog(CatalogGradeLevel);
|
||||
|
||||
public CompetencyCatalogImportPreview? PrepareCatalogCopy(int targetGradeLevel)
|
||||
{
|
||||
if (CatalogSubject is null)
|
||||
{
|
||||
CatalogValidation = "Bitte zuerst ein Fach auswählen.";
|
||||
return null;
|
||||
}
|
||||
if (Domains.Count == 0)
|
||||
{
|
||||
CatalogValidation = "Der ausgewählte Katalog enthält keine Bereiche.";
|
||||
return null;
|
||||
}
|
||||
if (targetGradeLevel is < 1 or > 13 || targetGradeLevel == CatalogGradeLevel)
|
||||
{
|
||||
CatalogValidation = "Bitte eine andere Zielklassenstufe zwischen 1 und 13 auswählen.";
|
||||
return null;
|
||||
}
|
||||
|
||||
CatalogValidation = "";
|
||||
return _catalogImport.Analyze(SerializeCatalog(targetGradeLevel), CatalogSubject.Id,
|
||||
CatalogSubject.Name, targetGradeLevel);
|
||||
}
|
||||
|
||||
public void SetCatalogCopyStatus(int targetGradeLevel) =>
|
||||
CatalogValidation = $"Kompetenzkatalog wurde in Klassenstufe {targetGradeLevel} kopiert.";
|
||||
|
||||
private string SerializeCatalog(int gradeLevel)
|
||||
{
|
||||
var dto = new CatalogDto
|
||||
{
|
||||
Subject = CatalogSubject?.Name ?? "",
|
||||
GradeLevel = CatalogGradeLevel,
|
||||
GradeLevel = gradeLevel,
|
||||
Domains = Domains.Select(d => new DomainDto
|
||||
{
|
||||
Name = d.Name,
|
||||
@@ -834,8 +890,11 @@ public partial class DomainEditItem : ObservableObject
|
||||
[ObservableProperty] private string _newItemDesc = "";
|
||||
|
||||
public ObservableCollection<CompetencyItemVm> Items { get; } = [];
|
||||
public IRelayCommand MoveUpCommand { get; }
|
||||
public IRelayCommand MoveDownCommand { get; }
|
||||
|
||||
public DomainEditItem(CompetencyDomain domain, ICompetencyDomainRepository repo)
|
||||
public DomainEditItem(CompetencyDomain domain, ICompetencyDomainRepository repo,
|
||||
Action<DomainEditItem>? onMoveUp = null, Action<DomainEditItem>? onMoveDown = null)
|
||||
{
|
||||
_domain = domain;
|
||||
_repo = repo;
|
||||
@@ -846,8 +905,31 @@ public partial class DomainEditItem : ObservableObject
|
||||
? domain.Name
|
||||
: $"{domain.Name} ({domain.Code})";
|
||||
|
||||
foreach (var item in domain.Items.OrderBy(i => i.SortOrder))
|
||||
Items.Add(new CompetencyItemVm(item, DeleteItem));
|
||||
MoveUpCommand = new RelayCommand(() => onMoveUp?.Invoke(this), () => _canMoveUp);
|
||||
MoveDownCommand = new RelayCommand(() => onMoveDown?.Invoke(this), () => _canMoveDown);
|
||||
|
||||
_domain.Items = domain.Items.OrderBy(i => i.SortOrder).ToList();
|
||||
foreach (var item in _domain.Items)
|
||||
Items.Add(CreateItemViewModel(item));
|
||||
RefreshItemMoveState();
|
||||
}
|
||||
|
||||
private bool _canMoveUp;
|
||||
private bool _canMoveDown;
|
||||
|
||||
internal void SetMoveState(bool canMoveUp, bool canMoveDown)
|
||||
{
|
||||
_canMoveUp = canMoveUp;
|
||||
_canMoveDown = canMoveDown;
|
||||
MoveUpCommand.NotifyCanExecuteChanged();
|
||||
MoveDownCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
|
||||
internal void SetSortOrder(int sortOrder)
|
||||
{
|
||||
if (_domain.SortOrder == sortOrder) return;
|
||||
_domain.SortOrder = sortOrder;
|
||||
_repo.Save(_domain);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -862,15 +944,42 @@ public partial class DomainEditItem : ObservableObject
|
||||
};
|
||||
_domain.Items.Add(item);
|
||||
_repo.Save(_domain);
|
||||
Items.Add(new CompetencyItemVm(item, DeleteItem));
|
||||
Items.Add(CreateItemViewModel(item));
|
||||
RefreshItemMoveState();
|
||||
NewItemCode = ""; NewItemDesc = "";
|
||||
}
|
||||
|
||||
private void DeleteItem(CompetencyItemVm vm)
|
||||
{
|
||||
_domain.Items.RemoveAll(i => i.Id == vm.ItemId);
|
||||
_repo.Save(_domain);
|
||||
Items.Remove(vm);
|
||||
PersistItemOrder();
|
||||
}
|
||||
|
||||
private CompetencyItemVm CreateItemViewModel(CompetencyItem item) =>
|
||||
new(item, DeleteItem, vm => MoveItem(vm, -1), vm => MoveItem(vm, 1));
|
||||
|
||||
private void MoveItem(CompetencyItemVm item, int offset)
|
||||
{
|
||||
var oldIndex = Items.IndexOf(item);
|
||||
var newIndex = oldIndex + offset;
|
||||
if (oldIndex < 0 || newIndex < 0 || newIndex >= Items.Count) return;
|
||||
Items.Move(oldIndex, newIndex);
|
||||
PersistItemOrder();
|
||||
}
|
||||
|
||||
private void PersistItemOrder()
|
||||
{
|
||||
_domain.Items = Items.Select(x => x.Model).ToList();
|
||||
for (var i = 0; i < _domain.Items.Count; i++) _domain.Items[i].SortOrder = i;
|
||||
_repo.Save(_domain);
|
||||
RefreshItemMoveState();
|
||||
}
|
||||
|
||||
private void RefreshItemMoveState()
|
||||
{
|
||||
for (var i = 0; i < Items.Count; i++)
|
||||
Items[i].SetMoveState(i > 0, i < Items.Count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,14 +987,19 @@ public partial class DomainEditItem : ObservableObject
|
||||
|
||||
public class CompetencyItemVm
|
||||
{
|
||||
internal CompetencyItem Model { get; }
|
||||
public Guid ItemId { get; }
|
||||
public string Code { get; }
|
||||
public string Description { get; }
|
||||
public string Display { get; }
|
||||
public IRelayCommand DeleteCommand { get; }
|
||||
public IRelayCommand MoveUpCommand { get; }
|
||||
public IRelayCommand MoveDownCommand { get; }
|
||||
|
||||
public CompetencyItemVm(CompetencyItem item, Action<CompetencyItemVm> onDelete)
|
||||
public CompetencyItemVm(CompetencyItem item, Action<CompetencyItemVm> onDelete,
|
||||
Action<CompetencyItemVm>? onMoveUp = null, Action<CompetencyItemVm>? onMoveDown = null)
|
||||
{
|
||||
Model = item;
|
||||
ItemId = item.Id;
|
||||
Code = item.Code;
|
||||
Description = item.Description;
|
||||
@@ -893,6 +1007,19 @@ public class CompetencyItemVm
|
||||
? item.Description
|
||||
: $"[{item.Code}] {item.Description}";
|
||||
DeleteCommand = new RelayCommand(() => onDelete(this));
|
||||
MoveUpCommand = new RelayCommand(() => onMoveUp?.Invoke(this), () => _canMoveUp);
|
||||
MoveDownCommand = new RelayCommand(() => onMoveDown?.Invoke(this), () => _canMoveDown);
|
||||
}
|
||||
|
||||
private bool _canMoveUp;
|
||||
private bool _canMoveDown;
|
||||
|
||||
internal void SetMoveState(bool canMoveUp, bool canMoveDown)
|
||||
{
|
||||
_canMoveUp = canMoveUp;
|
||||
_canMoveDown = canMoveDown;
|
||||
MoveUpCommand.NotifyCanExecuteChanged();
|
||||
MoveDownCommand.NotifyCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user