あきちゃんの飽き飽き備忘録

ほぼ死んでるブログ

Blazor+RadzenでUserControl

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

今回はBlazor+RadzenでUserControlについて書きます。

それでは早速・・・Blazor+RadzenでUserControl

Lesson.1 事の発端

Blazor+RadzenでUserControl作ろうとしたらデータバインドでだいぶ苦戦しました。

なので書き残しておこうと思います。

Lesson.2 コンポーネントの作成

Blazorでは、UserControlという名称は出てきません。

代わりにコンポーネントというそうです、なので新しい項目の追加からRazorコンポーネントを追加します。

今回は外部から値を入力・出力だけするシンプルなものを作ろうと思うので追加したコンポーネントに以下の追加・修正をします。

<RadzenTextBox Value=@Note></RadzenTextBox>
@code {
    string _note;
    [Parameter]
    public string Note
    {
        get => _note;
        set
        {
            if (_note != value)
            {
                _note = value;
                NoteChanged.InvokeAsync(value);
            }
            else
            {
                return;
            }
        }
    }
    [Parameter]
    public EventCallback<string> NoteChanged { get; set; }
}

みそなのは属性として[Parameter]を追加しているところと、値が変わったときに宣言したコールバックを読んでいることです。

コールバックを呼ぶことで変更通知が発行されコンポーネントの値が変更されます。

Lesson.3 コンポーネントを使う

作成したコンポーネントはほかのコンポーネントと同様に扱えます。

適当なページ(今回はIndex.razor)を以下のように修正します。

@page "/"
<SampleComponent @bind-Note=@value></SampleComponent>
<RadzenTextBox @bind-Value=@input></RadzenTextBox>
<RadzenButton Text="転送" Click=OnClick></RadzenButton>
@code {
    string value = string.Empty;
    string input = string.Empty;
    async Task OnClick()
    {
        value = input;
    }
}

コンポーネントの中で宣言した[Parameter]属性を持つ変数は上記のように"@bind-[コンポーネント変数名]=@ページ内変数"でバインドし使うことができます。

ここまできたら実行してまず右側のテキストボックスに文字を入力し、転送ボタンを押下します。

すると左側のテキストボックスに入力した文字が入力されるとおもいます。

Lesson.4 あとがき

以上!

HttpRequestMessageでGet・Post使用

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

今回はHttpRequestMessageでGet・Post使用について書きます。

それでは早速・・・HttpRequestMessageでGet・Post使用

Lesson.1 事の発端

僕はC#狂なので基本的にすべてをC#で実装したいです。

なのでBlazorでHttpRequestMessageを使用してGet・Postしようと思います。

Lesson.2 Program.cs

C#でGet・Postを行うにおいていろんな方法がありますがHttpClientについてあまりこみいった実装をしたくないといった思いがあります。

qiita.com

なのでかわりにIHttpClientFactoryを使用したいので以下のコードを追記します。

builder.Services.AddHttpClient();

Lesson.3 HttpRequestMessage - Get

Getはまあこれといった必要なことはありません。

ただ0000は各Post番号に左右されます。

@inject IHttpClientFactory ClientFactory

var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:0000" + controllerPath);
var client = ClientFactory.CreateClient();
var response = await client.SendAsync(request);
var getVal = await response.Content.ReadAsStringAsync();

Lesson.4 HttpRequestMessage - Post

Postも基本は送り付けるだけなんですが、ファイル等をアップロードするときだけ注意が必要です。

@inject IHttpClientFactory ClientFactory

var request = new HttpRequestMessage(HttpMethod.Post, "https://localhost:0000" + controllerPath);
var client = ClientFactory.CreateClient();
{
    var content = new MultipartFormDataContent();
    content .Add(new StringContent(JsonSerializer.Serialize<JsonSample>(new JsonSample() { Number = docNumber, Content = value }), Encoding.UTF8, "application/json"), "file", "test.json");
    request.Content = content ;
    using (var response = await client.SendAsync(request)) ;
}

上で使っているJsonのクラス(JsonSample)は以下です。

public class JsonSample
{
    [JsonPropertyName("number")]
    public int Number { get; set; }
    [JsonPropertyName("content")]
    public string? Content { get; set; }
}

一つ気を付けなければいけないのはcontent.Add()をする際第二引数は"file"でないと上手く動きません。

また、送るものに応じてcontent .Add(new StringContent())のAddするContentが変わります。

Lesson.5 あとがき

以上!!

ControllerでGet・Post実装

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

今回はにControllerでGet・Post実装ついて書きます。

それでは早速・・・ControllerでGet・Post実装

Lesson.1 事の発端

僕はC#狂なので基本的にすべてをC#で実装したいです。

なのでBlazorでApiの実装を試してみようと思います。

Lesson.2 Program.cs

BlazorではControllerでApiを実装する際、Program.csに追加の設定をしなければなりません。

app.UseEndpoints(userEndPpoints=>
{
   userEndPpoints.MapControllers();
});

Lesson.3 Controller - Get

Getの実装ではあんまり考えることはありません。

ざっくりこうです。

[Route("api/get")]
public class GetController : Controller
{
    private readonly IWebHostEnvironment environment;
    public GetController(IWebHostEnvironment environment)
    {
        this.environment = environment;
    }
    [HttpGet("string")]
    public IActionResult GetString()
    {
        try
        {
            return Content("Hello World");
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
    public class JsonSample
    {
        [JsonPropertyName("number")]
        public int Number { get; set; }
        [JsonPropertyName("content")]
      public string? Content { get; set; }
    }
    [HttpGet("json/{content}")]
    public IActionResult GetJson(string content)
    {
        try
        {
            return Content(JsonSerializer.Serialize(new JsonSample { Number = 1, Content = content }), "application/json", System.Text.Encoding.UTF8);
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
    [HttpGet("xlsx/{filePath}")]
    public IActionResult GetXlsxFile(string filePath)
    {
        try
        {
            var rslt = System.IO.File.ReadAllBytes(filePath);
            return File(rslt, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Path.GetFileName(filePath));
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
}

Lesson.4 Controller - Post

Postで行うことでいちばんミソとなるのはFileのアップロードだと思います。

あと、稀に送られてきたJsonを書き込まずStreamでそのまま使いたい時だと思います。

ざっくりこうです。

[Route("api/post")]
public class PostController : Controller
{
    private readonly IWebHostEnvironment environment;
    public PostController(IWebHostEnvironment environment)
    {
        this.environment = environment;
    }
    [HttpPost("file")]
    public IActionResult SetFile(IFormFile file)
    {
        try
        {
            using (var stream = new FileStream(Path.Combine(environment.WebRootPath, file.Name), FileMode.Create))
            {
                file.CopyTo(stream);
            }
            return Ok();
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
    public class JsonSample
    {
        [JsonPropertyName("number")]
        public int Number { get; set; }
        [JsonPropertyName("content")]
        public string? Content { get; set; }
    }
    [HttpGet("json")]
    public async Task<IActionResult> SetJson(IFormFile file)
    {
        try
        {
            using (var memoryStream = new MemoryStream())
            {
                await file.CopyToAsync(memoryStream);
              byte[] buffer = memoryStream.ToArray();
                // getのなかに取得したJsonが入る
                // 新規で書き込んで作るもよし・既存のファイルをいじるもよし
                var get = JsonSerializer.Deserialize<JsonSample>(Encoding.ASCII.GetString(buffer));
            }
            return Ok();
        }
        catch (Exception ex)
        {
            return StatusCode(500, ex.Message);
        }
    }
}

Lesson.5 あとがき

*20221219追記

using System.Text.Json.Serialization;でJsonを操作する際は元となるクラスの変数をプロパティにしないとSerialize、Deserializeがうまく動かずJsonが生成されません

以上!

Blazor と 32KB以上の通信

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

今回はBlazor と 32KB以上の通信について書きます。

それでは早速・・・Blazor と 32KB以上の通信

Lesson.1 事の発端

BlazorでRadzenのHtmlEditorを使用したWebアプリを運用していたとき、ある日から入力するためにコンポーネントをクリックすると以下メッセージ

"Attempting to reconnect to the server: 1 of 8"

と共に画面に再描画がかかるようになりました。

blazor.radzen.com

Lesson.2 原因と理由

SignalRの受信最大サイズがデフォルトでは32KBになっておりHtmlEditor内への入力データ量が32KBを超えてしまったためでした。

Lesson.3 対策

Program.csに以下のコードを追記しました。

// 32K超える通信のためのHubOption
builder.Services.Configure<HubOptions>(options =>
{
    options.MaximumReceiveMessageSize = null;
});

上記の記述をすることでSignalRの最大受信サイズを無制限にすることができるのでクリックごとの更新が起こらなくなりました。

Lesson.4 あとがき

以上!

Let's BlazorServer+Radzen ♪ ⑦ (Controller[Api] 作成)

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

前回で作業共有画面が完了しました。

今回はController(Api)を作成しようと思います。

それでは早速・・・Let's BlazorServer+Radzen ♪

Lesson.1 Controller(Api) ♪

Controllerとは、極限的に言うとMVCのCの部分のことです。

よくわかんない場合はApiのようなものだと思ってください。

learn.microsoft.com

本記事では、前回作成したWorkShareService.csをController(Api)化しようと思います。

Lesson.2 Service→Controller(Api)化 ♪

BlazroServerAppに"Controllers"というフォルダを作成します。

"Controllers"を左クリックし"追加"→"コントローラー"→"MCV コントローラー -空"を押下し"WorkShareController.cs"を作成します。

作成したWorkShareController.csを開くと以下関数

public IActionResult Index()
{
return View();
}

がありますが、これを削除して以下の変数と関数を追記します。

    public class WorkShareController : Controller
    {
       readonly IWebHostEnvironment environment;
       public WorkShareController(IWebHostEnvironment environment)
       {
           this.environment = environment;
           [Route("api/getworkshare/{id}")]
           public IActionResult GetWorkShareAsync(int id)
           {
               try
               {
                   return StatusCode(200);
               }
               catch (Exception ex)
               {
                   return StatusCode(500, ex.Message);
               }
           }
           [Route("api/setworkshare/{workShareJson}")]
           public IActionResult SetWorkShareAsync(string workShareJson)
           {
               try
               {
                   return StatusCode(200);
               }
               catch (Exception ex)
               {
                   return StatusCode(500, ex.Message);
               }
           }
    }

上記で重要なのはRouteと引数の記述です、[Route]属性指定されるパスはControllerを呼び出すためのパスです。

{}で囲っている部分は引数になり{}内の文字列と同等の引数を宣言することでパスにあたえられた値を引数として取得することができます。

また、GetWorkShareAsyncで返していたWorkShareについてはせっかくControllerにするのでJsonで取得するようにしたいです、Data\WorkShare.csに以下の修正を加えます。

using System.Text.Json.Serialization;
namespace BlazorServerApp.Data
{
    public class WorkShare
    {
        [JsonPropertyName("id")]
        public int Id { get; set; } = -1;
        [JsonPropertyName("content")]
        public string Content { get; set; } = string.Empty;
    }
}

Jsonを使う準備ができたためController\WorkShareController.csに以下の修正を加えます。

    public class WorkShareController : Controller
    {
       readonly IWebHostEnvironment environment;
       public WorkShareController(IWebHostEnvironment environment)
       {
           this.environment = environment;
           [Route("api/getworkshare/{id}")]
           public IActionResult GetWorkShareAsync(int id)
           {
               try
               {
                   var content = string.Empty;
                   if (System.IO.File.Exists(Path.Combine(environment.WebRootPath + @"\workshares", $"{id}.txt")))
                   {
                 content = System.IO.File.ReadAllText(Path.Combine(environment.WebRootPath + @"\workshares", $"{id}.txt"));
                   }
                 return Content(JsonSerializer.Serialize(new WorkShare() { Id = id, Content = content }), "application/json");
                   }
                   catch (Exception ex)
                   {
                 return StatusCode(500, ex.Message);
                   }
           }
           [Route("api/setworkshare/{workShareJson}")]
           public IActionResult SetWorkShareAsync(string workShareJson)
           {
               try
               {
                 var workShare = JsonSerializer.Deserialize<WorkShare>(workShareJson);
                 System.IO.File.WriteAllText(Path.Combine(environment.WebRootPath + @"\workshares", $"{workShare.Id}.txt"), workShare.Content);
                 return StatusCode(200);
               }
               catch (Exception ex)
               {
                   return StatusCode(500, ex.Message);
               }
           }
    }

上記で肝なコードは特にありませんが、しいて言うならContent(JsonSerializer.Serialize(new WorkShare() { Id = id, Content = content }), "application/json");の部分です。

これはJson形式にシリアライズしたデータを"application/json"でMIME TYPEをJsonに指定してデータとして返しているということです。

Lesson.3 エンドポイント設定 ♪

ロジック部分についてはLesson.3までで完成ですが、アプリケーションのエンドポイントにControllerを使っていることを教えてあげなくてはいけません。

なのでProgram.csに以下のコードを追記します。

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

ここまで来たら実行してするとLogin画面が表示され、URLが以下の文字列になっていると思います。

"https://localhost:7185"←7185は環境によって数字が若干違うかもしれません。

これに/api/getworkshare/1を付け加え

"https://localhost:7185/api/getworkshare/1"

にしてページを遷移させると・・・

すごいたくさん文字が出てくると思います!(前の記事での作業共有フォームでの保存をしてない方はちょっとだけ文字がでてくるとおもいます。)

画面にでている文字の最初が"{"id":1,"content":"ならちゃんとApiからデータが取得できています!

Lesson.4 あとがき ♪

次回はC#側でApiからのデータの取得を作成しようと思います!

それでは次回更新でまた!

github.com

Let's BlazorServer+Radzen ♪ ⑥ (作業共有画面-2)

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

前回で作業共有画面-1(UI部分)が完了しました。

今回は作業共有画面-2(処理部分)を作成しようと思います。

それでは早速・・・Let's BlazorServer+Radzen ♪

Lesson.1 データService作成 ♪

Data\WorkShare.csに以下のコードを追加します。

    public class WorkShare
    {
        public int Id { get; set; } = -1;
        public string Content { get; set; } = string.Empty;
    }

Data\WorkShareService.csに以下のコードを追加します。

    public class WorkShareService
    {
        readonly IWebHostEnvironment environment;
        public WorkShareService(IWebHostEnvironment environment)
        {
            this.environment = environment;
        }
        public Task SetWorkShareAsync(WorkShare workShare)
        {
            return Task.FromResult(SetWorkShare(workShare));
        }
        public Task<WorkShare> GetWorkShareAsync(int id)
        {
            return Task.FromResult(GetWorkShare(id));
        }
        bool SetWorkShare(WorkShare workShare)
        {
            // ここでDBと通信しユーザー情報を取得
            // 今回は構造体で適当にユーザーを返す
            return true;
        }
        WorkShare GetWorkShare(int id)
        {
            // ここでDBと通信しユーザー情報を取得
            // 今回は構造体で適当にユーザーを返す
            return new WorkShare();
        }
    }

ここで重要な関数はSerWorkShareとGetWorkShareです

SetWorkShareでユーザーIDと入力内容を保存しGetWorkShareで保存した情報を取得できるようにします。

合わせてコンストラクタで引数として取得しているenvironmentにrootのパスが入っているためそこに"{ID}.txt"のファイルを作成し、取得・保存を行うようにします。

        public Task SetWorkShareAsync(WorkShare workShare)
        {
           return Task.FromResult(SetWorkShare(workShare));
        }
       bool SetWorkShare(WorkShare workShare)
        {
            // ここでDBと通信しデータの保存
            // 今回はファイルで扱う
            File.WriteAllText(Path.Combine(environment.WebRootPath + @"\workshares", $"{workShare.Id}.txt"), workShare.Content);
            return true;
        }

        WorkShare GetWorkShare(int id)
        {
            // ここでDBと通信しデータの取得
            // 今回はファイルで扱う
           var content = string.Empty;
            if (File.Exists(Path.Combine(environment.WebRootPath + @"\workshares", $"{id}.txt")))
            {
                content = File.ReadAllText(Path.Combine(environment.WebRootPath + @"\workshares", $"{id}.txt"));
            }
            return new WorkShare() { Id = id, Content = content };
      }

これでServiceの作成は完了です。

この部分はControllerといえる動作もしているため、次回記事のControllerの作成で参考に使おうと思います。

Lesson.2 データService利用 ♪

あとは画面側で参照するだけですが前回までの実装ではせっかくログインしたのに他のユーザーのデータも保存できるようになっていました。

なのでログインユーザー以外の保存はできなくしてしまいましょう。Page\WorkShare.razorに以下の修正を行います。

<div class="col-12" style="height:5%;">
    <RadzenButton Text="読込" Icon="refresh" Click=@Read_Click Disabled=@(!isLogin)></RadzenButton>
    <RadzenButton Text="保存" Icon="save_alt" Click=@Save_Click Disabled=@(!isLogin)></RadzenButton>
</div>

@code{}に以下の修正を加えます。


@code {
    bool isLogin = false;
    string value = string.Empty;
    [Parameter]
    public string? loginId { get; set; }
    [Parameter]
    public string? userId { get; set; }
    protected override async void OnParametersSet()
  {
        isLogin = (loginId == userId);
        StateHasChanged();
    }
    async Task Read_Click()
    {
    }
    async Task Save_Click()
    {
    }
    async Task OnExecute(string type, RadzenHtmlEditor editor)
    {
        if (type == "UpdateRedFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(255,0,0,100)");
        }
        else if (type == "UpdateBlueFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,255,100)");
        }
        else if (type == "UpdateBlackFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,0,100)");
        }
    }
}

上記の修正でOnParameterSet()で画面描画時、

・ログインユーザー 保存ボタン:有効

・ログインユーザーでない 保存ボタン:無効

と処理を行うようにしました。

データ保存、読込の処理はLesson.1で作ったServiceをそれぞれRead_Click、Save_Clicに追記します。

    async Task Read_Click()
  {
        var get = await WorkShareService.GetWorkShareAsync(int.Parse(userId));
        value = get.Content;
    }
    async Task Save_Click()
  {
        var set = new Data.WorkShare() { Id = int.Parse(userId), Content = value }; 
        await WorkShareService.SetWorkShareAsync(set);
    }

また画面描画時にも自動で入力内容を書き込むようにしたいのでOnParameterSetを以下のように修正します。

    protected override async void OnParametersSet()
    {
        isLogin = (loginId == userId);
      var get = await WorkShareService.GetWorkShareAsync(int.Parse(userId));
        value = get.Content;
        StateHasChanged();
  }

Lesson.3 他設定 (32KB以上の通信他) ♪

BlazorServerは32KB以上のデータ通信が発生した場合、画面を再描画するといった設定が初期設定でされております。

learn.microsoft.com

すぐに問題が発生するといったことはないと思いますが、入力内容が増えるにつれてスクロールするだけで再描画といった動作をするようになるため、対策として以下の設定を追加します。

Program.cs

using Microsoft.AspNetCore.SignalR;

builder.Services.Configure<HubOptions>(options =>
{
    options.MaximumReceiveMessageSize = null;
});

また、再読み込み等から再ログインした際、今後再開ページによっては都合が悪くなる場面がくると思います、(権限等により)なのでログイン成功後は必ずルートのページに遷移するように以下の修正を加えます。

Shared\MainLayout.razor

@inject NavigationManager NavigationManager

if (getUser.Any())
{
        // ユーザーが取得できたためLogin
        IsLogin = false;
        ShowNotification(NotificationSeverity.Success, "ログイン成功", "ログインに成功しました。");
        loginUser = getUser.ToList()[0];
        NavigationManager.NavigateTo("/");
        StateHasChanged();
}

ここまできたら実行して"saitou"でログイン後、何かしら入力し保存を行います。(僕は何も思いつかなかったためC#Wikipediaの説明を貼り付けました)

ページをリロードかプロジェクトを再ビルドをしLogin画面に遷移して"yamada"でログイン後再度"saitou"のページに行くと・・・

先ほどの入力情報が残っていてさらにボタンが無効になっていますね!

Lesson.4 あとがき ♪

Lesson.3の32KBの通信の部分は覚えておくといつか役立つかもしれません!(自分が苦労したので・・・w)

また、保存成功・読込成功のメッセージを出すようにしていないため、復習がてらメッセージを出すように改造したりしてもらえたらと思います!

それでは次回更新でまた!

github.com

Let's BlazorServer+Radzen ♪ ⑤ (作業共有画面-1)

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

前回で通知機能の実装が完了しました。

今回は作業共有画面を作成しようと思います。

それでは早速・・・Let's BlazorServer+Radzen ♪

Lesson.1 下準備 ♪

作業共有画面を作るにあたって下準備をしたいと思います。

データの保存に関してですが実環境ではDatabaseを使用し保存するのが望ましいです。しかし今回はそこまで準備ができないためwwwrootの下にworksharesというフォルダを作成しそこにテキスト形式で保存しようと思います。

各作業員の入力データを取得するためのServiceが必要なのでDataの下にWorkShares.cs、WorkShareService.csを作成します。

入力フォームが必要なのでPagesの下にWorkShare.razorを作成します。(Pages右クリック→追加(D)→Radzenコンポーネント)

前回までで作成していたユーザーのパスワードでは以下の注意画面が出てくると思います。

これはパスワードに"password"という漏洩リスクのあるものを使っているのが原因なのでData\LoinInfoService.csのパスワードを"akiword"に変更します。

new LoginInfo() {Id = 1, UserName = "saitou", Password = "akiword" },
new LoginInfo() {Id = 2, UserName = "yamada", Password = "akiword" },
new LoginInfo() {Id = 3, UserName = "tanaka", Password = "akiword" }

また追加したWorkShareServiceをProgram.csのServicesに登録します。

builder.Services.AddSingleton<WorkShareService>();

Lesson.2 HtmlEditorコンポーネント

今回の入力フォームはHtmlEditorコンポーネントを使用しようと思います。

blazor.radzen.com

Lesson.3 入力フォーム(画面)作成 ♪

Lesson.1で追加したWorkShare.razorを入力フォームとするためPage\WorkShare.razorを開き既存のコードをすべて消し以下コードを貼り付けます。

@page "/workshare"
@using Radzen
@using Radzen.Blazor
<div class="col-12" style="height:5%;">
    <RadzenButton Text="読込" Icon="refresh" Click=@Read_Click></RadzenButton>
    <RadzenButton Text="保存" Icon="save_alt" Click=@Save_Click></RadzenButton>
</div>
<RadzenHtmlEditor @bind-Value=@value class="w-100" style="height:95%;font-family:Source Han Code JP;">
    <RadzenHtmlEditorUndo />
    <RadzenHtmlEditorRedo />
    <RadzenHtmlEditorSeparator />
    <RadzenHtmlEditorFontSize />
    <RadzenHtmlEditorColor />
    <RadzenHtmlEditorBackground />
    <RadzenHtmlEditorCustomTool>
        <Template Context="editor">
            <RadzenButton Icon=title Style="color:red; background-color:transparent;" Click=@(args => OnExecute("UpdateRedFormat",editor))></RadzenButton>
        </Template>
    </RadzenHtmlEditorCustomTool>
    <RadzenHtmlEditorCustomTool>
        <Template Context="editor">
            <RadzenButton Icon=title Style="color:blue; background-color:transparent;" Click=@(args => OnExecute("UpdateBlueFormat",editor))></RadzenButton>
        </Template>
    </RadzenHtmlEditorCustomTool>
    <RadzenHtmlEditorCustomTool>
        <Template Context="editor">
            <RadzenButton Icon=title Style="color:black; background-color:transparent;" Click=@(args => OnExecute("UpdateBlackFormat",editor))></RadzenButton>
        </Template>
    </RadzenHtmlEditorCustomTool>
    <RadzenHtmlEditorRemoveFormat />
    <RadzenHtmlEditorSeparator />
    <RadzenHtmlEditorBold />
    <RadzenHtmlEditorItalic />
    <RadzenHtmlEditorUnderline />
    <RadzenHtmlEditorStrikeThrough />
    <RadzenHtmlEditorSeparator />
    <RadzenHtmlEditorAlignLeft />
    <RadzenHtmlEditorAlignCenter />
    <RadzenHtmlEditorAlignRight />
    <RadzenHtmlEditorJustify />
    <RadzenHtmlEditorSeparator />
</RadzenHtmlEditor>
@code {
  string value = string.Empty;
    async Task Read_Click(){
    }
    
    async Task Save_Click(){
    }

    async Task OnExecute(string type, RadzenHtmlEditor editor)
    {
        if (type == "UpdateRedFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(255,0,0,100)");
        }
        else if (type == "UpdateBlueFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,255,100)");
        }
        else if (type == "UpdateBlackFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,0,100)");
        }
    }
}

Shared\MainLayout.razorを開き以下コードを追記します。

<RadzenPanelMenuItem Icon="" Text="作業共有" Path="/workshare">
</RadzenPanelMenuItem>

ここで一旦実行をするとログイン後作業共有から入力画面に移動できるようになってると思います。

Lesson.4 入力フォーム(ルーティング)作成 ♪

Lesson.3までで入力画面を表示できるようにしました。

ですが、今回は作業共有が目的なので他の人のデータが見れる必要があります。

作業共有からすべてのユーザーの入力画面に遷移できるように以下の修正を加えます。

Shared/MainLayout.razor

                        <RadzenPanelMenuItem Icon="" Text="作業共有">
                            @foreach (var i in allUser)
                            {
                                <RadzenPanelMenuItem Text=@i.UserName Path=@($"workshare/{i.Id.ToString()}/{loginUser.Id.ToString()}")></RadzenPanelMenuItem>
                            }
                        </RadzenPanelMenuItem>
                    </ChildContent>
                </RadzenPanelMenu>
            </ChildContent>
        </RadzenSidebar>
        <RadzenFooter>
            <ChildContent>
                <RadzenLabel Text="BlazorServerApp, Copyright Ⓒ 2022">
                </RadzenLabel>
            </ChildContent>
        </RadzenFooter>
    </ChildContent>
</RadzenLayout>
@code {
    bool IsLogin = true;
    IList<LoginInfo> allUser = new List<LoginInfo>();
    LoginInfo loginUser = new LoginInfo();
    protected override async Task OnInitializedAsync()
    {
        allUser = await LoginInfoService.GetLoginInfoAsync();
    }
    async Task OnLogin(LoginArgs args)
    {
        var getUser = allUser.Where(x => x.UserName == args.Username && x.Password == args.Password);
        if (getUser.Any())
        {
            // ユーザーが取得できたためLogin
            IsLogin = false;
            ShowNotification(NotificationSeverity.Success, "ログイン成功", "ログインに成功しました。");
            loginUser = getUser.ToList()[0];
            StateHasChanged();
        }
        else
        {
            // ユーザーが取得できなかったためNG
            ShowNotification(NotificationSeverity.Error, "ログイン失敗", "ログインに失敗しました。");
        }
  }

上記の変更でみそなのは一番上の変更の記述で、BlazorではHtmlにC#での記述を混ぜることができます。

なので以下の記述は

@foreach (var i in allUser)
{
    <RadzenPanelMenuItem Text=@i.UserName Path=@($"workshare/{i.Id.ToString()}/{loginUser.Id.ToString()}")></RadzenPanelMenuItem>
}

OnInitializedAsyncで取得した全てのユーザーへのRadzenPanelMenuItemとクリックしのPathを設定しています。

上記の状態で実行をすると作業共有がDropDownできるようになっておりLoginInfoで登録している3人の名前が確認できるとおもいます。

ですが、この状態でクリックしてもLogin画面に戻されてしまうと思います。これは受け手側のフォームが対応できていないからです。

なのでWorkShare.razorにも修正を加えます。

ソース上部にある@page "/workshare"を以下のように修正します。

@page "/workshare/{userId}/{loginId}"

@codeを以下のように修正します。

@code {
    string value = string.Empty;
    [Parameter]
    public string? loginId { get; set; }
    [Parameter]
    public string? userId { get; set; }
    async Task Read_Click()
    {
    }
    async Task Save_Click()
    {
    }
    async Task OnExecute(string type, RadzenHtmlEditor editor)
    {
        if (type == "UpdateRedFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(255,0,0,100)");
        }
        else if (type == "UpdateBlueFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,255,100)");
        }
        else if (type == "UpdateBlackFormat")
        {
            await editor.ExecuteCommandAsync(HtmlEditorCommands.Color, $"rgba(0,0,0,100)");
        }
    }
}

上記でやっているのはpathに与えられた文字列を動的に取得しその値を[Parameter]で設定してある同名変数に格納するようにしています。(表現としてはbindの方が正しいかもしれません)

ここまできて実行をすると・・・

名前を選択して入力フォームに遷移できるようになりましたね!

Lesson.5 あとがき ♪

今回は画面までしかできませんでした。

次回更新でデータ読込から保存を実装し完成させようと思います。

それでは次回更新でまた!

github.com