前言
昨天写了一篇介绍 Blazor Hybrid 技术的文章,但限于篇幅,一些问题未能深入探讨。今天,我想继续记录使用 Blazor Hybrid 过程中遇到的几个问题,以及这个技术目前的一些局限性。
文件拖放事件的局限
Blazor Hybrid 的运行环境是 WebView,这导致了在处理文件拖放时出现了一些限制。在传统桌面应用中(如 WinForms 或 WPF),开发者可以直接捕获拖放事件,并获得文件的完整路径。但在 Blazor 中,拖放事件只能像浏览器中一样处理,意味着我们只能获得上传文件的流,而无法获取文件的实际路径。
这对于那些需要直接访问文件路径的功能(如Clipify中把视频拖进去处理)带来了很大的不便。
冗余代码(不是)
看了项目代码的同学可能会发现,FormMain.cs里还有处理拖放事件的代码,不过实际上并没有生效。
// 处理拖动进入事件,检测是否为文件 private void blazorWebView1_DragEnter(object sender, DragEventArgs e) { Console.WriteLine("drag enter"); if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // 改变鼠标图标,表示可以拖放 e.Effect = DragDropEffects.Copy; } else { e.Effect = DragDropEffects.None; } } // 处理拖放事件,获取文件路径 private void blazorWebView1_DragDrop(object sender, DragEventArgs e) { Console.WriteLine("drag drop"); if (e.Data.GetDataPresent(DataFormats.FileDrop)) { var files = (string[]?)e.Data.GetData(DataFormats.FileDrop); // 这里只处理单个文件,当然你也可以处理多个文件 if (files?.Length > 0) { var filePath = files[0]; // 获取拖放的文件路径 MessageBox.Show($"文件路径: {filePath}"); // 在这里你可以将文件路径传递给 Blazor 或其他处理逻辑 } } } // 处理 DragOver 事件,防止系统默认行为 private void blazorWebView1_DragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { e.Effect = DragDropEffects.Copy; // 明确允许拖放文件 } else { e.Effect = DragDropEffects.None; } }
解决方案
目前的解决办法有限,根据查找到的资料和我自己的探索,有以下几种:
- 在需要拖放的时候,使用一个WinForms原生控件覆盖webview
- 使用hook技术,拦截webview的拖放事件
- 重写微软提个的这个 Blazor Webview 控件,自己实现
WndProc
方法
第3种方法的代码大概是这样(未验证)
public class CustomBlazorWebView : BlazorWebView { protected override void WndProc(ref Message m) { const int WM_DROPFILES = 0x233; // 拖放文件消息 if (m.Msg == WM_DROPFILES) { // 处理文件拖放逻辑 // 你可以在这里调用你的拖放事件处理逻辑 // 阻止消息传递,避免系统默认处理文件 return; } base.WndProc(ref m); } }
PS:我嫌麻烦就还没去折腾实现这个拖放功能,目前只做了打开对话框选择文件。
社区反馈
同样的问题我在 Github issues 和 Stack Overflow 之类的平台也有看到很多人提出,不过看起来微软并不想解决这些问题。
相关链接:
- https://github.com/MicrosoftEdge/WebView2Feedback/issues/2805
- https://github.com/dotnet/maui/issues/2205
- https://stackoverflow.com/questions/73197778/net-maui-blazor-app-drag-and-drop-impossible
桌面应用体验差异
Blazor Hybrid 尽管以桌面应用的形式运行,但表现更接近于网页应用。
浏览器的快捷键
一个明显的例子是,在 WebView 中按下 F5 键时,页面会像浏览器一样刷新,这种行为显然不符合传统桌面软件的用户体验。
在类似的技术中,如 Electron,也存在类似的局限。但不同的是,Electron 提供了更多对浏览器行为的控制手段,可以阻止或重定义这些行为,而 Blazor Hybrid 目前则没有这些更细粒度的控制能力。
从桌面应用的角度来看,用户希望获得一致且原生的操作体验,因此这些细微的差异可能会影响开发者对 Blazor Hybrid 应用的期望。
窗口大小调整的表现
在使用 Blazor Hybrid 时,我还注意到窗口大小调整的流畅度问题。相比起原生的桌面应用,Blazor Hybrid 的表现不尽如人意。当用户调整窗口大小时,界面偶尔会出现黑边或画面撕裂的现象。
这种问题不仅在 Blazor Hybrid 中出现,实际上,在浏览器(chrome)和 Electron 应用(QQ)中,我也观察到类似的问题。
为了更深入地理解这个现象,我还测试了 C++ 原生应用,结果发现原生应用在调整窗口大小时相对来说更流畅,没有出现黑边或撕裂的问题。
我猜测造成这种差异的原因可能在于,Blazor Hybrid 和 Electron 依赖 WebView 作为渲染引擎,而 WebView 的渲染机制在处理窗口大小调整时不如原生 UI 渲染引擎高效。
小结
Blazor Hybrid 是一个非常有潜力的技术,它让 C# 开发者能够轻松地构建跨平台桌面应用。
然而,在使用过程中,我发现了一些需要关注的问题,尤其是在拖放事件、桌面应用行为一致性和窗口大小调整表现上。
这些问题目前可能对开发者造成一定的困扰,也影响了用户体验的流畅性。
接下来我会找时间试一下 Electron 和 wails 的开发体验,进一步探索 Blazor Hybrid 在桌面软件开发中的优势。