Compare commits

..

22 Commits

Author SHA1 Message Date
Matthias Heil 36160f709c Deleted MicroSoft_IEnumerableVisualizer/IEnumerableViewModel.cs
Deleted    MicroSoft_IEnumerableVisualizer/IEnumerableVisualizer.cs
Deleted    MicroSoft_IEnumerableVisualizer/IEnumerableVisualizerControl.cs
Deleted    MicroSoft_IEnumerableVisualizer/IEnumerableVisualizerProvider.cs
Deleted    MicroSoft_IEnumerableVisualizer/IEnumerableVisualizerSource.cs
Deleted    MicroSoft_IEnumerableVisualizer/LatestDataAvailable.cs
2026-04-15 16:06:12 +02:00
Matthias Heil 5c9dded0a4 Deleted obsolete files 2026-04-15 16:03:09 +02:00
Matthias Heil 001b945ea1 NrxDebugVisualizer shows objects.
TODO: Update SceneTreeView after adding new objects
2026-04-15 15:59:42 +02:00
Matthias Heil 4549022153 Added Settings and ShowLogViewer option 2026-04-15 13:45:42 +02:00
Matthias Heil d3b5b624b5 Added necessary projects for DebugVisualizer 2026-04-15 10:09:49 +02:00
Matthias Heil ebe055ddfe Merge branch 'main' of https://hetzner.8837053.ch/matt/DebugVisualizerExtension 2026-04-15 09:06:47 +02:00
Matthias Heil 0a24d616b0 Rename MicroSoft_IEnumerableVisualizer(from IEnumerableVisualizer)
Modified   .gitignore
Modified   NrxDebugVisualizer/Program.cs
Modified   NrxDebugVisualizer/Views/MainWindow.axaml
2026-04-15 09:06:03 +02:00
Matthias Heil 40c72fc868 Updated avalonia packages 2026-04-14 15:26:54 +02:00
Matthias Heil 5ab615ffe2 nuget update 2026-04-10 16:59:24 +02:00
Matthias Heil 30aa75dc8d Added NrxDebugVisualizer, not working 2026-04-08 16:06:35 +02:00
Matthias Heil 0f145eaebd Rename NrxDebuggerVisualizerProvider/NrxDebugVisualizerProvider.csproj (from NrxDebuggerVisualizerProvider/NrxDebugVisualizer.csproj)
Modified   DebugVisualizerExtension.slnx
2026-04-08 14:26:29 +02:00
Matthias Heil b56974ec06 Copy TestServer to Visual Studio 2026 2026-04-08 14:24:40 +02:00
Matthias Heil 49e94b9b45 use own PipeSerializer
SendToVisualizerAsync uses await
2026-04-08 08:20:33 +02:00
Matthias Heil 96bb165f68 Deleted .idea 2026-04-08 08:00:13 +02:00
Matthias Heil 6f7a3a5e31 Works with NetJsonPipeSerializer 2026-04-07 13:38:08 +02:00
Matthias Heil 7b4bbd28a1 Not working 2026-04-07 12:21:37 +02:00
Matthias Heil 8038c76307 Enhanced VisualizerModel and Vector3VisualizerTest 2026-04-07 11:16:24 +02:00
Matthias Heil 26864a695f Rename DebugVisualizerExtension.slnx (from VisualizerExtensionExample.slnx) 2026-04-07 09:43:21 +02:00
Matthias Heil 38c916b86b Works for IEnumerable 2026-04-02 15:20:12 +02:00
Matthias Heil 0276f0a34c Added more IEnumerableVisualizer files 2026-04-02 11:05:33 +02:00
Matthias Heil 48e2f108a8 Renamed 2026-04-02 10:09:10 +02:00
Matthias Heil 4623740937 Supports System.Collections.Generic.IEnumerableSystem.Collections.Generic.IEnumerable 2026-04-02 09:32:48 +02:00
46 changed files with 792 additions and 365 deletions
+3
View File
@@ -33,6 +33,9 @@ bld/
[Ll]og/
[Ll]ogs/
# Jetbrains Rider
.idea/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
-15
View File
@@ -1,15 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/modules.xml
/contentModel.xml
/.idea.VisualizerExtensionExample.iml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>
+33
View File
@@ -0,0 +1,33 @@
<Solution>
<Folder Name="/Avalonia/">
<Project Path="../Num.Roto.Visualization/Avalonia/Avalonia.PropertyGrid/Avalonia.PropertyGrid.csproj" />
<Project Path="../Num.Roto.Visualization/Avalonia/Controls/Controls.csproj" />
<Project Path="../Num.Roto.Visualization/Avalonia/LogViewer/LogViewer.csproj" />
<Project Path="../Num.Roto.Visualization/Tests/Avalonia/TestAvaloniaProportionalDock/TestAvaloniaProportionalDock.csproj" />
</Folder>
<Folder Name="/NamedPipes/">
<Project Path="NamedPipes/NamedPipes.csproj" Id="8d7b1151-8b57-4411-a361-47ed9c504a22" />
</Folder>
<Folder Name="/Num.Roto/">
<Project Path="../Num.Roto.Visualization/Base/Num.Roto.Visualization.Base.csproj" />
<Project Path="../Num.Roto.Visualization/Math/Num.Roto.Visualization.Math.csproj" />
<Project Path="../Num.Roto.Visualization/Models/Num.Roto.Visualization.Models/Num.Roto.Visualization.Models.csproj" />
<Project Path="../Num.Roto.Visualization/SceneGraph/Num.Roto.Visualization.SceneGraph.csproj" />
<Project Path="../Num.Roto.Visualization/Types/Num.Roto.Visualization.Types.csproj" />
<Project Path="../Num.Roto.Visualization/Vulkan/VulkanLib/Num.Roto.Visualization.VulkanLib.csproj" />
</Folder>
<Folder Name="/Test/">
<Project Path="TestClient/TestClient.csproj" />
<Project Path="TestServer/TestServer.csproj" Id="c81154ef-d854-4f1e-9d14-2cf674885291" />
<Project Path="Vector3VisualizerTest/Vector3VisualizerTest.csproj" />
</Folder>
<Folder Name="/Visualizer/">
<Project Path="NrxDebuggerVisualizerProvider/NrxDebugVisualizerProvider.csproj">
<Deploy />
</Project>
<Project Path="NrxDebugVisualizer/NrxDebugVisualizer.csproj" Id="807bb178-0fd6-4ae8-8c48-1088fa8a01fd">
<Deploy />
</Project>
<Project Path="NrxVisualizerObjectSource/NrxVisualizerObjectSource.csproj" />
</Folder>
</Solution>
@@ -1,2 +0,0 @@
[InternetShortcut]
URL=https://blog.elmah.io/creating-custom-debug-visualizers-for-visual-studio-2022/
+2 -16
View File
@@ -1,22 +1,8 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace NamedPipes;
[Serializable]
public struct Frame(Vector3 translation, Quaternion orientation)
{
public Vector3 Translation => translation;
public Quaternion Orientation => orientation;
}
[Serializable]
public class DebugObject
{
public string? Type { get; set; }
public byte[]? Data { get; set; }
}
public interface IDebugVisualizer
{
Task<bool> SetDebugObjectAsync(DebugObject debugObject);
Task<bool> SetVisualizerModelAsync(VisualizerModel visualizerModel);
Task<bool> SetMessageAsync(string message);
}
+6 -6
View File
@@ -1,8 +1,8 @@
using System;
using PipeMethodCalls;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using PipeMethodCalls;
namespace NamedPipes;
@@ -30,7 +30,7 @@ public class NamedPipeClient (string pipeName,string? serverLocation = null, st
try
{
await PipeClient.ConnectAsync().ConfigureAwait(true);
Logger("NamedPipeClient.StartServerAsync succeded.");
Logger("NamedPipeClient.StartServerAsync succeeded.");
return;
}
catch(Exception e)
@@ -40,11 +40,11 @@ public class NamedPipeClient (string pipeName,string? serverLocation = null, st
}
}
public async Task<bool> SetDebugObjectAsync(DebugObject debugObject)
public async Task<bool> SetVisualizerModelAsync(VisualizerModel visualizerModel)
{
await StartServerAsync().ConfigureAwait(true);
var result = await PipeClient.InvokeAsync(server => server.SetDebugObjectAsync(debugObject));
Logger("NamedPipeClient.SetDebugObjectAsync: result = " + result);
var result = await PipeClient.InvokeAsync(server => server.SetVisualizerModelAsync(visualizerModel));
Logger("NamedPipeClient.SetVisualizerModelAsync: result = " + result);
return result;
}
+13 -11
View File
@@ -1,9 +1,11 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;
using PipeMethodCalls;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace NamedPipes;
public partial class NamedPipesServer(string pipeName,Action<string>? logger = null) : ObservableObject,IDebugVisualizer, IDisposable
{
@@ -29,27 +31,27 @@ public partial class NamedPipesServer(string pipeName,Action<string>? logger = n
Logger("Waiting for client connection...");
await PipeServer.WaitForConnectionAsync().ConfigureAwait(true);
}
public async Task RunAsync()
public async Task RunAsync(CancellationToken cancellationToken)
{
while(true)
while(!cancellationToken.IsCancellationRequested)
{
await WaitForConnectionAsync().ConfigureAwait(true);
Logger("Client connected.");
while (IsConnected)
{
await Task.Delay(100).ConfigureAwait(true);
await Task.Delay(100, cancellationToken).ConfigureAwait(true);
}
Logger("Client disconnected.");
}
}
[ObservableProperty]
public partial DebugObject? DebugObject { get; private set; }
public partial VisualizerModel? VisualizerModel { get; private set; }
public async Task<bool> SetDebugObjectAsync(DebugObject debugObject)
public async Task<bool> SetVisualizerModelAsync(VisualizerModel visualizerModel)
{
await Task.Delay(1);
DebugObject = debugObject;
Logger("Received DebugObject of type: " + DebugObject.Type);
VisualizerModel = visualizerModel;
Logger("NamedPipesServer, received object of type: " + visualizerModel.GetType());
return true;
}
+3 -3
View File
@@ -7,10 +7,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.6" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
<PackageReference Include="PipeMethodCalls" Version="4.0.3" />
<PackageReference Include="System.Numerics.Vectors" Version="4.6.1" />
<PackageReference Include="System.Text.Json" Version="10.0.6" />
</ItemGroup>
</Project>
+27 -31
View File
@@ -1,38 +1,34 @@
using System;
using MessagePack;
using PipeMethodCalls;
using PipeMethodCalls;
using System;
using System.IO;
using System.Text.Json;
namespace NamedPipes
namespace NamedPipes;
/// <summary>
/// Serializes pipe method call information with System.Text.Json.
/// </summary>
public class PipeSerializer : IPipeSerializer
{
public class PipeSerializer : IPipeSerializer
private JsonSerializerOptions options = new()
{
public object? Deserialize(byte[] data, Type type)
{
if (data.Length == 0) return null;
//Log.Trace("PipeSerializer.Deserialize: type = " + type + " , data.length = " + data.Length);
var obj = MessagePackSerializer.Deserialize(type, data, MessagePack.Resolvers.ContractlessStandardResolver.Options);
//if (obj is DebugObject debugObject)
//{
// var length = debugObject.Data?.Length ?? 0;
// var debugObjectType = debugObject.Type ?? "null";
// Log.Trace("PipeSerializer.Deserialize: debugObject.Type = " + debugObjectType + " , debugObject.Data.Length = " + length);
//}
return obj;
}
IncludeFields = true
};
public byte[] Serialize(object o)
{
if (o.GetType().FullName == "System.Threading.Tasks.VoidTaskResult") return [];
//if (o is DebugObject debugObject)
//{
// var length = debugObject.Data?.Length ?? 0;
// Log.Trace("PipeSerializer.Deserialize: debugObject.Type = " + debugObject.Type + " , debugObject.Data.Length = " + length);
//}
public object Deserialize(byte[] data, Type type)
{
var bytearray = MessagePackSerializer.Serialize(o.GetType(), o, MessagePack.Resolvers.ContractlessStandardResolver.Options);
//var xxx = Deserialize(bytearray, o.GetType());
//Log.Trace("PipeSerializer.Serialize: type = " + o.GetType() + " , bytearray.length = " + bytearray.Length);
return bytearray;
}
var obj = JsonSerializer.Deserialize(data, type, options) ?? throw new InvalidDataException($"Can not deserialize to type: {type} ");
return obj;
}
public byte[] Serialize(object o)
{
using var memoryStream = new MemoryStream();
using var utf8JsonWriter = new Utf8JsonWriter(memoryStream);
JsonSerializer.Serialize(utf8JsonWriter, o, options);
var data = memoryStream.ToArray();
return data;
}
}
+31
View File
@@ -0,0 +1,31 @@
using System;
using System.Numerics;
using System.Runtime.Serialization;
using Frame = System.ValueTuple<System.Numerics.Vector3, System.Numerics.Quaternion, float>;
namespace NamedPipes;
[DataContract]
[Serializable]
public class VisualizerModel
{
public static Type FrameType => typeof(Frame);
[DataMember]
public string? Content { get; set; }
[DataMember]
public Vector3? Point { get; set; }
[DataMember]
public Quaternion? Orientation { get; set; }
[DataMember]
public Vector3[]? PointArray { get; set; }
[DataMember]
public Frame? Frame { get; set; }
[DataMember]
public Frame[]? FrameArray { get; set; }
}
+11
View File
@@ -0,0 +1,11 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="NrxDebugVisualizer.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<SimpleTheme />
<DockSimpleTheme />
</Application.Styles>
</Application>
+34
View File
@@ -0,0 +1,34 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Controls.Utilities;
using NrxDebugVisualizer.ViewModels;
using NrxDebugVisualizer.Views;
namespace NrxDebugVisualizer;
public partial class App : Application
{
public static Settings? Settings { get; set; }
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
#if DEBUG
this.AttachDeveloperTools();
#endif
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel(),
};
Settings = Settings.Load(desktop.MainWindow);
}
base.OnFrameworkInitializationCompleted();
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

+43
View File
@@ -0,0 +1,43 @@
using NamedPipes;
using NrxDebugVisualizer.Scenes;
using Num.Roto.Visualization.Math.Geometry;
using Num.Roto.Visualization.Math.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
namespace NrxDebugVisualizer.Models;
internal sealed class PipeServer
{
private string PipeName { get; }
private NamedPipesServer? NamedPipesServer { get; set; }
private Action<VisualizerModel> UpdateAction { get; init; }
public PipeServer(string pipeName, Action<VisualizerModel> updateAction,CancellationToken cancellationToken)
{
PipeName = pipeName;
UpdateAction = updateAction;
StartPipeServer(cancellationToken);
}
private void NamedPipesServer_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(NamedPipesServer.VisualizerModel)) return;
var visualizerObject = NamedPipesServer?.VisualizerModel;
if (visualizerObject is null) return;
UpdateAction(visualizerObject);
}
#region NamedPipesServer
private async void StartPipeServer(CancellationToken cancellationToken)
{
NamedPipesServer = new NamedPipesServer(PipeName, logger: (s) => Log.Info(s,0));
NamedPipesServer.PropertyChanged += NamedPipesServer_PropertyChanged;
await NamedPipesServer.RunAsync(cancellationToken).ConfigureAwait(false);
}
#endregion
}
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="12.0.1" />
<PackageReference Include="Avalonia.Desktop" Version="12.0.1" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="12.0.1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.14">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Num.Roto.Visualization\Avalonia\Controls\Controls.csproj" />
<ProjectReference Include="..\..\Num.Roto.Visualization\Math\Num.Roto.Visualization.Math.csproj" />
<ProjectReference Include="..\..\Num.Roto.Visualization\SceneGraph\Num.Roto.Visualization.SceneGraph.csproj" />
<ProjectReference Include="..\NamedPipes\NamedPipes.csproj" />
</ItemGroup>
</Project>
+21
View File
@@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace NrxDebugVisualizer;
internal static class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
private static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
@@ -0,0 +1,89 @@
using Num.Roto.Visualization.Math.Geometry;
using Num.Roto.Visualization.SceneGraph.Geometry;
using Num.Roto.Visualization.SceneGraph.Material;
using Num.Roto.Visualization.SceneGraph.Scene;
using Num.Roto.Visualization.SceneGraph.Scene.Nodes;
using Num.Roto.Visualization.Types;
using System.Numerics;
namespace NrxDebugVisualizer.Scenes;
internal sealed class DebugVisualizerScene : Num.Roto.Visualization.SceneGraph.Scenes.SceneBase
{
private static uint Counter;
private static uint Uid => Counter++;
private SceneNode Points { get; }
private SceneNode Frames { get; }
internal DebugVisualizerScene() : base("NrxDebuggerVisualizerScene")
{
Points = new SceneNode(nameof(Points), Objects);
Frames = new SceneNode(nameof(Frames), Objects);
}
public void AddPointGeometry(Vector3 position, float pointSize)
{
var point = new Points([position], "Point");
_ = new SceneGeometry("Point" + $".{Uid}", point, new Material(Colors4.White, null), Points)
{
PointSize = pointSize,
ComputeFragColor = false
};
}
public void AddPointListGeometry(Vector3[] positions, float pointSize)
{
var points = new Points(positions, "Points");
var material = new Material(Colors4.White, null)
{
EmissiveColor = Colors4.White,
VertexColorBlendFactor = 1
};
_ = new SceneGeometry("Points" + $".{Uid}", points, material, Points)
{
PointSize = pointSize,
ComputeFragColor = false
};
}
public void AddFrameGeometry(Frame frame, float length)
{
AddFrameListGeometry([frame], length);
}
public void AddFrameListGeometry(Frame[] frames, float length)
{
var material = new Material(Colors4.White, null)
{
EmissiveColor = Colors4.White,
VertexColorBlendFactor = 1
};
var name = frames.Length > 1 ? "FrameList" : "Frame";
var firstFrame = frames[0];
var frameContainer = new SceneNode(name + $".{Uid}", Frames)
{
Frame = firstFrame
};
var inverse = firstFrame.Inverse();
for (var i = 0; i < frames.Length; ++i)
{
frames[i] = inverse * frames[i];
}
var frameGeometry = new SceneGeometry("Geometry", Crosses.DefaultCross(0.5f), material, frameContainer)
{
InstanceFrames = [.. frames],
Flags = 0,
LineWidth = 1
};
if (frames.Length > 1)
{
var size = 2 * (frames.Length - 1);
var path = new Vector3[size];
path[0] = frames[0].Translation;
for (var i = 1; i < frames.Length - 1; ++i)
{
path[2 * i] = path[2 * i - 1] = frames[i].Translation;
}
path[^1] = frames[^1].Translation;
_ = new SceneGeometry("Path", new Lines(path), material, frameGeometry);
}
}
}
@@ -0,0 +1,127 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using CommunityToolkit.Mvvm.Input;
using Controls.ViewModels;
using NamedPipes;
using NrxDebugVisualizer.Models;
using NrxDebugVisualizer.Scenes;
using Num.Roto.Visualization.Math.Geometry;
using Num.Roto.Visualization.Math.Utilities;
using Num.Roto.Visualization.Types;
using Num.Roto.Visualization.VulkanLib.SceneInteraction;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using KontractFrame = System.ValueTuple<System.Numerics.Vector3, System.Numerics.Quaternion, float>;
namespace NrxDebugVisualizer.ViewModels;
internal sealed partial class MainWindowViewModel : ViewModelBase
{
public ProportionalDockControlViewModel ProportionalDockControlViewModel { get; } = new();
public VulkanSceneControlViewModel VulkanSceneControlViewModel => ProportionalDockControlViewModel.VulkanSceneControlViewModel;
public SceneTreeViewViewModel SceneTreeViewViewModel => ProportionalDockControlViewModel.SceneTreeViewViewModel?? throw new InvalidOperationException("SceneTreeViewViewModel is not available");
public SceneInteraction SceneInteraction => ProportionalDockControlViewModel.SceneInteraction;
public DebugVisualizerScene DebugVisualizerScene => ProportionalDockControlViewModel.Scene as DebugVisualizerScene ?? throw new InvalidOperationException("Scene is not a DebugVisualizerScene");
private PipeServer PipeServer {get;init;}
public MainWindowViewModel()
{
ProportionalDockControlViewModel.Scene = new DebugVisualizerScene();
ProportionalDockControlViewModel.Scene.SelectedCamera.DefaultFrame = CameraView.Frame(ViewPosition);
PipeServer = new PipeServer(nameof(NrxDebugVisualizer), UpdateScene, cancellationToken: CancellationToken.None);
}
#region Commands
[RelayCommand]
public static void ShowLogViewer()
{
Log.LogViewerEnabled = true;
}
[RelayCommand]
private static void Exit(object? parameter)
{
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopApp)
{
desktopApp.Shutdown();
}
}
[RelayCommand]
internal void ResetCamera()
{
ProportionalDockControlViewModel.VulkanSceneControlViewModel.ResetCamera(CameraView.Frame(ViewPosition));
}
[RelayCommand]
internal void FitToWindow()
{
ProportionalDockControlViewModel.Scene?.FitToWindow(0.95f);
ProportionalDockControlViewModel.VulkanSceneControlViewModel.SceneInteraction.Update();
}
#endregion
#region Camera View
public static IEnumerable<CameraView.Position> ViewPositions => Enum.GetValues<CameraView.Position>();
private CameraView.Position _viewPosition = CameraView.Position.Custom1;
public CameraView.Position ViewPosition
{
get => _viewPosition;
set
{
if (_viewPosition == value) return;
_viewPosition = value;
OnPropertyChanged();
if (_viewPosition == CameraView.Position.User) return;
ProportionalDockControlViewModel.Scene?.SelectedCamera.DefaultFrame = CameraView.Frame(_viewPosition);
FitToWindow();
}
}
#endregion
#region Pipe Server
private void UpdateScene(VisualizerModel visualizerModel)
{
SetPoint(visualizerModel.Point);
SetPointList(visualizerModel.PointArray);
SetFrame(visualizerModel.Frame);
SetFrameList(visualizerModel.FrameArray);
SceneInteraction.Update();
}
private static Frame ToFrame(KontractFrame kontractFrame)
{
var (translation, orientation, scale) = kontractFrame;
return new Frame(translation, scale, orientation);
}
private static Frame[] ToFrameArray(IEnumerable<KontractFrame> frameList)
{
return [.. frameList.Select(ToFrame)];
}
private void SetPoint(Vector3? point)
{
if (point is null) return;
DebugVisualizerScene.AddPointGeometry(point.Value, 5f);
}
private void SetPointList(Vector3[]? pointList)
{
if (pointList == null || pointList.Length < 1) return;
DebugVisualizerScene.AddPointListGeometry(pointList, 5);
}
private void SetFrame(KontractFrame? kontractFrame)
{
if (kontractFrame is null) return;
DebugVisualizerScene.AddFrameGeometry(ToFrame(kontractFrame.Value), 1);
}
private void SetFrameList(KontractFrame[]? frameArray)
{
if (frameArray == null || frameArray.Length < 1) return;
DebugVisualizerScene.AddFrameListGeometry(ToFrameArray(frameArray), 1);
}
#endregion
}
+50
View File
@@ -0,0 +1,50 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:NrxDebugVisualizer.ViewModels"
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"
x:Class="NrxDebugVisualizer.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
xmlns:viewModels="clr-namespace:NrxDebugVisualizer.ViewModels"
xmlns:controls="clr-namespace:Controls.Views;assembly=Controls"
Icon="/Assets/avalonia-logo.ico"
Title="NrxDebugVisualizer"
Width="1200"
Height="800"
MinWidth="800"
MinHeight="600">
<Design.DataContext>
<viewModels:MainWindowViewModel />
</Design.DataContext>
<DockPanel LastChildFill="True" Background="LightGray" >
<Menu DockPanel.Dock="Top" FontSize="12">
<MenuItem Header="_File">
<MenuItem Header="_Exit" Command="{Binding ExitCommand}" />
</MenuItem>
<MenuItem Header="_Options" VerticalAlignment="Center">
<MenuItem Header="_ShowLogViewer" Command="{Binding ShowLogViewerCommand}" />
</MenuItem>
<MenuItem Header="_Camera">
<MenuItem Header="_Reset" Command="{Binding ResetCameraCommand }" />
<MenuItem Header="_Fit" Command="{Binding FitToWindowCommand}" />
<DropDownButton Content="View">
<Button.Flyout>
<Flyout Placement="Right">
<ListBox ItemsSource="{Binding ViewPositions}" SelectedItem="{Binding ViewPosition}" SelectionMode="Single" />
</Flyout>
</Button.Flyout>
</DropDownButton>
</MenuItem>
</Menu>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" Background="DarkGray" >
<Label Content="{Binding ProportionalDockControlViewModel.VulkanSceneControlViewModel.Fps,FallbackValue=Unset}" IsHitTestVisible="False" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
<Label Content="{Binding ProportionalDockControlViewModel.VulkanSceneControlViewModel.ObjectInfo,FallbackValue=Unset}" IsHitTestVisible="False" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
</StackPanel>
<controls:ProportionalDockControl DataContext="{Binding ProportionalDockControlViewModel}"/>
</DockPanel>
</Window>
@@ -0,0 +1,40 @@
using Avalonia.Controls;
using Avalonia.Interactivity;
using NrxDebugVisualizer.ViewModels;
using Num.Roto.Visualization.Types;
using System.Data;
using System.Globalization;
using System.Threading;
namespace NrxDebugVisualizer.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
InitializeComponent();
Closing += OnClosing;
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
if (DataContext is not MainWindowViewModel viewModel) throw new DataException("wrong viewModel type!");
if (App.Settings?.CameraFrame is not { } cameraFrame) return;
var scene = viewModel.ProportionalDockControlViewModel.Scene;
var camera = scene?.SelectedCamera;
camera?.Frame = cameraFrame;
viewModel.ViewPosition = CameraView.Position.User;
}
private async void OnClosing(object? sender, System.ComponentModel.CancelEventArgs e)
{
if (DataContext is not MainWindowViewModel viewModel) throw new DataException("wrong viewModel type!");
var scene = viewModel.ProportionalDockControlViewModel.Scene;
var camera = scene?.SelectedCamera;
App.Settings?.MainWindow = this;
App.Settings?.CameraFrame = camera?.Frame;
App.Settings?.Save();
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="NrxDebugVisualizer.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
@@ -0,0 +1,6 @@
{
"Vector3Visualizer_DisplayName" : "Vector3 Visualizer",
"QuaternionVisualizer_DisplayName" : "Quaternion Visualizer",
"FrameVisualizer_DisplayName" : "Frame Visualizer",
"NrxIEnumerableVisualizer_DisplayName" : "Nrx IEnumerable Visualizer",
}
@@ -1,7 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.Extensibility;
namespace Vector3Visualizer
namespace NrxDebugVisualizer
{
/// <summary>
/// Extension entrypoint for the VisualStudio.Extensibility extension.
@@ -14,7 +14,7 @@ namespace Vector3Visualizer
{
Metadata = new(
id: "Vector3Visualizer.3c0400c3-acec-4b09-b561-c11fac7b10a7",
version: this.ExtensionAssemblyVersion,
version: ExtensionAssemblyVersion,
publisherName: "Nrx Visualizer",
displayName: "Vector3Visualizer",
description: "Visualizer for MailAdress"),
@@ -14,17 +14,15 @@
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.14.40608" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\Vector3VisualizerSource.dll" Link="netstandard2.0\Vector3VisualizerSource.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\NrxVisualizerObjectSource.dll" Link="netstandard2.0\NrxVisualizerObjectSource.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\NamedPipes.dll" Link="netstandard2.0\NamedPipes.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\PipeMethodCalls.dll" Link="netstandard2.0\PipeMethodCalls.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\MessagePack.dll" Link="netstandard2.0\MessagePack.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\MessagePack.Annotations.dll" Link="netstandard2.0\MessagePack.Annotations.dll" CopyToOutputDirectory="PreserveNewest" />
<Content Include="$(MSBuildThisFileDirectory)..\bin\$(Configuration)\net8.0-windows8.0\CommunityToolkit.Mvvm.dll" Link="netstandard2.0\CommunityToolkit.Mvvm.dll" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Vector3VisualizerUserControl.xaml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Vector3VisualizerSource\Vector3VisualizerSource.csproj" />
<ProjectReference Include="..\NrxVisualizerObjectSource\NrxVisualizerObjectSource.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,43 @@
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.DebuggerVisualizers;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
using NamedPipes;
using System;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
namespace NrxDebugVisualizer;
[VisualStudioContribution]
internal sealed class NrxDebuggerVisualizerProvider : DebuggerVisualizerProvider
{
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new(
[
new VisualizerTargetType("%Vector3Visualizer_DisplayName%", @"System.Numerics.Vector3, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"),
new VisualizerTargetType("%QuaternionVisualizer_DisplayName%", typeof(Quaternion)),
new VisualizerTargetType("%FrameVisualizer_DisplayName%", @"Num.Roto.Visualization.Math.Geometry.Frame, Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"),
new VisualizerTargetType("%NrxIEnumerableVisualizer_DisplayName%", @"System.Collections.Generic.IEnumerable`1, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
])
{
VisualizerObjectSourceType = new VisualizerObjectSourceType(typeof(NrxVisualizerObjectSource.NrxVisualizerObjectSource)),
Style = VisualizerStyle.ToolWindow,
};
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
VisualizerModel? model = await visualizerTarget.ObjectSource.RequestDataAsync<VisualizerModel?>(jsonSerializer: null, cancellationToken);
await SendToVisualizerAsync(model);
//throw new InvalidOperationException("This is a test exception to demonstrate the visualizer. Please remove this line and implement the visualizer logic.");
var control = new Vector3VisualizerUserControl(dataContext: model);
return await Task.FromResult<IRemoteUserControl>(control);
}
private static NamedPipeClient? PipeClient { get; set; }
private static async Task SendToVisualizerAsync(VisualizerModel? visualizerModel)
{
if (visualizerModel is null) return;
PipeClient ??= new NamedPipeClient("testPipe", serverName: @"TestServer", logger: (m) => Console.WriteLine(m));
await PipeClient.SetVisualizerModelAsync(visualizerModel);
await PipeClient.SetMessageAsync($"Hello from {nameof(CreateVisualizerAsync)},visualizerModel.Content = {visualizerModel.Content}");
}
}
@@ -0,0 +1,14 @@
using Microsoft.VisualStudio.Extensibility.UI;
using NamedPipes;
namespace NrxDebugVisualizer;
internal sealed class Vector3VisualizerUserControl : RemoteUserControl
{
public Vector3VisualizerUserControl(VisualizerModel? dataContext) : base(dataContext)
{
Vector3Model = (VisualizerModel?)DataContext;
}
public VisualizerModel? Vector3Model { get; }
}
@@ -0,0 +1,5 @@
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<TextBox TextWrapping="Wrap" AcceptsReturn="True" Text="{Binding Content}" Grid.Column="1" Grid.Row="0" />
</Grid>
</DataTemplate>
@@ -0,0 +1,95 @@
using Microsoft.VisualStudio.DebuggerVisualizers;
using NamedPipes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using Frame = System.ValueTuple<System.Numerics.Vector3, System.Numerics.Quaternion, float>;
namespace NrxVisualizerObjectSource;
public class NrxVisualizerObjectSource : VisualizerObjectSource
{
public NrxVisualizerObjectSource()
{
Debug.WriteLine($"new {nameof(NrxVisualizerObjectSource)}");
}
public override void GetData(object target, Stream outgoingData)
{
var fullname = target.GetType().FullName;
Trace.WriteLine("GetData: objectType is: " + fullname);
VisualizerModel visualizerModel = new();
switch (fullname)
{
case "System.Numerics.Vector3":
visualizerModel.Point = (Vector3)target;
visualizerModel.Content = target.ToString();
break;
case "System.Numerics.Quaternion":
visualizerModel.Orientation = (Quaternion)target;
visualizerModel.Content = target.ToString();
break;
case "Num.Roto.Visualization.Math.Geometry.Frame":
var frame = (Frame)TypeDescriptor.GetConverter(target).ConvertTo(target, VisualizerModel.FrameType);
visualizerModel.Frame = frame;
visualizerModel.Content = frame.ToString();
break;
}
if(target is IEnumerable<Vector3> enumerableVector3)
{
Trace.WriteLine($"enumerable type is {typeof(Vector3)}");
if (enumerableVector3 is not null)
{
List<string> stringList = [];
List<Vector3> pointList = [];
foreach (var item in enumerableVector3)
{
pointList.Add(item);
stringList.Add(TypeDescriptor.GetConverter(item).ConvertToString(item));
}
visualizerModel.PointArray = [.. pointList];
visualizerModel.Content = string.Join(Environment.NewLine, stringList);
}
}
else if (target is IEnumerable<object> enumerable)
{
var objectType = enumerable.First().GetType().FullName;
Trace.WriteLine($"IEnumerable<object> objectType is {objectType}");
switch (objectType)
{
case "Num.Roto.Visualization.Math.Geometry.Frame":
{
List<Frame> frameList = [];
foreach (var item in enumerable)
{
var frame = (Frame)TypeDescriptor.GetConverter(item).ConvertTo(item, VisualizerModel.FrameType);
frameList.Add(frame);
}
visualizerModel.FrameArray = [.. frameList];
visualizerModel.Content = string.Join(Environment.NewLine, frameList);
Trace.WriteLine($"I visualizerModel.Content is {visualizerModel.Content}");
break;
}
default:
visualizerModel.Content = $"unsupported enumerable of {objectType}";
break;
}
}
Trace.WriteLine($"visualizerModel.Content = {visualizerModel.Content}");
SerializeAsJson(outgoingData, visualizerModel);
}
public override object CreateReplacementObject(object target, Stream incomingData)
{
throw new NotImplementedException();
//Debug.WriteLine("CreateReplacementObject: objectType is: " + target.GetType().FullName);
//return base.CreateReplacementObject(target, incomingData);
}
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
throw new NotImplementedException();
//Debug.WriteLine("TransferData: objectType is: " + target.GetType().FullName);
//base.TransferData(target, incomingData, outgoingData);
}
}
+16 -4
View File
@@ -1,12 +1,24 @@
using System.Text;
using NamedPipes;
var count = 0;
var message = "Hello World!".ToCharArray();
VisualizerModel visualizerModel = new()
{
Content = "Hello from TestClient",
Point = new System.Numerics.Vector3(1, 2, 3),
//Orientation = System.Numerics.Quaternion.Identity,
//PointArray = [new System.Numerics.Vector3(4, 5, 6), new System.Numerics.Vector3(7, 8, 9)],
//Frame = (new System.Numerics.Vector3(10, 11, 12), System.Numerics.Quaternion.Identity, 1.0f),
//FrameArray = [(new System.Numerics.Vector3(13, 14, 15), System.Numerics.Quaternion.Identity, 2.0f), (new System.Numerics.Vector3(16, 17, 18), System.Numerics.Quaternion.Identity, 3.0f)]
};
while (true)
{
var pipeClient = new NamedPipeClient("testPipe",@".\","TestServer",logger:Console.WriteLine);
var serverName = "NrxDebugVisualizer";
var pipeClient = new NamedPipeClient(serverName, @".\", serverName, logger:Console.WriteLine);
Thread.Sleep(1000);
pipeClient.SetMessageAsync($"Hello from TestClient " + count++).GetAwaiter().GetResult();
pipeClient.SetDebugObjectAsync(new DebugObject{Type = typeof(string).FullName,Data = Encoding.GetEncoding("UTF-8").GetBytes(message)}).GetAwaiter().GetResult();
visualizerModel.Point = new System.Numerics.Vector3(count, count * 2, count * 3);
count++;
await pipeClient.SetVisualizerModelAsync(visualizerModel);
//await pipeClient.SetMessageAsync($"Hello from TestClient " + count++);
pipeClient.Dispose();
}
+3 -2
View File
@@ -1,5 +1,6 @@
using System;
var pipeServer = new NamedPipes.NamedPipesServer("testPipe",logger:Console.WriteLine);
await pipeServer.RunAsync().ConfigureAwait(true);
using System.Threading;
var pipeServer = new NamedPipes.NamedPipesServer("NrxDebugVisualizer", logger:Console.WriteLine);
await pipeServer.RunAsync(CancellationToken.None).ConfigureAwait(true);
@@ -0,0 +1,8 @@
{
"profiles": {
"TestServer": {
"commandName": "Project",
"workingDirectory": "C:\\Users\\matth\\Documents\\Visual Studio 2026\\Visualizers"
}
}
}
+13 -1
View File
@@ -8,5 +8,17 @@
<ItemGroup>
<ProjectReference Include="..\NamedPipes\NamedPipes.csproj" />
</ItemGroup>
<Target Name="CopyToVs2026" Condition="Exists('$(OutputPath)\$(MSBuildProjectName).exe')" AfterTargets="AfterBuild" >
<Message Importance="High" Text="CopyToVs2026"></Message>
<ItemGroup>
<FilesToCopy Include="$(OutputPath)\$(MSBuildProjectName).exe;
$(OutputPath)\$(MSBuildProjectName).dll;
$(OutputPath)\$(MSBuildProjectName).runtimeconfig.json;
$(OutputPath)\PipeMethodCalls.dll;
$(OutputPath)\NamedPipes.dll;
$(OutputPath)\CommunityToolkit.Mvvm.dll;
"/>
</ItemGroup>
<Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(USERPROFILE)\Documents\Visual Studio 2026\Visualizers" SkipUnchangedFiles="True" />
</Target>
</Project>
-80
View File
@@ -1,80 +0,0 @@
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Vector3VisualizerSource;
namespace Vector3Visualizer;
public class MyRemoteUserControl : IRemoteWpfUserControl, IRemoteProxiedUserControl, IRemoteUserControl, IDisposable, IRemoteProxiedUserControl2
{
public Vector3Model? Model { get; }
public MyRemoteUserControl(Vector3Model? model) => Model = model;
private bool disposedValue;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects)
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
// ~MyRemoteUserControl()
// {
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
// Dispose(disposing: false);
// }
void IDisposable.Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
Task<RemoteWpfUserControlDefinition> IRemoteWpfUserControl.InitializeAsync(IRemoteProxiedUserControlClient remoteUserControlClient, CancellationToken cancellationToken)
{
return Task.FromResult(new RemoteWpfUserControlDefinition());
}
Task IRemoteWpfUserControl.ControlLoadedAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
Task<bool> IRemoteProxiedUserControl.GetObjectAsync(ObjectId id, CancellationToken cancellationToken)
{
return Task.FromResult(false);
}
Task<bool> IRemoteProxiedUserControl.SetObjectPropertyAsync(ObjectId id, string propertyName, MessagePackFragment value, CancellationToken cancellationToken)
{
return Task.FromResult(false);
}
Task<bool> IRemoteProxiedUserControl.SetCollectionEntryAsync(ObjectId id, int index, MessagePackFragment value, ObjectVersion? version, CancellationToken cancellationToken)
{
return Task.FromResult(false);
}
Task<bool> IRemoteProxiedUserControl.InvokeAsync(ObjectId id, MessagePackFragment parameter, CancellationToken cancellationToken)
{
return Task.FromResult(false);
}
Task<bool> IRemoteProxiedUserControl2.InvokeAsync(ObjectId id, MessagePackFragment parameter, IReadOnlyDictionary<string, string> context, CancellationToken cancellationToken)
{
return Task.FromResult(false);
}
}
@@ -1,52 +0,0 @@
using Microsoft.VisualStudio.Extensibility;
using Microsoft.VisualStudio.Extensibility.DebuggerVisualizers;
using Microsoft.VisualStudio.RpcContracts.RemoteUI;
using NamedPipes;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Vector3VisualizerSource;
namespace Vector3Visualizer;
[VisualStudioContribution]
internal sealed class Vector3DebuggerVisualizerProvider : DebuggerVisualizerProvider
{
#pragma warning disable CEE0027 // String not localized
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new(
[
new VisualizerTargetType("Vector3 Visualizer", @"System.Numerics.Vector3, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"),
new VisualizerTargetType("List Visualizer", typeof(List<>)),
new VisualizerTargetType("Vector3[] Visualizer", typeof(Vector3[])),
new VisualizerTargetType("Quaternion Visualizer", typeof(Quaternion)),
new VisualizerTargetType("Frame Visualizer", @"Num.Roto.Visualization.Math.Geometry.Frame, Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"),
new VisualizerTargetType("Frame Array Visualizer", @"Num.Roto.Visualization.Math.Geometry.Frame[], Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"),
//not working
new VisualizerTargetType("Frame List Visualizer", @"System.Collections.Generic.List<Num.Roto.Visualization.Math.Geometry.Frame>, Num.Roto.Visualization.Math, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]"),
])
{
VisualizerObjectSourceType = new VisualizerObjectSourceType(typeof(Vector3ObjectSource)),
Style = VisualizerStyle.ToolWindow,
};
#pragma warning restore CEE0027 // String not localized
private static NamedPipeClient? PipeClient { get; set; }
private static void SendToVisualizer(Vector3Model? vector3Model)
{
if (vector3Model is null) return;
PipeClient ??= new NamedPipeClient("testPipe", serverName: @"TestServer", logger: (m) => Console.WriteLine(m));
_ = PipeClient.SetMessageAsync($"Hello from {nameof(CreateVisualizerAsync)},vector3Model = {vector3Model.Vector3},{vector3Model.Quaternion}");
}
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
Vector3Model? model = await visualizerTarget.ObjectSource.RequestDataAsync<Vector3Model?>(jsonSerializer: null, cancellationToken);
SendToVisualizer(model);
var control = new Vector3VisualizerUserControl(dataContext: model);
return await Task.FromResult<IRemoteUserControl>(control);
//return await Task.FromResult<IRemoteUserControl>(new MyRemoteUserControl(model));
}
}
@@ -1,14 +0,0 @@
using Vector3VisualizerSource;
using Microsoft.VisualStudio.Extensibility.UI;
namespace Vector3Visualizer;
internal sealed class Vector3VisualizerUserControl : RemoteUserControl
{
public Vector3VisualizerUserControl(Vector3Model? dataContext) : base(dataContext)
{
Vector3Model = (Vector3Model?)DataContext;
}
public Vector3Model? Vector3Model { get; }
}
@@ -1,16 +0,0 @@
<DataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Vector3" Grid.Column="0" Grid.Row="0" />
<TextBlock Text="{Binding Vector3}" Grid.Column="1" Grid.Row="0" />
<TextBlock Text="Quaternion" Grid.Column="0" Grid.Row="1" />
<TextBlock Text="{Binding Quaternion}" Grid.Column="1" Grid.Row="1" />
</Grid>
</DataTemplate>
-13
View File
@@ -1,13 +0,0 @@
using System.Numerics;
using System.Runtime.Serialization;
namespace Vector3VisualizerSource;
[DataContract]
public class Vector3Model
{
[DataMember]
public Vector3? Vector3 { get; set; }
[DataMember]
public Quaternion? Quaternion { get; set;}
}
@@ -1,35 +0,0 @@
using Microsoft.VisualStudio.DebuggerVisualizers;
using NamedPipes;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
namespace Vector3VisualizerSource;
public class Vector3ObjectSource : VisualizerObjectSource
{
public Vector3ObjectSource()
{
Debug.WriteLine("new Vector3ObjectSource");
}
public override void GetData(object target, Stream outgoingData)
{
Debug.WriteLine("GetData: objectType is: " + target.GetType().FullName);
Vector3Model vector3Model = new();
switch (target)
{
case Vector3 vector3:
vector3Model.Vector3 = vector3;
break;
case IEnumerable<Vector3> vector3List:
vector3Model.Vector3 = vector3List.Last();
break;
case Quaternion quaternion:
vector3Model.Quaternion = quaternion;
break;
}
SerializeAsJson(outgoingData, vector3Model);
}
}
-12
View File
@@ -1,12 +0,0 @@
using System.Numerics;
var a = new Vector3(1,2,3);
var typeName = a.GetType().AssemblyQualifiedName;
var b = new Vector3(5, 6, 7);
Vector3[] v3Array = [a, b];
List<Vector3> v3List = v3Array.ToList();
var quaternion = new Quaternion(1,2,3,4);
return;
@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
@@ -1,3 +0,0 @@
<Solution>
<Project Path="Vector3VisualizerTest.csproj" />
</Solution>
-12
View File
@@ -1,12 +0,0 @@
<Solution>
<Folder Name="/NamedPipes/">
<Project Path="NamedPipes/NamedPipes.csproj" Id="8d7b1151-8b57-4411-a361-47ed9c504a22" />
</Folder>
<Folder Name="/Test/">
<Project Path="TestClient/TestClient.csproj" />
<Project Path="TestServer/TestServer.csproj" Id="c81154ef-d854-4f1e-9d14-2cf674885291" />
<Project Path="Vector3VisualizerTest/Vector3VisualizerTest.csproj" />
</Folder>
<Project Path="Vector3Visualizer/Vector3Visualizer.csproj" />
<Project Path="Vector3VisualizerSource/Vector3VisualizerSource.csproj" />
</Solution>