diff --git a/Core/Models/Tag/Tag.cs b/Core/Models/Tag/Tag.cs
index de0b2d7..219e399 100644
--- a/Core/Models/Tag/Tag.cs
+++ b/Core/Models/Tag/Tag.cs
@@ -34,6 +34,7 @@ public partial class Tag
public string Notes { get; set; } = string.Empty;
// TODO ensure ParentIds is the authority on parent-child relationships in both the core + UI.
+ // TODO convert these to hashsets
///
/// Gets or sets a list of the tag entry's parent IDs for interaction with the database.
///
diff --git a/UI/ViewModels/HierarchyTreeViewModel.cs b/UI/ViewModels/HierarchyTreeViewModel.cs
index e33e6f9..2c01f57 100644
--- a/UI/ViewModels/HierarchyTreeViewModel.cs
+++ b/UI/ViewModels/HierarchyTreeViewModel.cs
@@ -10,17 +10,25 @@ namespace TagHierarchyManager.UI.ViewModels;
public partial class HierarchyTreeViewModel : ViewModelBase, IDisposable
{
+ private readonly Func, List> _getParentNamesById;
private readonly MainWindowViewModel _mainWindow;
- private readonly Dictionary _viewModelMap = new();
+
+ [ObservableProperty] private Dictionary> _childNodeMap = new();
[ObservableProperty] private TagItemViewModel? _selectedTag;
- [ObservableProperty] private ObservableCollection _topLevelTags = [];
+ [ObservableProperty] private ObservableCollection _topLevelTagNodes = [];
+
+ [ObservableProperty] private Dictionary> _viewModelMap = new();
public HierarchyTreeViewModel(MainWindowViewModel mainWindow)
{
this._mainWindow = mainWindow;
-
+ this._getParentNamesById = parentIds =>
+ parentIds.Select(id => this._mainWindow.Database?.Tags.FirstOrDefault(t => t.Id == id))
+ .Where(tag => tag is not null)
+ .Select(tag => tag!.Name)
+ .ToList();
this.SubscribeToEvents();
}
@@ -31,132 +39,225 @@ public partial class HierarchyTreeViewModel : ViewModelBase, IDisposable
this._mainWindow.Database.TagUpdated -= this.TagDatabase_OnTagUpdated;
this._mainWindow.Database.TagAdded -= this.TagDatabase_OnTagAdded;
this._mainWindow.Database.TagDeleted -= this.TagDatabase_OnTagDeleted;
-
- this._viewModelMap.Clear();
}
public async Task InitializeAsync()
{
- await this.SyncHierarchyAsync();
+ if (this._mainWindow.Database is null) return;
+ // await this.SyncHierarchyAsync();
+ this.ViewModelMap.Clear();
+ await Task.Run(() =>
+ {
+ var topLevelTags = this._mainWindow.Database?.Tags.Where(t => t.IsTopLevel).ToList();
+ var buildingTopLevelNodes = new List();
+ foreach (var tagNode in topLevelTags!.Select(tag => new TagItemViewModel(tag, this._getParentNamesById)))
+ {
+ buildingTopLevelNodes.Add(tagNode);
+ this.AddTagNodeToViewModelMap(tagNode);
+ this.AddAllChildrenAsync(tagNode);
+ }
+
+ this.TopLevelTagNodes = new ObservableCollection(buildingTopLevelNodes);
+ });
}
- private TagItemViewModel GetOrCreateViewModel(Tag tag, int parentId)
+ private void AddAllChildrenAsync(TagItemViewModel tag, bool beingUpdated = false)
{
- var key = $"{parentId}_{tag.Id}";
- if (!this._viewModelMap.TryGetValue(key, out var viewModel))
+ if (beingUpdated)
{
- viewModel = new TagItemViewModel(tag, id =>
- this._viewModelMap.Values.FirstOrDefault(v => v.Id == id)?.Name);
- this._viewModelMap[key] = viewModel;
- viewModel.UserEditedTag += this.OnUserEditedTag;
+ tag.Children.Clear();
+ if (this.ChildNodeMap.TryGetValue(tag.Id, out var existingParents))
+ existingParents.Clear();
}
- return viewModel;
+ var childTags =
+ this._mainWindow.Database?.Tags.Where(t => t.ParentIds.Contains(tag.Id)).OrderBy(t => t.Name).ToList();
+
+ if (childTags is null) return;
+ foreach (var childNode in childTags.Select(child =>
+ new TagItemViewModel(child, this._getParentNamesById)))
+ {
+ if (!this.ChildNodeMap.ContainsKey(childNode.Id))
+ this.ChildNodeMap.Add(childNode.Tag.Id, []);
+ this.ChildNodeMap[childNode.Tag.Id].Add(tag.Id);
+
+ this.AddTagNodeToViewModelMap(childNode, beingUpdated);
+
+ tag.Children.Add(childNode);
+ this.AddAllChildrenAsync(childNode);
+ }
}
-
- partial void OnSelectedTagChanged(TagItemViewModel? value)
+
+ private async Task AddChildNode(Tag tag, int parentId)
{
- this._mainWindow.SelectedTag = value;
+ if (!this.ViewModelMap.TryGetValue(parentId, out var parentViewModels)) return;
+
+ foreach (var parent in parentViewModels)
+ await Task.Run(() =>
+ {
+ var tagNode = new TagItemViewModel(tag, this._getParentNamesById);
+ this.AddAllChildrenAsync(tagNode);
+
+ var index = 0;
+ while (index < parent.Children.Count && string.Compare(parent.Children[index].Name, tagNode.Name,
+ StringComparison.CurrentCultureIgnoreCase) < 0) index++;
+
+ parent.Children.Insert(index, tagNode);
+ this.AddTagNodeToViewModelMap(tagNode);
+ });
+
+ if (!this.ChildNodeMap.TryGetValue(tag.Id, out var set))
+ this.ChildNodeMap.Add(tag.Id, [parentId]);
+ else
+ set.Add(parentId);
}
- private async Task OnTreeUpdate()
+ private void AddTagNodeToViewModelMap(TagItemViewModel tagNode, bool beingUpdated = false)
{
+ if (!this.ViewModelMap.TryGetValue(tagNode.Id, out var tagNodeSet))
+ {
+ this.ViewModelMap.Add(tagNode.Id, [tagNode]);
+ }
+ else
+ {
+ if (beingUpdated) tagNodeSet.Clear();
+ tagNodeSet.Add(tagNode);
+ }
+ }
+
+ private async Task AddTopLevelNode(Tag tag)
+ {
+ if (this.TopLevelTagNodes.Any(t => t.Id == tag.Id)) return;
await Task.Run(() =>
{
- foreach (var viewModel in this._viewModelMap.Values) viewModel.RefreshParentsString();
+ var newTopLevelTag = new TagItemViewModel(tag, this._getParentNamesById);
+ // this does create considerable delay, would be nice to speed it up somehow.
+ this.AddAllChildrenAsync(newTopLevelTag);
+ this.TopLevelTagNodes.Add(newTopLevelTag);
+ this.AddTagNodeToViewModelMap(newTopLevelTag);
});
- await this.SyncHierarchyAsync();
}
-
- private void OnUserEditedTag(object? sender, EventArgs e) => this._mainWindow.UnsavedChanges = true;
- private void SubscribeToEvents()
+ private async Task DeleteChildNode(int parentId, int idToDelete)
{
- if (this._mainWindow.Database is null) return;
- this._mainWindow.Database.TagUpdated += this.TagDatabase_OnTagUpdated;
- this._mainWindow.Database.TagAdded += this.TagDatabase_OnTagAdded;
- this._mainWindow.Database.TagDeleted += this.TagDatabase_OnTagDeleted;
+ if (!this.ViewModelMap.TryGetValue(parentId, out var parentViewModels)) return;
+
+ foreach (var parentTag in parentViewModels)
+ await Task.Run(() =>
+ {
+ var foundChild =
+ parentTag.Children.FirstOrDefault(t => t.Id == idToDelete)!;
+ parentTag.Children.Remove(foundChild);
+ });
+
+ if (!this.ChildNodeMap.TryGetValue(idToDelete, out var parentSet)) return;
+ parentSet.Remove(parentId);
}
- private void SyncCollection(ObservableCollection collection, List newItems)
+ private async Task DeleteTopLevelNode(int idToDelete)
{
- var updatedKeys = newItems.Select(v => v.Id).ToHashSet();
- for (var i = collection.Count - 1; i >= 0; i--)
- if (!updatedKeys.Contains(collection[i].Id))
- collection.RemoveAt(i);
-
- var currentKeys = collection.Select(v => v.Id).ToHashSet();
- foreach (var newItem in newItems)
- if (!currentKeys.Contains(newItem.Id))
- {
- // Find the correct index to maintain alphabetical order
- var index = 0;
- while (index < collection.Count && string.Compare(collection[index].Name, newItem.Name,
- StringComparison.CurrentCultureIgnoreCase) < 0) index++;
- collection.Insert(index, newItem);
- }
+ var topLevelNode = this.TopLevelTagNodes.FirstOrDefault(t => t.Id == idToDelete);
+ if (topLevelNode is null) return;
+ await Task.Run(() => { this.TopLevelTagNodes.Remove(topLevelNode); });
}
- private async Task SyncHierarchyAsync()
+ partial void OnSelectedTagChanged(TagItemViewModel? value)
{
- if (this._mainWindow.Database is null) return;
+ this._mainWindow.SelectedTag = value;
+ }
- var activeKeys = new HashSet();
+ private void SubscribeToEvents()
+ {
+ if (this._mainWindow.Database is null) return;
+ this._mainWindow.Database.TagUpdated += this.TagDatabase_OnTagUpdated;
+ this._mainWindow.Database.TagAdded += this.TagDatabase_OnTagAdded;
+ this._mainWindow.Database.TagDeleted += this.TagDatabase_OnTagDeleted;
+ }
- var result = await Task.Run(() =>
+ private async void TagDatabase_OnTagAdded(object? sender, Tag newTag)
+ {
+ try
{
- var children = this._mainWindow.Database.Tags
- .SelectMany(t => t.ParentIds.Select(pId => new { ParentId = pId, Child = t }))
- .ToLookup(x => x.ParentId, x => x.Child);
- var topLevelTags = this._mainWindow.Database.Tags.Where(t => t.IsTopLevel).OrderBy(t => t.Name)
- .ToList();
+ if (newTag.IsTopLevel)
+ await this.AddTopLevelNode(newTag);
- return (topLevelTags, children);
- });
+ if (newTag.ParentIds.Count == 0) return;
+ foreach (var parentId in newTag.ParentIds)
+ await this.AddChildNode(newTag, parentId);
+ }
+ catch (Exception e)
+ {
+ var error = new ErrorDialogViewModel(e.Message);
+ error.ShowDialog();
+ }
+ }
- var topLevelViewModels = result.topLevelTags.Select(t =>
+ private async void TagDatabase_OnTagDeleted(object? sender, (int id, string name) deletedTag)
+ {
+ try
{
- var vm = this.GetOrCreateViewModel(t, 0);
- activeKeys.Add($"0_{t.Id}");
- this.SyncTagRecursive(vm, result.children, activeKeys);
- return vm;
- }).ToList();
- this.SyncCollection(this.TopLevelTags, topLevelViewModels);
-
- var keysToRemove = this._viewModelMap.Keys.Where(k => !activeKeys.Contains(k)).ToList();
- foreach (var key in keysToRemove)
+ await this.WipeTagNodes(deletedTag.id);
+ }
+ catch (Exception e)
{
- this._viewModelMap[key].UserEditedTag -= this.OnUserEditedTag;
- this._viewModelMap.Remove(key);
+ var error = new ErrorDialogViewModel(e.Message);
+ error.ShowDialog();
}
}
- private void SyncTagRecursive(TagItemViewModel parentVm, ILookup childrenLookup,
- HashSet activeKeys)
+ private async void TagDatabase_OnTagUpdated(object? sender, Tag updatedTag)
{
- var childTags = childrenLookup[parentVm.Id].OrderBy(t => t.Name).ToList();
- var childVms = new List();
-
- foreach (var ct in childTags)
+ try
{
- var key = $"{parentVm.Id}_{ct.Id}";
- activeKeys.Add(key);
+ if (!this.ViewModelMap.TryGetValue(updatedTag.Id, out var tagViewModels)) return;
- var childVm = this.GetOrCreateViewModel(ct, parentVm.Id);
- childVms.Add(childVm);
+ HashSet oldParents = [];
+ HashSet newParents = new(updatedTag.ParentIds);
- this.SyncTagRecursive(childVm, childrenLookup, activeKeys);
- }
+ // grab old parents if they exist
+ if (this.ChildNodeMap.TryGetValue(updatedTag.Id, out var parentList))
+ oldParents = [..parentList];
- parentVm.SyncChildren(childVms);
- }
+ // add/remove parents as necessary
+ var removedParents = oldParents.Except(newParents);
+ var addedParents = newParents.Except(oldParents);
+
+ foreach (var parentId in removedParents)
+ await this.DeleteChildNode(parentId, updatedTag.Id);
+
+ foreach (var parentId in addedParents)
+ await this.AddChildNode(updatedTag, parentId);
- private void TagDatabase_OnTagAdded(object? sender, Tag tag) =>
- _ = Task.Run(async () => await this.OnTreeUpdate());
+ // refresh all tagViewModels
+ foreach (var tag in tagViewModels)
+ tag.RefreshSelf();
- private void TagDatabase_OnTagDeleted(object? sender, (int id, string name) tag) =>
- _ = Task.Run(async () => await this.OnTreeUpdate());
+ // add/remove top level nodes as necessary
+ if (updatedTag.IsTopLevel)
+ await this.AddTopLevelNode(updatedTag);
+ else
+ await this.DeleteTopLevelNode(updatedTag.Id);
- private void TagDatabase_OnTagUpdated(object? sender, Tag tag) =>
- _ = Task.Run(async () => await this.OnTreeUpdate());
+ // clear child node map if tag has no parents
+ if (newParents.Count == 0)
+ this.ChildNodeMap.Remove(updatedTag.Id);
+ }
+ catch (Exception e)
+ {
+ var error = new ErrorDialogViewModel(e.Message);
+ error.ShowDialog();
+ }
+ }
+
+ private async Task WipeTagNodes(int idToDelete)
+ {
+ if (this.ChildNodeMap.TryGetValue(idToDelete, out var parentList))
+ {
+ foreach (var parentId in parentList) await this.DeleteChildNode(parentId, idToDelete);
+ this.ChildNodeMap.Remove(idToDelete);
+ this.ViewModelMap.Remove(idToDelete);
+ }
+
+ await this.DeleteTopLevelNode(idToDelete);
+ }
}
\ No newline at end of file
diff --git a/UI/ViewModels/MainWindowViewModel.cs b/UI/ViewModels/MainWindowViewModel.cs
index 8cb96ed..fad9f5e 100644
--- a/UI/ViewModels/MainWindowViewModel.cs
+++ b/UI/ViewModels/MainWindowViewModel.cs
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
@@ -35,8 +34,6 @@ public partial class MainWindowViewModel : ViewModelBase
[ObservableProperty] private string _statusBlockText = Resources.StatusBlockReady;
- [ObservableProperty] private ObservableCollection _topLevelTags = [];
-
[ObservableProperty] private bool _unsavedChanges;
public int TotalTags => this.Database?.Tags.Count ?? 0;
@@ -59,11 +56,13 @@ public partial class MainWindowViewModel : ViewModelBase
}
else
{
+ this._selectedTag?.UserEditedTag -= this.OnUserEditedTag;
this._selectedTag = value;
this.HierarchyTreeViewModel?.SelectedTag = value;
this._selectedTag?.BeginEdit();
this.OnPropertyChanged();
this.UnsavedChanges = false;
+ this._selectedTag?.UserEditedTag += this.OnUserEditedTag;
}
}
}
@@ -144,7 +143,7 @@ public partial class MainWindowViewModel : ViewModelBase
public async Task SaveSelectedTagAsync()
{
if (this.SelectedTag is null || this.Database is null) return;
-
+
this.SelectedTag.CommitEdit();
await this.Database.WriteTagToDatabase(this.SelectedTag.Tag);
this.SelectedTag.RefreshParentsString();
@@ -246,9 +245,11 @@ public partial class MainWindowViewModel : ViewModelBase
if (result == true)
await this.SaveSelectedTagAsync();
+
this._selectedTag = newTag;
this.HierarchyTreeViewModel?.SelectedTag = newTag;
this._selectedTag?.BeginEdit();
+ this._selectedTag?.UserEditedTag += this.OnUserEditedTag;
this.OnPropertyChanged(nameof(this.SelectedTag));
this.UnsavedChanges = false;
}
@@ -258,6 +259,11 @@ public partial class MainWindowViewModel : ViewModelBase
}
}
+ private void OnUserEditedTag(object? sender, EventArgs e)
+ {
+ this.UnsavedChanges = true;
+ }
+
private Importer PickImporterFromFileExt(string path)
{
var fileExt = Path.GetExtension(path);
@@ -270,6 +276,12 @@ public partial class MainWindowViewModel : ViewModelBase
throw new NotSupportedException(string.Format(Resources.ErrorImportFileTypeNotSupported, fileExt));
}
+ private void ShowErrorDialog(string message)
+ {
+ var error = new ErrorDialogViewModel(message);
+ error.ShowDialog();
+ }
+
private void TagDatabase_OnInitalisationComplete(object? sender, EventArgs e)
{
if (sender is not TagDatabase db) return;
@@ -288,7 +300,7 @@ public partial class MainWindowViewModel : ViewModelBase
this.Database = db;
this.SelectedTag = null;
- this.IsDbEnabled = true;
+
this.HierarchyTreeViewModel = new HierarchyTreeViewModel(this);
this.SearchViewModel = new SearchViewModel(this);
this.Database.TagAdded += this.TagDatabase_TagAdded;
@@ -296,6 +308,7 @@ public partial class MainWindowViewModel : ViewModelBase
await this.HierarchyTreeViewModel.InitializeAsync();
this.OnPropertyChanged(nameof(this.TotalTags));
this.OnPropertyChanged(nameof(this.WindowTitle));
+ this.IsDbEnabled = true;
this.Database.InitialisationComplete -= this.TagDatabase_OnInitalisationComplete;
this.UnsavedChanges = false;
@@ -309,12 +322,6 @@ public partial class MainWindowViewModel : ViewModelBase
});
Debug.WriteLine($"Database loaded on UI - name: {db.Name}, version: {db.Version}");
}
-
- private void ShowErrorDialog(string message)
- {
- var error = new ErrorDialogViewModel(message);
- error.ShowDialog();
- }
private void TagDatabase_TagAdded(object? sender, Tag _)
{
@@ -330,10 +337,11 @@ public partial class MainWindowViewModel : ViewModelBase
private void UninitialiseDatabase()
{
if (this.Database == null) return;
+ this.SelectedTag = null;
+ this.IsDbEnabled = false;
this.Database.TagAdded -= this.TagDatabase_TagAdded;
this.Database.TagDeleted -= this.TagDatabase_TagDeleted;
this.Database = null;
- this.IsDbEnabled = false;
this.HierarchyTreeViewModel = null;
this.SearchViewModel = null;
this.OnPropertyChanged(nameof(this.TotalTags));
diff --git a/UI/ViewModels/SearchViewModel.cs b/UI/ViewModels/SearchViewModel.cs
index e884cda..b8bfcbd 100644
--- a/UI/ViewModels/SearchViewModel.cs
+++ b/UI/ViewModels/SearchViewModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
@@ -9,6 +10,7 @@ namespace TagHierarchyManager.UI.ViewModels;
public partial class SearchViewModel : ViewModelBase, IDisposable
{
+ private readonly Func, List> _getParentNamesById;
private readonly MainWindowViewModel _mainWindow;
[ObservableProperty] private ObservableCollection _searchResults = [];
@@ -18,10 +20,18 @@ public partial class SearchViewModel : ViewModelBase, IDisposable
public SearchViewModel(MainWindowViewModel mainWindow)
{
this._mainWindow = mainWindow;
+ this._getParentNamesById = parents =>
+ parents.Select(id => this._mainWindow.Database?.Tags.FirstOrDefault(t => t.Id == id))
+ .Where(tag => tag is not null)
+ .Select(tag => tag!.Name)
+ .ToList();
mainWindow.Database?.TagDeleted += this.TagDatabase_OnTagDeleted;
}
- public void Dispose() => this._mainWindow.Database?.TagDeleted -= this.TagDatabase_OnTagDeleted;
+ public void Dispose()
+ {
+ this._mainWindow.Database?.TagDeleted -= this.TagDatabase_OnTagDeleted;
+ }
public void Search(string searchQuery, TagDatabaseSearchMode mode, bool searchAliases)
{
@@ -39,7 +49,7 @@ public partial class SearchViewModel : ViewModelBase, IDisposable
}
results.Select(tag =>
- new TagItemViewModel(tag, id => this._mainWindow.Database.Tags.FirstOrDefault(t => t.Id == id)?.Name))
+ new TagItemViewModel(tag, this._getParentNamesById))
.OrderBy(tag => tag.Name)
.ToList()
.ForEach(this.SearchResults.Add);
diff --git a/UI/ViewModels/TagItemViewModel.cs b/UI/ViewModels/TagItemViewModel.cs
index 1a4cfa7..818c603 100644
--- a/UI/ViewModels/TagItemViewModel.cs
+++ b/UI/ViewModels/TagItemViewModel.cs
@@ -9,7 +9,8 @@ using TagHierarchyManager.UI.Assets;
namespace TagHierarchyManager.UI.ViewModels;
-public partial class TagItemViewModel(Tag tag, Func? getNameById = null) : ViewModelBase
+public partial class TagItemViewModel(Tag tag, Func, List>? getParentNamesByIds = null)
+ : ViewModelBase
{
[ObservableProperty] private string _editingAliases = string.Empty;
@@ -32,8 +33,7 @@ public partial class TagItemViewModel(Tag tag, Func? getNameById =
? string.Join("; ", this.Tag.Aliases)
: string.Empty;
-
- public ObservableCollection Children { get; } = [];
+ public bool HasChildren => this.Children.Count > 0;
public int Id => this.Tag.Id;
@@ -42,30 +42,30 @@ public partial class TagItemViewModel(Tag tag, Func? getNameById =
public string Notes => this.Tag.Notes;
public bool OnDatabase => this.Id != 0;
-
- public bool HasChildren => this.Children.Count > 0;
public string TagBindings =>
this.Tag.TagBindings.Count > 0
? string.Join("; ", this.Tag.TagBindings)
: string.Empty;
+ public ObservableCollection Children { get; set; } = [];
+
internal Tag Tag { get; } = tag;
private bool IsTopLevel => this.Tag.IsTopLevel;
- private string Parents => getNameById != null && this.Tag.ParentIds is { Count: > 0 }
- ? string.Join("; ", this.Tag.ParentIds.Select(getNameById).Where(n => n != null))
+ private string Parents => getParentNamesByIds is not null && this.Tag.ParentIds is { Count: > 0 }
+ ? string.Join("; ", getParentNamesByIds(this.Tag.ParentIds))
: string.Empty;
public void BeginEdit()
{
this._isInitialising = true;
this.EditingName = this.Tag.Name;
-
+
if (this.OnDatabase || string.IsNullOrEmpty(this.EditingParents))
this.EditingParents = this.Parents;
-
+
this.EditingIsTopLevel = this.IsTopLevel;
this.EditingTagBindings = this.TagBindings;
this.EditingAliases = this.Aliases;
@@ -113,29 +113,19 @@ public partial class TagItemViewModel(Tag tag, Func? getNameById =
this.EditingParents = newParents;
this.OnPropertyChanged(nameof(this.EditingParents));
}
+
this._isInitialising = false;
}
-
- public void SyncChildren(List children)
+ public void RefreshSelf()
{
- var newChildren = children.Select(c => c.Id).ToHashSet();
-
- for (var i = this.Children.Count - 1; i >= 0; i--)
- if (!newChildren.Contains(this.Children[i].Id))
- this.Children.RemoveAt(i);
-
- var currentIds = this.Children.Select(c => c.Id).ToHashSet();
- foreach (var child in children)
- if (!currentIds.Contains(child.Id))
- {
- // Find the correct index to maintain alphabetical order
- var index = 0;
- while (index < this.Children.Count && string.Compare(this.Children[index].Name, child.Name,
- StringComparison.CurrentCultureIgnoreCase) < 0) index++;
-
- this.Children.Insert(index, child);
- }
+ this.OnPropertyChanged(nameof(this.Name));
+ this.OnPropertyChanged(nameof(this.Parents));
+ this.OnPropertyChanged(nameof(this.Aliases));
+ this.OnPropertyChanged(nameof(this.TagBindings));
+ this.OnPropertyChanged(nameof(this.Notes));
+ this.OnPropertyChanged(nameof(this.IsTopLevel));
+ this.OnPropertyChanged(nameof(this.HasChildren));
}
public void SyncId()
diff --git a/UI/Views/MainWindow.axaml b/UI/Views/MainWindow.axaml
index 5e4341f..c127e06 100644
--- a/UI/Views/MainWindow.axaml
+++ b/UI/Views/MainWindow.axaml
@@ -37,22 +37,22 @@
+ RowDefinitions="*"
+ Margin="10 0"
+ IsEnabled="{Binding IsDbEnabled}">
-
-
-
+
+
+
-
+
@@ -72,7 +72,7 @@
+ Click="ButtonAdd_Click" Theme="{StaticResource SolidButton}" />
@@ -116,13 +116,16 @@
-
-
-
+ Name="TopLevelCheckBox" Content="{x:Static assets:Resources.CheckBoxTopLevel}"
+ VerticalAlignment="Center" />
diff --git a/UI/Views/MainWindow.axaml.cs b/UI/Views/MainWindow.axaml.cs
index ec31eb1..628feb6 100644
--- a/UI/Views/MainWindow.axaml.cs
+++ b/UI/Views/MainWindow.axaml.cs
@@ -42,7 +42,7 @@ public partial class MainWindow : Window
error.ShowDialog();
}
}
-
+
public async void ButtonSave_Click(object? sender, RoutedEventArgs e)
{
try
@@ -72,7 +72,6 @@ public partial class MainWindow : Window
var error = new ErrorDialogViewModel(ex.Message);
error.ShowDialog();
}
-
}
public void MenuItemDatabaseSettings_Click(object? sender, RoutedEventArgs e)