// 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:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/