();
return builder.Build();
```
**第三步:在 Blazor 中使用共享服务**
修改 `Components/Pages/Counter.razor`,让它使用我们新的共享服务。
```html
@page "/counter"
@inject AppState AppState
@implements IDisposable
Counter
Counter
Current count: @AppState.Counter
@code {
protected override void OnInitialized()
{
// 订阅状态变更事件,以便在状态变化时刷新UI
AppState.OnStateChanged += StateHasChanged;
}
private void IncrementCount()
{
AppState.IncrementCounter();
}
public void Dispose()
{
// 组件销毁时取消订阅,防止内存泄漏
AppState.OnStateChanged -= StateHasChanged;
}
}
```
**第四步:在原生页面中使用和修改共享状态**
现在,我们让原生页面也能消费和修改这个共享状态。
1. **注入服务**: 修改 `NativeContentPage.xaml.cs` 的构造函数以接收 `AppState` 服务。
```csharp
// NativeViews/NativeContentPage.xaml.cs
using MauiHybridAppNet8.Services; // 添加 using
public partial class NativeContentPage : ContentPage, IDisposable
{
private readonly AppState _appState;
public NativeContentPage(AppState appState)
{
InitializeComponent();
_appState = appState;
// 订阅事件并更新UI
_appState.OnStateChanged += UpdateUI;
UpdateLabelText(); // 初始化文本
}
private void UpdateUI()
{
// 确保在UI线程上更新
MainThread.BeginInvokeOnMainThread(UpdateLabelText);
}
private void UpdateLabelText()
{
StateLabel.Text = $"当前共享计数值: {_appState.Counter}";
}
private void OnUpdateButtonClicked(object sender, EventArgs e)
{
// 从原生代码修改共享状态
_appState.IncrementCounter();
}
private async void OnBackButtonClicked(object sender, EventArgs e)
{
await Navigation.PopAsync();
}
public void Dispose()
{
_appState.OnStateChanged -= UpdateUI;
}
}
```
现在,您的应用程序已经完全配置好了!您可以:
1. 在 Blazor 的 Counter 页面增加计数。
2. 导航到原生页面,会看到计数值已经同步。
3. 在原生页面点击按钮增加计数。
4. 返回 Blazor 页面,会发现计数值也同步更新了。
这个使用 .NET 8 编写的例子展示了 Blazor Hybrid 架构的强大之处,它通过现代的依赖注入和服务模式,实现了 Web 技术和原生平台之间的无缝集成。
### 什么是 .NET MAUI Blazor?
.NET MAUI Blazor,也称为 **Blazor Hybrid**,是一种开发模式,它允许您将基于 Web 技术的 Blazor 组件嵌入到原生的 .NET MAUI 应用程序中。
简单来说,您可以:
* **使用 Web 技术构建原生应用界面**:利用 C#、HTML 和 CSS 来创建桌面和移动应用的 UI,就像开发网站一样。
* **获得原生应用的全部能力**:您的应用程序不是运行在浏览器沙箱中,而是作为一个真正的原生应用进程运行。这意味着它可以完全访问设备的所有原生功能,如文件系统、传感器、摄像头、蓝牙等。
它完美地结合了 **Web 开发的灵活性** 和 **原生应用的强大功能**。
### 核心工作原理:BlazorWebView
.NET MAUI Blazor 的核心是 `BlazorWebView` 控件。这是一个特殊的 .NET MAUI 控件,它的作用是在原生应用内部承载一个嵌入式的 Web 视图,并在其中渲染您的 Blazor 组件。
**工作流程如下**:
1. 您的 .NET MAUI 应用启动时,会创建一个窗口。
2. `BlazorWebView` 控件在这个窗口内初始化。
3. 它会加载您的 Blazor 应用所需的静态资源(HTML, CSS, JavaScript)。
4. 您的 C# Blazor 组件代码(`.razor` 文件)在 .NET 进程中直接执行。
5. Blazor 运行时通过一个高效的本地互操作通道,将 UI 的渲染指令发送给 `BlazorWebView`。
6. `BlazorWebView` 将这些指令转换为原生 Web 视图可以理解的内容并显示出来。
**关键点**:所有代码,包括 UI 逻辑、业务逻辑和原生 API 调用,都运行在同一个 .NET 进程中。这与将网站打包成应用的方案(如 PWA 或 Cordova)有本质区别,后者通常受限于浏览器沙箱。
### 使用 .NET MAUI Blazor 的主要优势
1. **代码重用和技能复用**
* **共享组件**:您可以为 Web 应用 (Blazor Server/WASM) 和原生桌面/移动应用 (.NET MAUI Blazor) 创建一套共用的 UI 组件库 (RCL)。
* **技能复用**:熟悉 Blazor、ASP.NET Core 或任何 Web 开发技术的团队可以快速上手构建原生应用,无需学习特定于平台的 UI 框架(如 XAML、SwiftUI 或 Jetpack Compose)。
2. **完全访问原生平台 API**
* 由于代码运行在原生进程中,您可以直接调用 .NET MAUI 提供的所有跨平台 API,或者通过条件编译编写特定于平台(Windows, Android, iOS, macOS)的代码。
* 例如,从一个 Blazor 组件的 C# 代码中,您可以轻松地调用 `Geolocation.GetLocationAsync()` 来获取设备位置,或使用 `FileSystem.Current.AppDataDirectory` 访问应用数据目录。
3. **丰富的生态系统**
* 您可以利用庞大的 .NET 生态系统,包括数以万计的 NuGet 包。
* 同时,您也可以使用为 Blazor 设计的各种 UI 组件库,如 MudBlazor、Telerik UI for Blazor 等。
4. **现代化和渐进式迁移**
* 对于希望现代化其老旧桌面应用(如 Windows Forms 或 WPF)的团队来说,.NET MAUI Blazor 提供了一个优秀的路径。 他们可以在现有应用中嵌入 `BlazorWebView`,逐步用现代的 Web UI 替换旧的 UI,而无需完全重写。
### 如何使用 .NET MAUI Blazor
#### 1. 项目类型
* **.NET MAUI Blazor App**:这是最常见的模板。它创建一个完整的 .NET MAUI 应用,其主界面由一个全屏的 `BlazorWebView` 构成。整个应用的 UI 几乎完全由 Blazor 组件驱动。
* **.NET MAUI App + BlazorWebView**:您可以从一个标准的 .NET MAUI 项目开始,然后在任何原生页面(ContentPage)的布局中,像添加其他原生控件(如 `Button` 或 `Label`)一样,添加一个 `BlazorWebView` 控件。这允许您在一个页面上混合使用原生 UI 控件和 Blazor Web 视图。
#### 2. 项目结构的关键文件
* `MauiProgram.cs`: 应用的入口点。在这里,您需要注册 Blazor 服务,使用 `builder.Services.AddMauiBlazorWebView()`。
* `MainPage.xaml`: 默认情况下,这个页面包含一个 `BlazorWebView` 控件。
* `wwwroot/index.html`: Blazor 应用的宿主 HTML 页面。它通常非常简单,只包含一个根元素(如 ``)和一个 Blazor 脚本引用。
* `Components/`: 这个文件夹(或 `Pages/` 和 `Shared/` 在旧模板中)存放您所有的 Blazor Razor 组件。
#### 3. Blazor 与原生代码的交互
这是混合应用开发的核心。主要通过 **依赖注入 (Dependency Injection)** 和 **共享服务** 来实现。
**场景示例:从 Blazor 组件中触发原生弹窗**
1. **创建服务接口和实现**
```csharp
// 定义一个服务接口
public interface INativeDialogService
{
Task ShowAlertAsync(string title, string message, string cancel);
}
// 在 MAUI 项目中实现它
public class NativeDialogServiceImpl : INativeDialogService
{
public Task ShowAlertAsync(string title, string message, string cancel)
{
// App.Current.MainPage 是对原生页面根的引用
return App.Current.MainPage.DisplayAlert(title, message, cancel);
}
}
```
2. **注册服务**
在 `MauiProgram.cs` 中注册这个服务:
```csharp
builder.Services.AddSingleton();
```
3. **在 Blazor 组件中注入和使用**
```html
@page "/native-test"
@inject INativeDialogService DialogService
与原生功能交互
@code {
private async Task ShowNativeAlert()
{
await DialogService.ShowAlertAsync("来自 Blazor", "这是一个由原生 UI 呈现的弹窗!", "好的");
}
}
```
通过这种模式,您的 Blazor 代码保持了平台无关性(它只知道 `INativeDialogService`),而具体的原生实现则被封装在 .NET MAUI 项目中。
### 总结
.NET MAUI Blazor 是一个功能强大的框架,它为 .NET 开发者开辟了一条使用 Web 技术构建全功能、高性能原生跨平台应用的新道路。如果您来自 Web 开发背景,或者希望在多个平台(Web、桌面、移动)之间最大化地共享 UI 和业务逻辑代码,那么 .NET MAUI Blazor 是一个非常值得考虑的选择。