csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
6.3 KiB
175 lines
6.3 KiB
using System;
|
|
using System.Text;
|
|
using Microsoft.UI.Xaml;
|
|
using Microsoft.UI.Xaml.Automation.Peers;
|
|
using Microsoft.UI.Xaml.Controls;
|
|
using Microsoft.UI.Xaml.Controls.Primitives;
|
|
using global::Avalonia.Styling;
|
|
using AvApplication = global::Avalonia.Application;
|
|
|
|
namespace WinUIEmbedSample
|
|
{
|
|
public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
|
|
{
|
|
private int _clicks;
|
|
|
|
public MainWindow()
|
|
{
|
|
InitializeComponent();
|
|
|
|
App.Lifetime.MainView = new EmbeddedView();
|
|
AvaloniaPanel.Content = App.Lifetime.MainView;
|
|
|
|
// Probe the automation peer *before* the panel is loaded — answers the
|
|
// open question of whether GetChildren() works before _root.Prepare().
|
|
AppendDiagnostic("ctor: " + DescribePeer());
|
|
|
|
AvaloniaPanel.Loading += (_, _) => AppendDiagnostic("Loading: " + DescribePeer());
|
|
AvaloniaPanel.Loaded += (_, _) =>
|
|
{
|
|
AppendDiagnostic("Loaded: " + DescribePeer());
|
|
};
|
|
}
|
|
|
|
private string DescribePeer()
|
|
{
|
|
try
|
|
{
|
|
var peer = FrameworkElementAutomationPeer.CreatePeerForElement(AvaloniaPanel);
|
|
if (peer is null)
|
|
return "peer=null";
|
|
var children = peer.GetChildren();
|
|
var count = children?.Count ?? 0;
|
|
var sb = new StringBuilder();
|
|
sb.Append("peer=").Append(peer.GetType().Name)
|
|
.Append(" class=").Append(peer.GetClassName())
|
|
.Append(" childCount=").Append(count);
|
|
if (count > 0)
|
|
{
|
|
sb.Append(" first=[");
|
|
var first = children![0];
|
|
sb.Append(first.GetClassName()).Append('/').Append(first.GetAutomationControlType());
|
|
sb.Append("] firstChildren=").Append(first.GetChildren()?.Count ?? 0);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return "threw: " + ex.GetType().Name + ": " + ex.Message;
|
|
}
|
|
}
|
|
|
|
private void ProbePeerButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
AppendDiagnostic("Probe: " + DescribePeer());
|
|
}
|
|
|
|
private async void ProbeWorkerButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
// Cache the peer on the UI thread (CreatePeerForElement is UI-thread bound).
|
|
var peer = FrameworkElementAutomationPeer.CreatePeerForElement(AvaloniaPanel);
|
|
|
|
// Walk on a worker thread — mimics how UIA queries (it calls from a separate thread).
|
|
var result = await System.Threading.Tasks.Task.Run(() =>
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.Append("Worker-thread walk (TID=").Append(Environment.CurrentManagedThreadId).Append("):\n");
|
|
try { WalkPeer(peer, 0, sb, maxDepth: 20); }
|
|
catch (Exception ex) { sb.Append("THREW: ").Append(ex); }
|
|
return sb.ToString();
|
|
});
|
|
|
|
AppendDiagnostic(result);
|
|
}
|
|
|
|
private void ProbeDeepButton_Click(object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var peer = FrameworkElementAutomationPeer.CreatePeerForElement(AvaloniaPanel);
|
|
var sb = new StringBuilder();
|
|
sb.Append("Deep walk:\n");
|
|
WalkPeer(peer, 0, sb, maxDepth: 20);
|
|
AppendDiagnostic(sb.ToString());
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppendDiagnostic("Deep probe threw: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static void WalkPeer(AutomationPeer peer, int depth, StringBuilder sb, int maxDepth)
|
|
{
|
|
if (peer is null || depth > maxDepth)
|
|
return;
|
|
|
|
for (var i = 0; i < depth; i++) sb.Append(" ");
|
|
var className = peer.GetClassName();
|
|
var name = peer.GetName();
|
|
var type = peer.GetAutomationControlType();
|
|
var children = peer.GetChildren();
|
|
sb.Append('[').Append(className).Append(']')
|
|
.Append(" type=").Append(type)
|
|
.Append(" name=\"").Append(name).Append('"')
|
|
.Append(" children=").Append(children?.Count ?? 0)
|
|
.Append('\n');
|
|
|
|
if (children is null) return;
|
|
foreach (var child in children)
|
|
WalkPeer(child, depth + 1, sb, maxDepth);
|
|
}
|
|
|
|
private void AppendDiagnostic(string line)
|
|
{
|
|
if (DiagnosticsLog is null)
|
|
return;
|
|
DiagnosticsLog.Text += "[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + line + "\n";
|
|
}
|
|
|
|
private void WinUiButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
|
{
|
|
WinUiClickCount.Text = $"Clicked {++_clicks} times";
|
|
}
|
|
|
|
private void WinUiDragSource_DragStarting(
|
|
Microsoft.UI.Xaml.UIElement sender,
|
|
Microsoft.UI.Xaml.DragStartingEventArgs e)
|
|
{
|
|
e.Data.SetText("Hello from WinUI");
|
|
e.AllowedOperations =
|
|
Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy |
|
|
Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
|
}
|
|
|
|
private void WinUiSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
|
|
{
|
|
if (WinUiSliderValue is not null)
|
|
WinUiSliderValue.Text = $"Slider: {e.NewValue:F0}";
|
|
}
|
|
|
|
private void WinUiThemeCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
{
|
|
var selected = WinUiThemeCombo.SelectedIndex;
|
|
|
|
if (Content is FrameworkElement root)
|
|
{
|
|
root.RequestedTheme = selected switch
|
|
{
|
|
0 => ElementTheme.Light,
|
|
1 => ElementTheme.Dark,
|
|
_ => ElementTheme.Default
|
|
};
|
|
}
|
|
|
|
if (AvApplication.Current is { } avApp)
|
|
{
|
|
avApp.RequestedThemeVariant = selected switch
|
|
{
|
|
0 => ThemeVariant.Light,
|
|
1 => ThemeVariant.Dark,
|
|
_ => ThemeVariant.Default
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|