// SpeedTestWindow.xaml.cs // SpeedOf.Me API - Windows/WPF Integration // // This file demonstrates how to integrate the SpeedOf.Me speed test // into a Windows WPF app using WebView2. using System; using System.Text.Json; using System.Threading.Tasks; using System.Windows; using Microsoft.Web.WebView2.Core; namespace SpeedTest { /// /// Speed test result data /// public class SpeedTestResult { public double Download { get; set; } public double Upload { get; set; } public double Latency { get; set; } public double Jitter { get; set; } public string? TestServer { get; set; } public string? IpAddress { get; set; } public string? Hostname { get; set; } } /// /// Speed test progress data /// public class SpeedTestProgress { public string TestType { get; set; } = "download"; public double CurrentSpeed { get; set; } public double PercentComplete { get; set; } public int PassNumber { get; set; } } /// /// Speed test error data /// public class SpeedTestError { public int Code { get; set; } public string Message { get; set; } = ""; } /// /// Message from WebView JavaScript /// public class WebViewMessage { public string Type { get; set; } = ""; public JsonElement Data { get; set; } } /// /// Main window containing the speed test WebView /// public partial class SpeedTestWindow : Window { private bool _isRunning = false; public SpeedTestWindow() { InitializeComponent(); InitializeWebView(); } /// /// Initialize WebView2 and load the speed test HTML /// private async void InitializeWebView() { try { // Ensure WebView2 runtime is available await SpeedTestWebView.EnsureCoreWebView2Async(); // Handle messages from JavaScript SpeedTestWebView.CoreWebView2.WebMessageReceived += OnWebMessageReceived; // Option 1: Load from embedded resource or file // Note: You'll need to set up the HTML as an embedded resource // or copy it to the output directory string htmlPath = System.IO.Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "speedtest.html" ); if (System.IO.File.Exists(htmlPath)) { SpeedTestWebView.CoreWebView2.Navigate($"file:///{htmlPath.Replace('\\', '/')}"); } else { // Option 2: Load from remote URL SpeedTestWebView.CoreWebView2.Navigate("https://your-domain.com/speedtest.html"); } UpdateStatus("Ready"); } catch (Exception ex) { UpdateStatus($"Error initializing WebView: {ex.Message}"); } } /// /// Handle messages received from the WebView JavaScript /// private void OnWebMessageReceived(object? sender, CoreWebView2WebMessageReceivedEventArgs e) { try { string json = e.WebMessageAsJson; var message = JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); if (message == null) return; // Must dispatch to UI thread Dispatcher.Invoke(() => HandleMessage(message)); } catch (Exception ex) { Dispatcher.Invoke(() => UpdateStatus($"Error: {ex.Message}")); } } /// /// Process a message from the WebView /// private void HandleMessage(WebViewMessage message) { switch (message.Type) { case "ready": _isRunning = false; UpdateStatus("Ready to test"); break; case "started": _isRunning = true; ResultsPanel.Visibility = Visibility.Collapsed; UpdateStatus("Starting test..."); break; case "progress": var progress = JsonSerializer.Deserialize( message.Data.GetRawText(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); if (progress != null) { string testType = progress.TestType == "download" ? "Download" : "Upload"; UpdateStatus($"{testType}: {progress.CurrentSpeed:F1} Mbps ({progress.PercentComplete:F0}%)"); } break; case "completed": var result = JsonSerializer.Deserialize( message.Data.GetRawText(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); if (result != null) { _isRunning = false; UpdateStatus("Test complete"); DisplayResults(result); } break; case "error": var error = JsonSerializer.Deserialize( message.Data.GetRawText(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); if (error != null) { _isRunning = false; UpdateStatus($"Error {error.Code}: {error.Message}"); } break; } } /// /// Update the status text /// private void UpdateStatus(string status) { StatusText.Text = status; } /// /// Display the test results in the native UI /// private void DisplayResults(SpeedTestResult result) { DownloadResult.Text = $"{result.Download} Mbps"; UploadResult.Text = $"{result.Upload} Mbps"; LatencyResult.Text = $"{result.Latency} ms"; JitterResult.Text = $"{result.Jitter} ms"; ResultsPanel.Visibility = Visibility.Visible; } } } /* * XAML for SpeedTestWindow.xaml: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */