- A+
所属分类:.NET技术
下面我们将讲解在WPF中使用Blazor,并且使用Blazor做一些文件编辑操作,下面是需要用到的东西
- WPF
- Blazor
- Masa Blazor
- Monaco
安装Masa Blazor模板
使用CMD
指令安装模板
dotnet new install MASA.Template
新建Masa Blazor WPF App
-
找到如图的模板,然后点击下一步
-
下一步,新建项目名称
FileEditor
添加Monaco
- 打开
wwwroot/index.html
,并且引用Monaco的依赖,将一下依赖添加到body里面的最尾部。
<script> var require = { paths: { 'vs': 'https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs' } }; </script> <script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/loader.js"></script> <script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.nls.js"></script> <script src="https://cdn.masastack.com/npm/monaco-editor/0.34.1/min/vs/editor/editor.main.js"></script>
- 新建
Pages/Index.razor.cs
文件
using System.IO; using System.Text; using Masa.Blazor; using Masa.Blazor.Presets; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace FileEditor.Pages; public partial class Index : IDisposable { /// <summary> /// 文本内容 /// </summary> private string value; private MMonacoEditor _editor; private DotNetObjectReference<Index>? _objRef; /// <summary> /// 定义Monaco的初始配置 /// </summary> private object options = new { language = "md", // 设置语法 automaticLayout = true, // 高度自适应 theme = "vs-dark", // 主题 }; private string fullName; protected override void OnInitialized() { _objRef = DotNetObjectReference.Create(this); } /// <summary> /// 具体文件路径 /// </summary> [Parameter] [CascadingParameter(Name = nameof(FullName))] public string FullName { get => fullName; set { fullName = value; UpdateValue(); } } /// <summary> /// Monaco初始化事件 /// </summary> private async Task InitMonaco() { // 监听CTRL+S 2097 = CTRL+S 快捷键 // 调用Monaco的Command,传递当前对象,并且指定当触发快捷键的时候调用当签对象的指定方法。 await _editor.AddCommandAsync(2097, _objRef, nameof(SaveValue)); } /// <summary> /// 更新value /// </summary> private void UpdateValue() { if (string.IsNullOrEmpty(fullName)) { return; } var info = new FileInfo(fullName); if (!info.Exists) return; using var fileStream = info.OpenText(); value = fileStream.ReadToEnd(); } /// <summary> /// 更新文件内容 /// </summary> [JSInvokable] public async Task SaveValue() { try { await using var fileStream = File.OpenWrite(fullName); fileStream.Position = 0; await fileStream.WriteAsync(Encoding.UTF8.GetBytes(value)); fileStream.Close(); } catch (Exception e) { await PopupService.EnqueueSnackbarAsync(new SnackbarOptions() { Title = "保存文件错误", Content = e.Message }); } } public void Dispose() { _editor.Dispose(); _objRef?.Dispose(); } }
在Index.razor.cs
文件中我们实现了拦截FullName的set,当被set的时候说明上级组件选择了文件并且通过CascadingParameter
传递了参数到当前组件。
并且对于当前的Value进行更新,
打开Index.razor
@page "/" @inject IPopupService PopupService <MMonacoEditor InitCompleteHandle="async () => await InitMonaco()" @bind-Value="value" Height="@("100%")" EditorOptions="options" @ref="_editor"> </MMonacoEditor>
我们对于cs的一些方法和参数进行了绑定,并且bind-value了value
的值,我们在cs
文件中更新了value
就自动更新了UI的显示的值。
然后我们打开Shared/MainLayout.razor
文件添加打开文件选择器,从而选择文件。
@using Microsoft.Win32 @inherits LayoutComponentBase <MApp> <MAppBar App> <MAppBarNavIcon @onclick="() => _drawer = !_drawer"></MAppBarNavIcon> <MToolbarTitle>FileEditor</MToolbarTitle> <MButton OnClick="OpenFile">打开文件</MButton> <MSpacer></MSpacer> <MButton Text Color="primary" Target="_blank" Href="https://docs.masastack.com/blazor/introduction/why-masa-blazor">About</MButton> </MAppBar> <MNavigationDrawer App @bind-Value="_drawer"> <MList Nav Routable> <MListItem Href="/" ActiveClass="primary--text"> <MListItemIcon> <MIcon>mdi-home</MIcon> </MListItemIcon> <MListItemContent> <MListItemTitle>Home</MListItemTitle> </MListItemContent> </MListItem> <MListItem Href="/counter" ActiveClass="primary--text"> <MListItemIcon> <MIcon>mdi-plus</MIcon> </MListItemIcon> <MListItemContent> <MListItemTitle>Counter</MListItemTitle> </MListItemContent> </MListItem> <MListItem Href="/fetchdata" ActiveClass="primary--text"> <MListItemIcon> <MIcon>mdi-list-box</MIcon> </MListItemIcon> <MListItemContent> <MListItemTitle>Fetch data</MListItemTitle> </MListItemContent> </MListItem> </MList> </MNavigationDrawer> <MMain> <MContainer Fluid Style="height: 100%"> <CascadingValue Value="fullName" Name="FullName"> <MErrorHandler> @Body </MErrorHandler> </CascadingValue> </MContainer> </MMain> </MApp> @code { private bool? _drawer; private string fullName; private void OpenFile() { var openFileDialog = new OpenFileDialog(); openFileDialog.Title = "请选择您的文件"; openFileDialog.Filter = "文本文件 (*.txt, *.md)|*.txt;*.md"; bool? result = openFileDialog.ShowDialog(); if (result == true) { fullName = openFileDialog.FileName; } } }
在这里我们将使用Microsoft.Win32.OpenFileDialog
打开文件选择器,并且指定选择文件的类型,
当前文件选择器返回true,则fullName
的值,fullName
则会通过CascadingValue
组件的绑定传递到<CascadingValue></CascadingValue>
内的所有子组件。
下面我们看看实际使用效果。
技术交流
qq群:452761192
wx:wk28u9123456789(请备注技术交流)
源码下载地址:https://code-token.oss-cn-beijing.aliyuncs.com/FileEditor.zip