Added a search bar to limit large XSD files

This commit is contained in:
Frederik Jacobsen 2025-10-18 20:31:00 +02:00
parent eacfcf611c
commit 81f6660da5
4 changed files with 99 additions and 3 deletions

View File

@ -16,6 +16,22 @@
<!-- Header -->
<DockPanel LastChildFill="False">
<TextBlock Text="XSD Visualiser" FontSize="20" FontWeight="SemiBold" Margin="0,0,12,0" DockPanel.Dock="Left"/>
<!-- Searchable dropdown for root elements -->
<AutoCompleteBox Width="320" Margin="0,0,12,0" Watermark="Search and choose a root element"
ItemsSource="{Binding RootElements}"
FilterMode="Contains"
MinimumPrefixLength="0">
<AutoCompleteBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding .}"/>
</DataTemplate>
</AutoCompleteBox.ItemTemplate>
<AutoCompleteBox.SelectedItem>
<Binding Path="SelectedRootElement" Mode="TwoWay"/>
</AutoCompleteBox.SelectedItem>
</AutoCompleteBox>
<Button Content="Open XSD and parse" x:Name="OpenBtn" Width="220"/>
</DockPanel>
@ -26,7 +42,7 @@
BorderBrush="{DynamicResource PanelBorderBrush}"
BorderThickness="1" CornerRadius="6" Margin="0,8,8,0">
<ScrollViewer>
<TreeView x:Name="SchemaTree" ItemsSource="{Binding RootElements}">
<TreeView x:Name="SchemaTree" ItemsSource="{Binding VisibleRootElements}">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type m:SchemaNode}" ItemsSource="{Binding Children}">
<StackPanel>

View File

@ -5,6 +5,7 @@ using Avalonia.Interactivity;
using Avalonia.Threading;
using XSDVisualiser.Core;
using XSDVisualiser.Models;
using XSDVisualiser.Desktop.ViewModels;
namespace XSDVisualiser.Desktop
{
@ -42,11 +43,11 @@ namespace XSDVisualiser.Desktop
{
var parser = new XsdSchemaParser();
var model = parser.Parse(path);
Dispatcher.UIThread.Post(() => DataContext = model);
Dispatcher.UIThread.Post(() => DataContext = new MainWindowViewModel(model));
}
catch (Exception ex)
{
Dispatcher.UIThread.Post(() => DataContext = new SchemaModel { TargetNamespace = ex.Message });
Dispatcher.UIThread.Post(() => DataContext = new MainWindowViewModel(new SchemaModel { TargetNamespace = ex.Message }));
}
});
}

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using XSDVisualiser.Models;
namespace XSDVisualiser.Desktop.ViewModels
{
public class MainWindowViewModel : INotifyPropertyChanged
{
private SchemaModel _model;
private SchemaNode? _selectedRootElement;
public MainWindowViewModel(SchemaModel model)
{
_model = model ?? throw new ArgumentNullException(nameof(model));
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public SchemaModel Model
{
get => _model;
set
{
if (!ReferenceEquals(_model, value))
{
_model = value ?? throw new ArgumentNullException(nameof(value));
OnPropertyChanged();
OnPropertyChanged(nameof(RootElements));
OnPropertyChanged(nameof(VisibleRootElements));
}
}
}
public IEnumerable<SchemaNode> RootElements => _model?.RootElements ?? Enumerable.Empty<SchemaNode>();
public SchemaNode? SelectedRootElement
{
get => _selectedRootElement;
set
{
if (!EqualityComparer<SchemaNode?>.Default.Equals(_selectedRootElement, value))
{
_selectedRootElement = value;
OnPropertyChanged();
OnPropertyChanged(nameof(VisibleRootElements));
}
}
}
public IEnumerable<SchemaNode> VisibleRootElements
{
get
{
if (SelectedRootElement != null)
return new[] { SelectedRootElement };
return RootElements;
}
}
}
}

View File

@ -54,6 +54,17 @@ namespace XSDVisualiser.Models
[XmlAttribute]
public string? ContentModel { get; set; } // sequence | choice | all | simple
public override string ToString()
{
// Used by AutoCompleteBox to get text for filtering and matching
// Prefer Name, then TypeName, and fall back to base implementation
if (!string.IsNullOrEmpty(Name))
return Name!;
if (!string.IsNullOrEmpty(TypeName))
return TypeName!;
return base.ToString();
}
}
/// <summary>