2
0

AppTheming and XAML

This commit is contained in:
2026-01-11 12:33:48 -05:00
parent f87ea17a6f
commit 50cc186d6d
48 changed files with 3544 additions and 3068 deletions

21
WebViewDemo/App.cs Normal file
View File

@@ -0,0 +1,21 @@
// App.cs - Main Application with NavigationPage
using Microsoft.Maui.Controls;
namespace WebViewDemo;
public class App : Application
{
public static NavigationPage? NavigationPage { get; private set; }
public App()
{
NavigationPage = new NavigationPage(new WebViewPage())
{
Title = "OpenMaui WebView Demo",
BarBackgroundColor = Color.FromArgb("#5C6BC0"),
BarTextColor = Colors.White
};
MainPage = NavigationPage;
}
}

View File

@@ -0,0 +1,22 @@
// MauiProgram.cs - MAUI app configuration
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform.Linux.Hosting;
namespace WebViewDemo;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
// Configure the app
builder.UseMauiApp<App>();
// Add Linux platform support with all handlers
builder.UseLinux();
return builder.Build();
}
}

View File

@@ -0,0 +1,158 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewDemo.WebViewPage"
Title="WebView Demo"
BackgroundColor="#F5F7FA">
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="PrimaryColor">#5C6BC0</Color>
<Color x:Key="PrimaryDark">#3949AB</Color>
<Color x:Key="AccentColor">#26A69A</Color>
<Color x:Key="ButtonColor">#667EEA</Color>
<Color x:Key="TextPrimary">#212121</Color>
<Color x:Key="TextSecondary">#757575</Color>
<Color x:Key="CardBackground">#FFFFFF</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid RowDefinitions="Auto,Auto,Auto,*,Auto,Auto" Padding="16" RowSpacing="12">
<!-- Header -->
<Label Grid.Row="0"
Text="WebView Demo - WebKitGTK"
FontSize="22"
FontAttributes="Bold"
TextColor="{StaticResource PrimaryColor}"
HorizontalOptions="Center" />
<!-- Navigation Bar -->
<Border Grid.Row="1"
BackgroundColor="{StaticResource CardBackground}"
StrokeThickness="0"
Padding="12">
<Border.StrokeShape>
<RoundRectangle CornerRadius="8" />
</Border.StrokeShape>
<HorizontalStackLayout Spacing="8" HorizontalOptions="Center">
<Button x:Name="BackButton"
Text="Back"
WidthRequest="70"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource ButtonColor}"
TextColor="White"
Clicked="OnBackClicked" />
<Button x:Name="ForwardButton"
Text="Forward"
WidthRequest="80"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource ButtonColor}"
TextColor="White"
Clicked="OnForwardClicked" />
<Button x:Name="ReloadButton"
Text="Reload"
WidthRequest="70"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource ButtonColor}"
TextColor="White"
Clicked="OnReloadClicked" />
</HorizontalStackLayout>
</Border>
<!-- URL Bar -->
<Border Grid.Row="2"
BackgroundColor="{StaticResource CardBackground}"
StrokeThickness="0"
Padding="12">
<Border.StrokeShape>
<RoundRectangle CornerRadius="8" />
</Border.StrokeShape>
<Grid ColumnDefinitions="*,Auto" ColumnSpacing="8">
<Entry x:Name="UrlEntry"
Grid.Column="0"
Placeholder="Enter URL..."
Text="https://dotnet.microsoft.com"
FontSize="14"
VerticalOptions="Center"
Completed="OnUrlSubmitted" />
<Button x:Name="GoButton"
Grid.Column="1"
Text="Go"
WidthRequest="60"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource AccentColor}"
TextColor="White"
Clicked="OnGoClicked" />
</Grid>
</Border>
<!-- WebView -->
<Border Grid.Row="3"
BackgroundColor="{StaticResource CardBackground}"
StrokeThickness="1"
Stroke="#E0E0E0">
<Border.StrokeShape>
<RoundRectangle CornerRadius="8" />
</Border.StrokeShape>
<WebView x:Name="MainWebView"
VerticalOptions="Fill"
HorizontalOptions="Fill"
Navigating="OnNavigating"
Navigated="OnNavigated" />
</Border>
<!-- Action Buttons -->
<Border Grid.Row="4"
BackgroundColor="{StaticResource CardBackground}"
StrokeThickness="0"
Padding="12">
<Border.StrokeShape>
<RoundRectangle CornerRadius="8" />
</Border.StrokeShape>
<HorizontalStackLayout Spacing="8" HorizontalOptions="Center">
<Button x:Name="LoadHtmlButton"
Text="Load HTML"
WidthRequest="110"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource PrimaryColor}"
TextColor="White"
Clicked="OnLoadHtmlClicked" />
<Button x:Name="EvalJsButton"
Text="Run JS"
WidthRequest="90"
HeightRequest="36"
FontSize="13"
BackgroundColor="{StaticResource PrimaryColor}"
TextColor="White"
Clicked="OnEvalJsClicked" />
</HorizontalStackLayout>
</Border>
<!-- Status Bar -->
<Border Grid.Row="5"
BackgroundColor="{StaticResource PrimaryDark}"
StrokeThickness="0"
Padding="12,8">
<Border.StrokeShape>
<RoundRectangle CornerRadius="6" />
</Border.StrokeShape>
<Label x:Name="StatusLabel"
Text="Ready"
FontSize="13"
TextColor="White"
HorizontalOptions="Center" />
</Border>
</Grid>
</ContentPage>

View File

@@ -0,0 +1,178 @@
// WebViewPage - Main page demonstrating WebView with WebKitGTK
using Microsoft.Maui.Controls;
namespace WebViewDemo;
public partial class WebViewPage : ContentPage
{
public WebViewPage()
{
Console.WriteLine("[WebViewPage] Constructor starting");
InitializeComponent();
// Set initial URL
MainWebView.Source = new UrlWebViewSource { Url = "https://dotnet.microsoft.com" };
Console.WriteLine("[WebViewPage] Constructor finished");
}
private void OnBackClicked(object? sender, EventArgs e)
{
Console.WriteLine("[WebViewPage] Back button clicked");
if (MainWebView.CanGoBack)
{
MainWebView.GoBack();
}
}
private void OnForwardClicked(object? sender, EventArgs e)
{
Console.WriteLine("[WebViewPage] Forward button clicked");
if (MainWebView.CanGoForward)
{
MainWebView.GoForward();
}
}
private void OnReloadClicked(object? sender, EventArgs e)
{
Console.WriteLine("[WebViewPage] Reload button clicked");
MainWebView.Reload();
}
private void OnGoClicked(object? sender, EventArgs e)
{
Navigate();
}
private void OnUrlSubmitted(object? sender, EventArgs e)
{
Navigate();
}
private void Navigate()
{
var url = UrlEntry.Text?.Trim();
if (string.IsNullOrEmpty(url))
return;
// Add https:// if not present
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
url = "https://" + url;
Console.WriteLine($"[WebViewPage] Navigating to: {url}");
MainWebView.Source = new UrlWebViewSource { Url = url };
UrlEntry.Text = url;
}
private void OnNavigating(object? sender, WebNavigatingEventArgs e)
{
StatusLabel.Text = $"Loading: {e.Url}";
Console.WriteLine($"[WebViewPage] Navigating to: {e.Url}");
}
private void OnNavigated(object? sender, WebNavigatedEventArgs e)
{
StatusLabel.Text = e.Result == WebNavigationResult.Success
? $"Loaded: {e.Url}"
: $"Failed: {e.Result}";
UrlEntry.Text = e.Url;
Console.WriteLine($"[WebViewPage] Navigated: {e.Result} - {e.Url}");
}
private void OnLoadHtmlClicked(object? sender, EventArgs e)
{
Console.WriteLine("[WebViewPage] Load HTML button clicked");
var html = @"
<!DOCTYPE html>
<html>
<head>
<title>OpenMaui WebView</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
}
h1 {
font-size: 2.5em;
margin-bottom: 20px;
}
p {
font-size: 1.2em;
line-height: 1.6;
}
.feature-list {
background: rgba(255,255,255,0.1);
padding: 20px;
border-radius: 10px;
margin-top: 20px;
}
li {
margin: 10px 0;
font-size: 1.1em;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 15px 30px;
font-size: 1.1em;
border-radius: 5px;
cursor: pointer;
margin-top: 20px;
}
button:hover {
background: #45a049;
}
</style>
</head>
<body>
<h1>Hello from OpenMaui Linux!</h1>
<p>This HTML content is rendered by WebKitGTK inside your .NET MAUI application.</p>
<div class='feature-list'>
<h2>WebView Features:</h2>
<ul>
<li>Full HTML5 support</li>
<li>CSS3 animations and transitions</li>
<li>JavaScript execution</li>
<li>Navigation history (back/forward)</li>
<li>WebGL and canvas support</li>
</ul>
</div>
<button onclick=""alert('Hello from JavaScript!')"">Click Me!</button>
<p style='margin-top: 30px; opacity: 0.8;'>
Powered by WebKitGTK - the same engine used by GNOME Web (Epiphany)
</p>
</body>
</html>";
MainWebView.Source = new HtmlWebViewSource { Html = html };
StatusLabel.Text = "Loaded custom HTML";
}
private async void OnEvalJsClicked(object? sender, EventArgs e)
{
Console.WriteLine("[WebViewPage] Run JS button clicked");
try
{
var result = await MainWebView.EvaluateJavaScriptAsync("document.title");
StatusLabel.Text = $"JS Result: {result ?? "(null)"}";
Console.WriteLine($"[WebViewPage] JS Eval result: {result}");
}
catch (Exception ex)
{
StatusLabel.Text = $"JS Error: {ex.Message}";
Console.WriteLine($"[WebViewPage] JS Error: {ex.Message}");
}
}
}

View File

@@ -1,283 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// Program.cs - Linux platform entry point
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Platform.Linux;
using Microsoft.Maui.Platform.Linux.Hosting;
namespace WebViewDemo;
public static class MauiProgram
class Program
{
public static MauiApp CreateMauiApp()
static void Main(string[] args)
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
builder.UseLinux();
return builder.Build();
}
}
// Redirect console output to a log file for debugging
var logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "webviewdemo.log");
using var logWriter = new StreamWriter(logPath, append: false) { AutoFlush = true };
var multiWriter = new MultiTextWriter(Console.Out, logWriter);
Console.SetOut(multiWriter);
Console.SetError(multiWriter);
public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine("[Program] Starting WebView Demo");
var app = MauiProgram.CreateMauiApp();
LinuxApplication.Run(app, args);
}
}
public class App : Application
{
public App()
{
MainPage = new NavigationPage(new WebViewPage())
// Global exception handler
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
Title = "WebView Demo"
};
}
}
public class WebViewPage : ContentPage
{
private readonly WebView _webView;
private readonly Entry _urlEntry;
private readonly Label _statusLabel;
public WebViewPage()
{
Title = "WebView Demo";
_webView = new WebView
{
HeightRequest = 400,
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.Fill,
Source = new UrlWebViewSource { Url = "https://dotnet.microsoft.com" }
};
_webView.Navigating += OnNavigating;
_webView.Navigated += OnNavigated;
_urlEntry = new Entry
{
Placeholder = "Enter URL...",
Text = "https://dotnet.microsoft.com",
HorizontalOptions = LayoutOptions.Fill
};
_urlEntry.Completed += OnUrlSubmitted;
_statusLabel = new Label
{
Text = "Ready",
TextColor = Colors.Gray,
FontSize = 12
};
var goButton = new Button
{
Text = "Go",
WidthRequest = 60
};
goButton.Clicked += (s, e) => Navigate();
var backButton = new Button
{
Text = "Back",
WidthRequest = 60
};
backButton.Clicked += (s, e) => _webView.GoBack();
var forwardButton = new Button
{
Text = "Forward",
WidthRequest = 80
};
forwardButton.Clicked += (s, e) => _webView.GoForward();
var reloadButton = new Button
{
Text = "Reload",
WidthRequest = 70
};
reloadButton.Clicked += (s, e) => _webView.Reload();
var loadHtmlButton = new Button
{
Text = "Load HTML",
WidthRequest = 100
};
loadHtmlButton.Clicked += OnLoadHtmlClicked;
var evalJsButton = new Button
{
Text = "Run JS",
WidthRequest = 80
};
evalJsButton.Clicked += OnEvalJsClicked;
// Navigation bar
var navBar = new HorizontalStackLayout
{
Spacing = 5,
Children = { backButton, forwardButton, reloadButton }
};
// URL bar
var urlBar = new HorizontalStackLayout
{
Spacing = 5,
Children = { _urlEntry, goButton }
};
// Action buttons
var actionBar = new HorizontalStackLayout
{
Spacing = 5,
Children = { loadHtmlButton, evalJsButton }
};
Content = new VerticalStackLayout
{
Padding = 10,
Spacing = 10,
Children =
var ex = e.ExceptionObject as Exception;
Console.WriteLine($"[FATAL] Unhandled exception: {ex?.GetType().Name}: {ex?.Message}");
Console.WriteLine($"[FATAL] Stack trace: {ex?.StackTrace}");
if (ex?.InnerException != null)
{
new Label { Text = "WebView Demo - WebKitGTK", FontSize = 20, FontAttributes = FontAttributes.Bold },
navBar,
urlBar,
_webView,
actionBar,
_statusLabel
Console.WriteLine($"[FATAL] Inner exception: {ex.InnerException.GetType().Name}: {ex.InnerException.Message}");
Console.WriteLine($"[FATAL] Inner stack trace: {ex.InnerException.StackTrace}");
}
};
}
private void Navigate()
{
var url = _urlEntry.Text?.Trim();
if (string.IsNullOrEmpty(url))
return;
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
Console.WriteLine($"[FATAL] Unobserved task exception: {e.Exception?.GetType().Name}: {e.Exception?.Message}");
Console.WriteLine($"[FATAL] Stack trace: {e.Exception?.StackTrace}");
e.SetObserved(); // Prevent crash
};
// Add https:// if not present
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
url = "https://" + url;
Console.WriteLine($"[Program] Starting WebView Demo at {DateTime.Now}");
Console.WriteLine($"[Program] Log file: {logPath}");
_webView.Source = new UrlWebViewSource { Url = url };
_urlEntry.Text = url;
}
private void OnUrlSubmitted(object? sender, EventArgs e)
{
Navigate();
}
private void OnNavigating(object? sender, WebNavigatingEventArgs e)
{
_statusLabel.Text = $"Loading: {e.Url}";
Console.WriteLine($"[WebViewPage] Navigating to: {e.Url}");
}
private void OnNavigated(object? sender, WebNavigatedEventArgs e)
{
_statusLabel.Text = e.Result == WebNavigationResult.Success
? $"Loaded: {e.Url}"
: $"Failed: {e.Result}";
_urlEntry.Text = e.Url;
Console.WriteLine($"[WebViewPage] Navigated: {e.Result} - {e.Url}");
}
private void OnLoadHtmlClicked(object? sender, EventArgs e)
{
var html = @"
<!DOCTYPE html>
<html>
<head>
<title>OpenMaui WebView</title>
<style>
body {
font-family: 'Segoe UI', Arial, sans-serif;
margin: 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
}
h1 {
font-size: 2.5em;
margin-bottom: 20px;
}
p {
font-size: 1.2em;
line-height: 1.6;
}
.feature-list {
background: rgba(255,255,255,0.1);
padding: 20px;
border-radius: 10px;
margin-top: 20px;
}
li {
margin: 10px 0;
font-size: 1.1em;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 15px 30px;
font-size: 1.1em;
border-radius: 5px;
cursor: pointer;
margin-top: 20px;
}
button:hover {
background: #45a049;
}
</style>
</head>
<body>
<h1>Hello from OpenMaui Linux!</h1>
<p>This HTML content is rendered by WebKitGTK inside your .NET MAUI application.</p>
<div class='feature-list'>
<h2>WebView Features:</h2>
<ul>
<li>Full HTML5 support</li>
<li>CSS3 animations and transitions</li>
<li>JavaScript execution</li>
<li>Navigation history (back/forward)</li>
<li>WebGL and canvas support</li>
</ul>
</div>
<button onclick=""alert('Hello from JavaScript!')"">Click Me!</button>
<p style='margin-top: 30px; opacity: 0.8;'>
Powered by WebKitGTK - the same engine used by GNOME Web (Epiphany)
</p>
</body>
</html>";
_webView.Source = new HtmlWebViewSource { Html = html };
_statusLabel.Text = "Loaded custom HTML";
}
private async void OnEvalJsClicked(object? sender, EventArgs e)
{
try
{
var result = await _webView.EvaluateJavaScriptAsync("document.title");
_statusLabel.Text = $"JS Result: {result ?? "(null)"}";
Console.WriteLine($"[WebViewPage] JS Eval result: {result}");
// Create the MAUI app with all handlers registered
var app = MauiProgram.CreateMauiApp();
// Run on Linux platform
LinuxApplication.Run(app, args);
}
catch (Exception ex)
{
_statusLabel.Text = $"JS Error: {ex.Message}";
Console.WriteLine($"[FATAL] Exception in Main: {ex.GetType().Name}: {ex.Message}");
Console.WriteLine($"[FATAL] Stack trace: {ex.StackTrace}");
throw;
}
}
}
// Helper to write to both console and file
class MultiTextWriter : TextWriter
{
private readonly TextWriter[] _writers;
public MultiTextWriter(params TextWriter[] writers) => _writers = writers;
public override System.Text.Encoding Encoding => System.Text.Encoding.UTF8;
public override void Write(char value) { foreach (var w in _writers) w.Write(value); }
public override void WriteLine(string? value) { foreach (var w in _writers) w.WriteLine(value); }
public override void Flush() { foreach (var w in _writers) w.Flush(); }
}

View File

@@ -5,14 +5,11 @@
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>WebViewDemo</RootNamespace>
<RuntimeIdentifier>linux-arm64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>false</PublishSingleFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../OpenMaui.Controls.Linux.csproj" />
<ProjectReference Include="../../maui-linux/OpenMaui.Controls.Linux.csproj" />
</ItemGroup>
</Project>