diff --git a/common/hybrid-blazor-apps/BlazorHybridApps.sln b/common/hybrid-blazor-apps/BlazorHybridApps.sln new file mode 100644 index 00000000..e4c4dd00 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorHybridApps.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31320.298 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebviewAppShared", "WebviewAppShared\WebviewAppShared.csproj", "{0E95EEB3-1734-42A3-A8B7-990BF6184233}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorWpfApp", "BlazorWpfApp\BlazorWpfApp.csproj", "{F84C858B-FA3C-433B-AE42-153BD944A9AC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorWinFormsApp", "BlazorWinFormsApp\BlazorWinFormsApp.csproj", "{16DEAB09-359E-4D58-9D8D-22F59E51F989}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0E95EEB3-1734-42A3-A8B7-990BF6184233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E95EEB3-1734-42A3-A8B7-990BF6184233}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E95EEB3-1734-42A3-A8B7-990BF6184233}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E95EEB3-1734-42A3-A8B7-990BF6184233}.Release|Any CPU.Build.0 = Release|Any CPU + {F84C858B-FA3C-433B-AE42-153BD944A9AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F84C858B-FA3C-433B-AE42-153BD944A9AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F84C858B-FA3C-433B-AE42-153BD944A9AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F84C858B-FA3C-433B-AE42-153BD944A9AC}.Release|Any CPU.Build.0 = Release|Any CPU + {16DEAB09-359E-4D58-9D8D-22F59E51F989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16DEAB09-359E-4D58-9D8D-22F59E51F989}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16DEAB09-359E-4D58-9D8D-22F59E51F989}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16DEAB09-359E-4D58-9D8D-22F59E51F989}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FE65FC7B-0A9C-4934-9C8E-A55A1209D189} + EndGlobalSection +EndGlobal diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/AppState.cs b/common/hybrid-blazor-apps/BlazorWinFormsApp/AppState.cs new file mode 100644 index 00000000..09993ac2 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/AppState.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace BlazorWinFormsApp +{ + public class AppState + { + public int Counter { get; set; } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/BlazorWinFormsApp.csproj b/common/hybrid-blazor-apps/BlazorWinFormsApp/BlazorWinFormsApp.csproj new file mode 100644 index 00000000..799b4ece --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/BlazorWinFormsApp.csproj @@ -0,0 +1,37 @@ + + + + net6.0-windows + WinExe + true + false + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + true + + + + diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.cs b/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.cs new file mode 100644 index 00000000..36a51942 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Windows.Forms; +using Microsoft.AspNetCore.Components.WebView.WindowsForms; +using Microsoft.Extensions.DependencyInjection; + +namespace BlazorWinFormsApp +{ + public partial class Form1 : Form + { + private readonly AppState _appState = new(); + + public Form1() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddBlazorWebView(); + serviceCollection.AddSingleton(_appState); + InitializeComponent(); + + blazorWebView1.HostPage = @"wwwroot\index.html"; + blazorWebView1.Services = serviceCollection.BuildServiceProvider(); + blazorWebView1.RootComponents.Add
("#app"); + } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.designer.cs b/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.designer.cs new file mode 100644 index 00000000..debe24e8 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Form1.designer.cs @@ -0,0 +1,90 @@ +namespace BlazorWinFormsApp +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.blazorWebView1 = new Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(13, 13); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(775, 162); + this.groupBox1.TabIndex = 10; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Native Windows Forms UI"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(28, 68); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(157, 32); + this.label1.TabIndex = 10; + this.label1.Text = "This app shows Telerik UI for Blazor in a native WinForms app."; + + // + // blazorWebView1 + // + this.blazorWebView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.blazorWebView1.Location = new System.Drawing.Point(13, 181); + this.blazorWebView1.Name = "blazorWebView1"; + this.blazorWebView1.Size = new System.Drawing.Size(775, 257); + this.blazorWebView1.TabIndex = 20; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.blazorWebView1); + this.Controls.Add(this.groupBox1); + this.Name = "Form1"; + this.Text = "Blazor Web in Windows Forms"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label1; + private Microsoft.AspNetCore.Components.WebView.WindowsForms.BlazorWebView blazorWebView1; + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Main.razor b/common/hybrid-blazor-apps/BlazorWinFormsApp/Main.razor new file mode 100644 index 00000000..ab62836b --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Main.razor @@ -0,0 +1,16 @@ + +
+ + + Home | + Other +
+ +
+ +

Not found

+

Sorry, there's nothing here.

+
+
+
+
\ No newline at end of file diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Index.razor b/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Index.razor new file mode 100644 index 00000000..a5854c59 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Index.razor @@ -0,0 +1,156 @@ +@page "/" + +@* NOTE: The full namespace for other proejcts and native code is included here to work around this bug: https://github.com/dotnet/aspnetcore/issues/30851 *@ +@inject BlazorWinFormsApp.AppState AppState + +

Telerik UI for Blazor running in a native WinForms app!

+ + +

Grid

+ + + + + + + + + + + + +

Button

+ +Click me + +
+ The button was clicked @(AppState.Counter) times. +
+ +

DatePicker

+@SelectedDate +
+ + +

Chart

+ + + + + + + + + + + + + + + + + + + +@code { + public DateTime Min = new DateTime(2000, 1, 1); + public DateTime Max = new DateTime(2050, 12, 31); + public DateTime? SelectedDate; + + public List GridData { get; set; } + + List ChartSeries1Data { get; set; } = new List(); + List ChartSeries2Data { get; set; } = new List(); + + protected override void OnInitialized() + { + GridData = GetProductData(); + ChartSeries1Data = GetSeriesData(); + ChartSeries2Data = GetSeriesData(); + } + + private List GetProductData(int count = 100) + { + var products = new List(); + + for (var i = 1; i <= count; i++) + { + var product = new Product() + { + ProductId = i, + ProductName = "Product" + i.ToString(), + UnitPrice = (decimal)(i * 3.14), + UnitsInStock = (short)((i * 1) % 9), + Discontinued = i % 3 == 0, + CreatedAt = new DateTime(2019, 1 + (i % 12), 1 + (i % 29)) + }; + + products.Add(product); + } + + return products; + } + + public static List GetSeriesData() + { + List data = new List(); + + for (int i = 1; i <= 3; i++) + { + var dataItem = new ChartSeriesData + { + Product1Sales = i, + Product2Sales = i + 1.123, + Year = new DateTime(2000 + i, 3, i), + SegmentName = $"{i * 100}" + }; + + data.Add(dataItem); + } + + return data; + } + + public void OnClick() + { + AppState.Counter++; + } + + public class Product + { + public Product() + { + } + + public int ProductId { get; set; } + public string ProductName { get; set; } + public decimal? UnitPrice { get; set; } + public short? UnitsInStock { get; set; } + public bool Discontinued { get; set; } + public DateTime? CreatedAt { get; set; } + } + + public class ChartSeriesData + { + public int Product1Sales { get; set; } + public double Product2Sales { get; set; } + public DateTime Year { get; set; } + public string SegmentName { get; set; } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Other.razor b/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Other.razor new file mode 100644 index 00000000..c1653c22 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Pages/Other.razor @@ -0,0 +1,19 @@ +@page "/other" + +@* NOTE: The full namespace for other proejcts and native code is included here to work around this bug: https://github.com/dotnet/aspnetcore/issues/30851 *@ +@using WebviewAppShared + +@inject NavigationManager NavigationManager + +Here is another page. Looks like navigation works. + + + + + +@code { + void BackToHome() + { + NavigationManager.NavigateTo(""); + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/Program.cs b/common/hybrid-blazor-apps/BlazorWinFormsApp/Program.cs new file mode 100644 index 00000000..bf14982f --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/Program.cs @@ -0,0 +1,31 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace BlazorWinFormsApp +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + AppDomain.CurrentDomain.UnhandledException += (sender, error) => + { + MessageBox.Show(text: error.ExceptionObject.ToString(), caption: "Error"); + }; + + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/_Imports.razor b/common/hybrid-blazor-apps/BlazorWinFormsApp/_Imports.razor new file mode 100644 index 00000000..6265c285 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/_Imports.razor @@ -0,0 +1,14 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop + +@using Telerik.Blazor +@using Telerik.Blazor.Components +@using Telerik.Blazor.Services + +@using Telerik.DataSource +@using Telerik.DataSource.Extensions \ No newline at end of file diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/css/app.css b/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/css/app.css new file mode 100644 index 00000000..4f895ce7 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/css/app.css @@ -0,0 +1,18 @@ +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} diff --git a/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/index.html b/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/index.html new file mode 100644 index 00000000..3bf13900 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWinFormsApp/wwwroot/index.html @@ -0,0 +1,43 @@ + + + + + + + Blazor WinForms app + + + + + + + + + +
+ +
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + + + diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml b/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml new file mode 100644 index 00000000..17dc04b5 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml @@ -0,0 +1,10 @@ + + + + + diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml.cs b/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml.cs new file mode 100644 index 00000000..69a54128 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/App.xaml.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Windows; + +namespace BlazorWpfApp +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + private void Application_Startup(object sender, StartupEventArgs e) + { + AppDomain.CurrentDomain.UnhandledException += (sender, error) => + { + MessageBox.Show(error.ExceptionObject.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error); + }; + } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/AppState.cs b/common/hybrid-blazor-apps/BlazorWpfApp/AppState.cs new file mode 100644 index 00000000..019ef33a --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/AppState.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace BlazorWpfApp +{ + public class AppState + { + public int Counter { get; set; } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/BlazorWpfApp.csproj b/common/hybrid-blazor-apps/BlazorWpfApp/BlazorWpfApp.csproj new file mode 100644 index 00000000..b0c65e5e --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/BlazorWpfApp.csproj @@ -0,0 +1,30 @@ + + + + net6.0-windows + WinExe + true + false + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/Main.razor b/common/hybrid-blazor-apps/BlazorWpfApp/Main.razor new file mode 100644 index 00000000..ab62836b --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/Main.razor @@ -0,0 +1,16 @@ + +
+ + + Home | + Other +
+ +
+ +

Not found

+

Sorry, there's nothing here.

+
+
+
+
\ No newline at end of file diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml b/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml new file mode 100644 index 00000000..61998248 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml.cs b/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml.cs new file mode 100644 index 00000000..18e64153 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/MainWindow.xaml.cs @@ -0,0 +1,34 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Windows; +using Microsoft.Extensions.DependencyInjection; + +namespace BlazorWpfApp +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + private readonly AppState _appState = new(); + + public MainWindow() + { + var services = new ServiceCollection(); + services.AddBlazorWebView(); + services.AddSingleton(_appState); + + // necessary for localization + // services.AddTelerikBlazor(); + + Resources.Add("services", services.BuildServiceProvider()); + + InitializeComponent(); + } + } + + // Workaround for compiler error "error MC3050: Cannot find the type 'local:Main'" + // It seems that, although WPF's design-time build can see Razor components, its runtime build cannot. + public partial class Main { } +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Index.razor b/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Index.razor new file mode 100644 index 00000000..093309ac --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Index.razor @@ -0,0 +1,156 @@ +@page "/" + +@* NOTE: The full namespace for other proejcts and native code is included here to work around this bug: https://github.com/dotnet/aspnetcore/issues/30851 *@ +@inject BlazorWpfApp.AppState AppState + +

Telerik UI for Blazor running in a native WPF app!

+ + +

Grid

+ + + + + + + + + + + + +

Button

+ +Click me + +
+ The button was clicked @(AppState.Counter) times. +
+ +

DatePicker

+@SelectedDate +
+ + +

Chart

+ + + + + + + + + + + + + + + + + + + +@code { + public DateTime Min = new DateTime(2000, 1, 1); + public DateTime Max = new DateTime(2050, 12, 31); + public DateTime? SelectedDate; + + public List GridData { get; set; } + + List ChartSeries1Data { get; set; } = new List(); + List ChartSeries2Data { get; set; } = new List(); + + protected override void OnInitialized() + { + GridData = GetProductData(); + ChartSeries1Data = GetSeriesData(); + ChartSeries2Data = GetSeriesData(); + } + + private List GetProductData(int count = 100) + { + var products = new List(); + + for (var i = 1; i <= count; i++) + { + var product = new Product() + { + ProductId = i, + ProductName = "Product" + i.ToString(), + UnitPrice = (decimal)(i * 3.14), + UnitsInStock = (short)((i * 1) % 9), + Discontinued = i % 3 == 0, + CreatedAt = new DateTime(2019, 1 + (i % 12), 1 + (i % 29)) + }; + + products.Add(product); + } + + return products; + } + + public static List GetSeriesData() + { + List data = new List(); + + for (int i = 1; i <= 3; i++) + { + var dataItem = new ChartSeriesData + { + Product1Sales = i, + Product2Sales = i + 1.123, + Year = new DateTime(2000 + i, 3, i), + SegmentName = $"{i * 100}" + }; + + data.Add(dataItem); + } + + return data; + } + + public void OnClick() + { + AppState.Counter++; + } + + public class Product + { + public Product() + { + } + + public int ProductId { get; set; } + public string ProductName { get; set; } + public decimal? UnitPrice { get; set; } + public short? UnitsInStock { get; set; } + public bool Discontinued { get; set; } + public DateTime? CreatedAt { get; set; } + } + + public class ChartSeriesData + { + public int Product1Sales { get; set; } + public double Product2Sales { get; set; } + public DateTime Year { get; set; } + public string SegmentName { get; set; } + } +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Other.razor b/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Other.razor new file mode 100644 index 00000000..c1653c22 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/Pages/Other.razor @@ -0,0 +1,19 @@ +@page "/other" + +@* NOTE: The full namespace for other proejcts and native code is included here to work around this bug: https://github.com/dotnet/aspnetcore/issues/30851 *@ +@using WebviewAppShared + +@inject NavigationManager NavigationManager + +Here is another page. Looks like navigation works. + + + + + +@code { + void BackToHome() + { + NavigationManager.NavigateTo(""); + } +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/_Imports.razor b/common/hybrid-blazor-apps/BlazorWpfApp/_Imports.razor new file mode 100644 index 00000000..48b02b34 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/_Imports.razor @@ -0,0 +1,18 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop + +@using System.Globalization +@using System.Collections.Generic; +@using System.Text.Json + +@using Telerik.Blazor +@using Telerik.Blazor.Components +@using Telerik.Blazor.Services + +@using Telerik.DataSource +@using Telerik.DataSource.Extensions diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/css/app.css b/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/css/app.css new file mode 100644 index 00000000..4f895ce7 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/css/app.css @@ -0,0 +1,18 @@ +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + +#blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; +} diff --git a/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/index.html b/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/index.html new file mode 100644 index 00000000..6e85e369 --- /dev/null +++ b/common/hybrid-blazor-apps/BlazorWpfApp/wwwroot/index.html @@ -0,0 +1,43 @@ + + + + + + + Blazor WPF app + + + + + + + + + +
+ +
+ An unhandled error has occurred. + Reload + 🗙 +
+ + + + + diff --git a/common/hybrid-blazor-apps/README.md b/common/hybrid-blazor-apps/README.md new file mode 100644 index 00000000..967e6d13 --- /dev/null +++ b/common/hybrid-blazor-apps/README.md @@ -0,0 +1,33 @@ +# Hybrid Blazor Apps + +With .NET 6 Previews an exciting new feature became available - `WebView` for native apps that is dedicated to running Blazor Web applications. + +The samples in this project showcase Telerik UI for Blazor web components running in this hybrid scenarios inside native WPF and WinForms apps. + +## Key Points + +Comments in the code offer some more insights, the key points pertaining to the Telerik components are: +* The native app project needs to reference the Telerik UI for Blazor package. +* You add the Telerik static assets in the `index.html` file as usual. +* The `TelerikRootComponent` should be added as a top-level component in the Blazor app. Since layouts are not supported yet, in this sample we add it to the `Main.razor` component. + * Make sure that the Telerik root component matches the webview viewport. In this sample, we need to remove the default margin and padding from the body to ensure the content matches the viewport. An extra element in the layout provides paddings. + * It is expected that layouts should be supported in the future so you would be able to set this up in the same way as with regular Blazor web apps. + +These sample apps contain just a few commonly used Telerik components such as a grid, chart, button, date picker to showcase things work. + +## How to run + +1. Install [.NET 6.0 Preview 4](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-4/). + * Note: It requires Visual Studio Preview for Windows or for Mac. +2. Install [WebView](https://devblogs.microsoft.com/aspnet/asp-net-core-updates-in-net-6-preview-3/#blazorwebview-controls-for-wpf-windows-forms). +3. Make sure you have WinForms/WPF/etc. installed. + * Note: they usually come as workloads through the Visual Studio installer, if you have not activated them previously go to the VS Installer and add them. +4. Make sure you have the latest Telerik UI for Blazor version (2.24.0) in [your nuget feed](https://docs.telerik.com/blazor-ui/installation/nuget). +5. Run an app - either the WinForms, or WPF one. + + +## Known Issues + +* The Blazor WebViews seem to throw exceptions about a disposed rendered when the `Trial` version of Telerik components is used. The Commercial version seems to work fine. Considering that `.NET 6 Preview4` (the current target of this sample) this is an early preview of .NET 6, this is a problem we would investigate if it remains in the official .NET 6 version. + + diff --git a/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor b/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor new file mode 100644 index 00000000..526afeb7 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor @@ -0,0 +1,17 @@ +@using Microsoft.AspNetCore.Components.Web + +@namespace WebviewAppShared + +

Counter

+ +

The current count is: @currentCount

+ + +@code { + int currentCount = 1; + + void IncrementCount() + { + currentCount++; + } +} \ No newline at end of file diff --git a/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor.cs b/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor.cs new file mode 100644 index 00000000..ff1077d3 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/Counter.razor.cs @@ -0,0 +1,4 @@ +namespace WebviewAppShared +{ + public partial class Counter { } +} \ No newline at end of file diff --git a/common/hybrid-blazor-apps/WebviewAppShared/ExampleJsInterop.cs b/common/hybrid-blazor-apps/WebviewAppShared/ExampleJsInterop.cs new file mode 100644 index 00000000..e4f19d8c --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/ExampleJsInterop.cs @@ -0,0 +1,39 @@ +using Microsoft.JSInterop; +using System; +using System.Threading.Tasks; + +namespace WebviewAppShared +{ + // This class provides an example of how JavaScript functionality can be wrapped + // in a .NET class for easy consumption. The associated JavaScript module is + // loaded on demand when first needed. + // + // This class can be registered as scoped DI service and then injected into Blazor + // components for use. + + public class ExampleJsInterop : IAsyncDisposable + { + private readonly Lazy> moduleTask; + + public ExampleJsInterop(IJSRuntime jsRuntime) + { + moduleTask = new(() => jsRuntime.InvokeAsync( + "import", "./_content/WebviewAppShared/exampleJsInterop.js").AsTask()); + } + + public async ValueTask Prompt(string message) + { + var module = await moduleTask.Value; + return await module.InvokeAsync("showPrompt", message); + } + + public async ValueTask DisposeAsync() + { + if (moduleTask.IsValueCreated) + { + var module = await moduleTask.Value; + await module.DisposeAsync(); + } + } + } +} diff --git a/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor b/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor new file mode 100644 index 00000000..4041aa40 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor @@ -0,0 +1,3 @@ +
+ This component is defined in the WebviewAppShared package. +
diff --git a/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor.css b/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor.css new file mode 100644 index 00000000..c6afca40 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/SharedComponent.razor.css @@ -0,0 +1,6 @@ +.my-component { + border: 2px dashed red; + padding: 1em; + margin: 1em 0; + background-image: url('background.png'); +} diff --git a/common/hybrid-blazor-apps/WebviewAppShared/WebviewAppShared.csproj b/common/hybrid-blazor-apps/WebviewAppShared/WebviewAppShared.csproj new file mode 100644 index 00000000..b4e91714 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/WebviewAppShared.csproj @@ -0,0 +1,19 @@ + + + + + net6.0 + + + + + + + + + + + + diff --git a/common/hybrid-blazor-apps/WebviewAppShared/_Imports.razor b/common/hybrid-blazor-apps/WebviewAppShared/_Imports.razor new file mode 100644 index 00000000..77285129 --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/_Imports.razor @@ -0,0 +1 @@ +@using Microsoft.AspNetCore.Components.Web diff --git a/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/background.png b/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/background.png new file mode 100644 index 00000000..e15a3bde Binary files /dev/null and b/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/background.png differ diff --git a/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/exampleJsInterop.js b/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/exampleJsInterop.js new file mode 100644 index 00000000..ea8d76ad --- /dev/null +++ b/common/hybrid-blazor-apps/WebviewAppShared/wwwroot/exampleJsInterop.js @@ -0,0 +1,6 @@ +// This is a JavaScript module that is loaded on demand. It can export any number of +// functions, and may import other JavaScript modules if required. + +export function showPrompt(message) { + return prompt(message, 'Type anything here'); +}