【炫丽】从0开始做一个WPF+Blazor对话小程序( 三 )

我们给整个窗体客户端区域加了一个背景Border(您可以去掉Border背景色,点击界面按钮试试) , 然后又套了一个Grid,用于放置自定义的标题栏(标题和窗体控制按钮)和BlazorWebView(用于渲染Razor组件的浏览器组件) , 下面是窗体控制按钮的响应事件:
using Microsoft.Extensions.DependencyInjection;using System.Windows;namespace WPFBlazorChat;public partial class MainWindow : Window{public MainWindow(){InitializeComponent();var serviceCollection = new ServiceCollection();serviceCollection.AddWpfBlazorWebView();Resources.Add("services", serviceCollection.BuildServiceProvider());}private void MoveWindow_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e){if (e.ClickCount == 1){this.DragMove();}else{MaximizeWindow_Click(null, null);}}private void CloseWindow_Click(object sender, RoutedEventArgs e){this.Close();}private void MinimizeWindow_Click(object sender, RoutedEventArgs e){this.WindowState = WindowState.Minimized;}private void MaximizeWindow_Click(object sender, RoutedEventArgs e){this.WindowState = this.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;}}代码简单,处理了窗体最小化、窗体最大化(还原)、关闭、标题栏双击窗体最大化(还原),上面的实现不是一个完美的自定义窗体实现,至少有这两个问题:

  • 当您尝试最大化后,窗体铺满了整个操作系统桌面(连任务栏区域也占用了);
  • 窗体任务栏两个圆角未生效(红色矩形框选的部分),即窗体下面的两个圆角,站长未找到让BlazorWebView出现圆角的属性或其他方法;标题栏区域(绿色矩形框选的部分)是WPF控件,所以圆角显示正常 。

【炫丽】从0开始做一个WPF+Blazor对话小程序

文章插图
在后面的3.4小节,站长使用一个第三库实现了窗体圆角问题,更多比较好的WPF自定义窗体实现可看这篇文章:WPF三种自定义窗体的实现,本小节中示例源码在这WPF自定义窗体 。
3.2 WPF异形窗体异形窗体的需求 , 使用WPF实现是比较方便的,本来打算写写的,感觉偏离主题太远了 , 给篇文章自行看看吧:WPF异形窗体演示,文中异形窗体效果如下:
【炫丽】从0开始做一个WPF+Blazor对话小程序

文章插图
下面介绍将窗体的标题栏也放Razor组件中实现的方式 。
3.3 Blazor实现自定义窗体效果上面使用了WPF制作自定义窗体,有没有这种需求,把菜单放置到标题栏?这个简单 , WPF能很好实现 。
如果放Tab类控件呢?Tab Header是在标题栏显示,TabItem是在客户端区域,Tab HeaderTabItem风格统一,在一套代码里面实现和维护也方便,那么在WPF+Blazor混合开发的情况怎么实现呢?相信通过本节Razor组件实现标题栏的介绍 , 你能做出来 。
MainWindow.xaml恢复代码 , 只设置隐藏WPF默认窗体边框 , 并给BlazorWebView套一层背景:
【炫丽】从0开始做一个WPF+Blazor对话小程序

文章插图
后面的代码有参考 BlazorDesktopWPF-CustomTitleBar 开源项目实现 。
我们把标题栏做到Counter.razor组件,即标题栏、客户区放一个组件里,当然你也可以分离,这里我们方便演示:
Counter.razor
@using WPFBlazorChat.Services<div class="titlebar" @ondblclick="WindowService.Maximize" @onmouseup="WindowService.StopMove" @onmousedown="WindowService.StartMove"><button class="titlebar-btn" onclick="alert('js alert: navigation pressed');"><img src="https://www.huyubaike.com/biancheng/svg/navigation.svg" /></button><div class="window-title">测试窗体标题</div><div style="flex-grow:1"></div><button class="titlebar-btn" onclick="alert('js alert: settings pressed');"><img src="https://www.huyubaike.com/biancheng/svg/settings.svg" /></button><button class="titlebar-btn" @onclick="WindowService.Minimize"><img src="https://www.huyubaike.com/biancheng/svg/minimize.svg" /></button><button class="titlebar-btn" @onclick="WindowService.Maximize">@if (WindowService.IsMaximized()){<img src="https://www.huyubaike.com/biancheng/svg/restore.svg" />}else{<img src="https://www.huyubaike.com/biancheng/svg/maximize.svg" />}</button><button class="titlebar-cbtn" @onclick="()=>WindowService.Close(false)"><img src="https://www.huyubaike.com/biancheng/svg/dismiss.svg" /></button></div><p>好开心,你点我了 , 现在是:<span style="color: red;">@currentCount</span></p><button class="btn btn-primary" @onclick="IncrementCount">快快点我</button>@code {private int currentCount = 0;protected override void OnInitialized(){WindowService.Init();base.OnInitialized();}private void IncrementCount(){currentCount++;}}

推荐阅读