下麵我們將講解在WPF中使用Blazor,並且使用Blazor做一些文件編輯操作,下麵是需要用到的東西 - WPF - Blazor - Masa Blazor - Monaco ## 安裝Masa Blazor模板 使用`CMD`指令安裝模板 ```shell dotnet new install ...
下麵我們將講解在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