Browse Source

Add dock view state save/load from vm

pull/165/head
Ionite 1 year ago
parent
commit
66ca2f8ffe
No known key found for this signature in database
  1. 48
      StabilityMatrix.Avalonia/Controls/Dock/DockUserControlBase.cs
  2. 11
      StabilityMatrix.Avalonia/Models/Inference/LoadViewStateEventArgs.cs
  3. 12
      StabilityMatrix.Avalonia/Models/Inference/SaveViewStateEventArgs.cs
  4. 13
      StabilityMatrix.Avalonia/Models/Inference/ViewState.cs
  5. 68
      StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs
  6. 8
      StabilityMatrix.Avalonia/Views/InferencePage.axaml

48
StabilityMatrix.Avalonia/Controls/Dock/DockUserControlBase.cs

@ -1,4 +1,8 @@
using System;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Threading;
@ -6,6 +10,8 @@ using Dock.Avalonia.Controls;
using Dock.Model;
using Dock.Model.Avalonia.Json;
using Dock.Model.Core;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.ViewModels.Base;
namespace StabilityMatrix.Avalonia.Controls.Dock;
@ -34,7 +40,43 @@ public abstract class DockUserControlBase : DropTargetUserControlBase
}
}
protected virtual void LoadDockLayout(string data)
/// <inheritdoc />
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
// Attach handlers for view state saving and loading
if (DataContext is InferenceTabViewModelBase vm)
{
vm.SaveViewStateRequested += (_, args) =>
{
var saveTcs = new TaskCompletionSource<ViewState>();
Dispatcher.UIThread.Post(() =>
{
var state = new ViewState { DockLayout = SaveDockLayout() };
saveTcs.SetResult(state);
});
args.StateTask ??= saveTcs.Task;
};
vm.LoadViewStateRequested += (_, args) =>
{
if (args.State.DockLayout is { } layout)
{
LoadDockLayout(layout);
}
};
}
}
protected void LoadDockLayout(JsonObject data)
{
LoadDockLayout(data.ToJsonString());
}
protected void LoadDockLayout(string data)
{
if (BaseDock is null)
return;
@ -46,8 +88,8 @@ public abstract class DockUserControlBase : DropTargetUserControlBase
}
}
protected virtual string SaveDockLayout()
protected string? SaveDockLayout()
{
return BaseDock is null ? string.Empty : DockSerializer.Serialize(BaseDock.Layout);
return BaseDock is null ? null : DockSerializer.Serialize(BaseDock.Layout);
}
}

11
StabilityMatrix.Avalonia/Models/Inference/LoadViewStateEventArgs.cs

@ -0,0 +1,11 @@
using System;
namespace StabilityMatrix.Avalonia.Models.Inference;
/// <summary>
/// Event for view models requesting to load their view state from a provided state
/// </summary>
public class LoadViewStateEventArgs : EventArgs
{
public required ViewState State { get; init; }
}

12
StabilityMatrix.Avalonia/Models/Inference/SaveViewStateEventArgs.cs

@ -0,0 +1,12 @@
using System;
using System.Threading.Tasks;
namespace StabilityMatrix.Avalonia.Models.Inference;
/// <summary>
/// Event for view models requesting to get their view state for saving
/// </summary>
public class SaveViewStateEventArgs : EventArgs
{
public Task<ViewState>? StateTask { get; set; }
}

13
StabilityMatrix.Avalonia/Models/Inference/ViewState.cs

@ -0,0 +1,13 @@
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace StabilityMatrix.Avalonia.Models.Inference;
/// <summary>
/// Model for view states of inference tabs
/// </summary>
[JsonSerializable(typeof(ViewState))]
public class ViewState
{
public string? DockLayout { get; set; }
}

68
StabilityMatrix.Avalonia/ViewModels/Base/InferenceTabViewModelBase.cs

@ -2,11 +2,15 @@
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using StabilityMatrix.Avalonia.Models;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.FileInterfaces;
@ -44,6 +48,70 @@ public abstract partial class InferenceTabViewModelBase
/// <inheritdoc />
Control? IPersistentViewProvider.AttachedPersistentView { get; set; }
#region Weak Events
private WeakEventManager<LoadViewStateEventArgs>? loadViewStateRequestedEventManager;
public event EventHandler<LoadViewStateEventArgs> LoadViewStateRequested
{
add
{
loadViewStateRequestedEventManager ??= new WeakEventManager<LoadViewStateEventArgs>();
loadViewStateRequestedEventManager.AddEventHandler(value);
}
remove => loadViewStateRequestedEventManager?.RemoveEventHandler(value);
}
protected void LoadViewState(LoadViewStateEventArgs args) =>
loadViewStateRequestedEventManager?.RaiseEvent(this, args, nameof(LoadViewStateRequested));
private WeakEventManager<SaveViewStateEventArgs>? saveViewStateRequestedEventManager;
public event EventHandler<SaveViewStateEventArgs> SaveViewStateRequested
{
add
{
saveViewStateRequestedEventManager ??= new WeakEventManager<SaveViewStateEventArgs>();
saveViewStateRequestedEventManager.AddEventHandler(value);
}
remove => saveViewStateRequestedEventManager?.RemoveEventHandler(value);
}
protected async Task<ViewState> SaveViewState()
{
var eventArgs = new SaveViewStateEventArgs();
saveViewStateRequestedEventManager?.RaiseEvent(
this,
eventArgs,
nameof(SaveViewStateRequested)
);
if (eventArgs.StateTask is not { } stateTask)
{
throw new InvalidOperationException(
"SaveViewStateRequested event handler did not set the StateTask property"
);
}
return await stateTask;
}
#endregion
[RelayCommand]
private async Task DebugSaveViewState()
{
var state = await SaveViewState();
if (state.DockLayout is { } layout)
{
await DialogHelper.CreateJsonDialog(layout).ShowAsync();
}
else
{
await DialogHelper.CreateTaskDialog("Failed", "No layout data").ShowAsync();
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)

8
StabilityMatrix.Avalonia/Views/InferencePage.axaml

@ -212,6 +212,14 @@
Command="{Binding MenuSaveAsCommand}"
InputGesture="Ctrl+Shift+S"
Text="Save As..." />
<!-- Debug mode menus -->
<ui:MenuFlyoutSeparator IsVisible="{Binding SharedState.IsDebugMode}" />
<ui:MenuFlyoutItem
Command="{Binding SelectedTab.DebugSaveViewStateCommand}"
Text="Show Dock State" />
</ui:FAMenuFlyout>
</Button.Flyout>
</Button>

Loading…
Cancel
Save