質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
blazor

Blazorは、マイクロソフトが開発している.NETベースのWebアプリフレームワークです。C#でフロントエンドもバックエンドも一貫して書くことが可能。クライアントサイド(WebAssembly)とサーバーサイド形式のホスティングモデルがあります。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

Q&A

解決済

1回答

1426閲覧

ASP.NET BlazorServer JavaScript->.NETの引数をクラスで受け取りたい

bjnes

総合スコア113

blazor

Blazorは、マイクロソフトが開発している.NETベースのWebアプリフレームワークです。C#でフロントエンドもバックエンドも一貫して書くことが可能。クライアントサイド(WebAssembly)とサーバーサイド形式のホスティングモデルがあります。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

ASP.NET

ASP.NETは動的なWebサイトやWebアプリケーション、そしてWebサービスを構築出来るようにする為、Microsoftによって開発されたウェブアプリケーション開発フレームワークです。

0グッド

0クリップ

投稿2022/11/17 08:52

編集2022/11/18 00:56

前提

 

実現したいこと

そうすれば、ブラウザからのイベント数を絞れるので、ドラッグイベントの負荷を軽くしたい。

発生している問題・エラーメッセージ

単純化のためにクリックイベントで実験中

  • String型やBool型の引数のやり取りはできるのに、PointerEventArgs? MouseEvetArgs?等で受け取ろうとすると、すべての値が無効=0になる。
  • 原因というか仕組みの理解不足だと思っています。

 

該当のソースコード

デフォルトのテンプレートから以下の3つのファイルだけ編集しています。
ログインオプションやDockerオプションは指定していません。

変更

Pages\Index.razor

1@inject IJSRuntime JS 2@page "/" 3 4<PageTitle>Index</PageTitle> 5 6<button @ref=@button1 style="margin:1em">Click</button> 7clickcount:@count1 8@ArgsInfo1 9<br /> 10<button @ref=@button2 style="margin:1em">Click</button> 11clickcount:@count2 12@ArgsInfo2 13 14<h1>Hello, world!</h1> 15 16Welcome to your new app. 17 18<SurveyPrompt Title="How is Blazor working for you?" /> 19@code { 20 21 ElementReference? button1, button2; 22 int count1, count2; 23 string? ArgsInfo1, ArgsInfo2; 24 25 [JSInvokable] 26 public void JSHandleOnClick1(MouseEventArgs e) 27 { 28 count1++; 29 ArgsInfo1 = e.ClientX.ToString(); 30 StateHasChanged(); 31 } 32 33 [JSInvokable] 34 public void JSHandleOnClick2(int clientx) 35 { 36 count2++; 37 ArgsInfo2 = clientx.ToString(); 38 StateHasChanged(); 39 } 40 41 protected override async Task OnAfterRenderAsync(bool firstRender) 42 { 43 if (firstRender) 44 { 45 if (firstRender) 46 { 47 var DotNetObject = DotNetObjectReference.Create(this); 48 await JS.InvokeAsync<IJSObjectReference>("import", "./Pages/Index.razor.js"); 49 await JS.InvokeVoidAsync("AddClickEventone", button1, DotNetObject, "click"); 50 await JS.InvokeVoidAsync("AddClickEventtow", button2, DotNetObject, "click"); 51 } 52 } 53 await base.OnAfterRenderAsync(firstRender); 54 } 55}

Pages_Layout.cshtml

1@using Microsoft.AspNetCore.Components.Web 2@namespace BlazorApp1.Pages 3@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 5<!DOCTYPE html> 6<html lang="en"> 7<head> 8 <meta charset="utf-8" /> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 10 <base href="~/" /> 11 <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> 12 <link href="css/site.css" rel="stylesheet" /> 13 <link href="BlazorApp1.styles.css" rel="stylesheet" /> 14 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script> 15 <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" /> 16</head> 17<body> 18 @RenderBody() 19 20 <div id="blazor-error-ui"> 21 <environment include="Staging,Production"> 22 An error has occurred. This application may no longer respond until reloaded. 23 </environment> 24 <environment include="Development"> 25 An unhandled exception has occurred. See browser dev tools for details. 26 </environment> 27 <a href="" class="reload">Reload</a> 28 <a class="dismiss">🗙</a> 29 </div> 30 31 <script src="_framework/blazor.server.js"></script> 32</body> 33</html>

新規作成

Pages\Index.razor.js

1window.AddClickEventone = 2 function (elem, component, name) { 3 elem.addEventListener(name, 4 _.throttle(e => { 5 component.invokeMethodAsync("JSHandleOnClick1", 6 e 7 ); 8 } 9 , 1000 10 , { leading: true, trailing: true })); 11 return; 12 }; 13 14window.AddClickEventtow = 15 function (elem, component, name) { 16 elem.addEventListener(name, 17 _.throttle(e => { 18 component.invokeMethodAsync("JSHandleOnClick2", 19 e.clientX 20 ); 21 } 22 , 1000 23 , { leading: true, trailing: true })); 24 return; 25 };

試したこと

該当のソースコードで比較実験しました。
ASP.NET Core Blazor JavaScript の相互運用性のドキュメントについて眺めています。

最後に

難解な質問で申し訳なく思っています。
このページを見てくれた方に感謝を申し上げます。
ありがとうございます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/11/18 00:13

ASP.NET のタグをつけて下さい。
bjnes

2022/11/18 00:53

指摘ありがとうございます。修正しました。
退会済みユーザー

退会済みユーザー

2022/11/18 01:33

自分が知らないだけという可能性は否定しきれませんが・・・ > JavaScriptからのマウスイベントを.NETでMouseEventArgs やDragEventArgsとして受け取りたい。 Blazor Server はブラウザとサーバー間の通信は SignalR を使うのですが、SignalR でクライアント側からサーバーの ASP.NET Core アプリに .NET のオブジェクトである MouseEventArgs や DragEventArgs を送ることはできないと思います。   まず、クライアント側(ブラウザ)で MouseEventArgs や DragEventArgs を生成できないはずです。生成できたとしても送信側でシリアル化して送り、受信側で逆シリアル化しなければなりませんが、そんなことはできないでしょうし、できたとしても意味がなさそうに思います。 そんなことはなくて、できるという Microsoft の公式文書などがあれば教えていただけませんか?
bjnes

2022/11/18 02:00

JavaScript→.Netの関数呼び出しの引数に、JsonSerializeがされてます。 該当コード中の引数にてMouseEvetArgsではなくてobjectで受け取ると、JsonSerializeの形跡が見て取れます。 オブジェクトのJSONシリアル化について: https://learn.microsoft.com/ja-jp/aspnet/core/blazor/javascript-interoperability/?view=aspnetcore-6.0#object-serialization >受信側で逆シリアル化しなければなりませんが、そんなことはできないでしょうし、できたとしても意味がなさそうに思います。 これができれば、JavaScriptドラッグイベントの引数をイベントの発生を絞ったうえで、簡単に.NET側で受け取れるんです。できない場合、イベント引数を大量にばらばらにしなければならなくて面倒なのです。
退会済みユーザー

退会済みユーザー

2022/11/18 02:20 編集

> JavaScript→.Netの関数呼び出しの引数に、JsonSerializeがされてます。 たとえば、JavaScript の shapeModel = { left: 0, top: 0 } というような単純なオブジェクトならフレームワーク組み込みの機能が JSON シリアライズ/デシリアライズをやってくれますが MouseEvetArgs はできないと思います。試しに System.Text.Json を使って試してみてはいかがですか? それより、上に書いたように、そもそもクライアント側(ブラウザ)で MouseEventArgs や DragEventArgs を生成できません。
bjnes

2022/11/18 02:29

MouseEvetArgs はできないという認識を持ったほうがいいのでしょうか。 なぜできないのか、わからないから質問をしている次第ですが。 > MouseEventArgs や DragEventArgs を生成できません。 これは可能です。正確には、MouseEventやDragEventとして JavaScript上で、動いています。 https://developer.mozilla.org/ja/docs/Web/API/MouseEvent _.throttle(e => { component.invokeMethodAsync("JSHandleOnClick1", e ); eが実際のそれです。 プロパティ名も、MouseEventArgsと対になっているので、JsonConvertされてもいいような気がするのです。
bjnes

2022/11/18 02:36

受け取る引数型をSystem.Text.Json.JsonDocument にすると、 ValueKind = Object : "{"isTrusted":true}" までは受け取れましたね…おしい。。 そのあとのプロパティーも受け取りたいのですが。
退会済みユーザー

退会済みユーザー

2022/11/18 03:17

>> MouseEventArgs や DragEventArgs を生成できません。 > これは可能です。正確には、MouseEventやDragEventとしてJavaScript上で、動いています。 > https://developer.mozilla.org/ja/docs/Web/API/MouseEvent それ、.NET のオブジェクトの MouseEventArgs や DragEventArgs とは別物です。その認識はありますか?  > JavaScriptからのマウスイベントを.NETでMouseEventArgs やDragEventArgsとして受け取りたい。 で言っている「MouseEventArgs やDragEventArgs」というのは一体何なのですか?
bjnes

2022/11/18 04:09

>それ、.NET のオブジェクトの MouseEventArgs や DragEventArgs とは別物です。その認識はありますか?  はい。別物ですね。認識はあります。 >MouseEventArgs やDragEventArgs」というのは一体何なのですか? JavaScriptから”JSONシリアライズされて読める形になっていてほしい” Microsoft.AspNetCore.Components.Web.MouseEventArgsです。 質問していただけるのはうれしいのですが、該当ソースコードの意図を少し汲んでいただけると幸いです。
退会済みユーザー

退会済みユーザー

2022/11/18 04:41 編集

質問者さんの問題が理解できてなかったようですみません。 > string型やBool型の引数のやり取りはできるのに、PointerEventArgs? MouseEvetArgs?等で受け取ろうとすると、すべての値が無効=0になる。 ・・・というのは、質問のコードの public void JSHandleOnClick2(int clientx) の clientx には期待通りの値が取得できるが、public void JSHandleOnClick1(MouseEventArgs e) の e のプロパティの値は「すべての値が無効=0」になるという言うことだったのですね?
退会済みユーザー

退会済みユーザー

2022/11/18 05:20

以下の記事に、 静的 .NET メソッドの呼び出し https://learn.microsoft.com/ja-jp/aspnet/core/blazor/javascript-interoperability/call-dotnet-from-javascript?view=aspnetcore-7.0#invoke-a-static-net-method 以下の構文で DotNet.invokeMethodAsync('{ASSEMBLY NAME}', '{.NET METHOD ID}', {ARGUMENTS}); "{ARGUMENTS} プレースホルダーは、メソッドに渡す省略可能なコンマ区切りの引数であり、各引数は JSON シリアル化可能である必要があります" ・・・と書いてあります。 MouseEventArgs は、質問者さんが試したように JSON シリアル化可能ではないということで、「すべての値が無効=0」ということになったのではなかろうかと思います。
退会済みユーザー

退会済みユーザー

2022/11/18 05:51 編集

MouseEventArgs が System.Text.Json で JSON にシリアル化できるかどうか、以下のコードで試してみました。 結果、シリアル化はできて変数 json に JSON 文字列が取得できました。ということは上の条件は満たしているので上のコメントの推測もハズレだったようです。もうちょっと調べてみます。 var arg = new Microsoft.AspNetCore.Components.Web.MouseEventArgs() { ClientX = 50, ClientY = 100 }; var json = System.Text.Json.JsonSerializer.Serialize(arg); > _.throttle(e => { の e は MouseEventArgs ではないので、MouseEventArgs がシリアル化できるか否かは関係なかったですね。 JavaScript の e をシリアル化して、その結果の JSON 文字列を MouseEventArgs にデシリアライスするようなことができないとがダメと言うことらしいですね。
bjnes

2022/11/18 07:07

はい。同じ目線に立って頂いて、非常にうれしく思います。 ありがとうございます。 もし、eが正確にシリアライズされていれば、プロパティ名に互換がある.NETのクラスでデシリアイズされてもおかしくないと思うのですが、それができてないのが問題なのです。
退会済みユーザー

退会済みユーザー

2022/11/18 07:44

回答しました。見てください。
guest

回答1

0

ベストアンサー

string型やBool型の引数のやり取りはできるのに、PointerEventArgs? MouseEvetArgs?等で受け取ろうとすると、すべての値が無効=0になる。

・・・というのは、質問のコードの public void JSHandleOnClick2(int clientx) の clientx には期待通りの値が取得できるが、public void JSHandleOnClick1(MouseEventArgs e) の e のプロパティの値は「すべての値が無効=0」になるということと理解して回答します。

質問者さんの Pages\Index.razor.js のコードで component.invokeMethodAsync("JSHandleOnClick1", e); としていますが、その場合 JavaScript オブジェクト e を JSON シリアル化して、その結果の JSON 文字列を MouseEventArgs にデシリアライズできる必要があるようです。でも、それはできないので上に書いた結果になったようです。

そこを何とかしてシリアライズ/デシリアライズする方法はなさそうです。

代案として、e の中身を、JSON にシリアライズ可能な別の JavaScript オブジェクト(連想配列)に詰め替えて、それを invokeMethodAsync メソッドの引数に渡してやるという手段があります。

質問者さんが参考にした以下の記事のサンプルを使って例を書いておきます。

イベントをすぐにトリガーしない
https://learn.microsoft.com/ja-jp/aspnet/core/blazor/performance?view=aspnetcore-6.0#dont-trigger-events-too-rapidly-1

上の記事では e.offsetX, e.offsetY を引数に取っていますが、これを { OffsetX: e.offsetX, OffsetY: e.offsetY } という JavaScript のオブジェクト(連想配列)にして渡してみます。そのコードは以下の通り。

JavaScript

1<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script> 2<script type="text/javascript"> 3 function onThrottledMouseMove(elem, component, interval) { 4 elem.addEventListener('mousemove', _.throttle(e => { 5 //component.invokeMethodAsync('HandleMouseMove', e.offsetX, e.offsetY); 6 let position = { OffsetX: e.offsetX, OffsetY: e.offsetY }; 7 component.invokeMethodAsync('HandleMouseMove', position); 8 }, interval));} 9</script>

上の position が JSON 文字列にシリアライズされ、.NET のオブジェクトにデシリアライズされて C# のメソッドの引数に渡されます。

なので、C# のオブジェクトのクラス定義が必要です。今回は Data/WeatherForecast.cs に追加しました。

C#

1namespace BlazorServer.Data 2{ 3 public class WeatherForecast 4 { 5 public DateTime Date { get; set; } 6 7 public int TemperatureC { get; set; } 8 9 public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); 10 11 public string? Summary { get; set; } 12 } 13 14 // 以下のクラス定義を追加 15 public class Position 16 { 17 public double OffsetX { get; set; } 18 19 public double OffsetY { get; set; } 20 } 21}

Razor ページは以下のようになります。HandleMouseMove メソッドは JSON がデシリアライズされた Position オブジェクトを引数として取得しているところに注目してください。

C#

1@page "/" 2@inject IJSRuntime JS 3@implements IDisposable 4@using BlazorServer.Data 5 6<PageTitle>Index</PageTitle> 7 8<h1>Hello, world!</h1> 9 10Welcome to your new app. 11 12<SurveyPrompt Title="How is Blazor working for you?" /> 13 14<h1>@message</h1> 15 16<div @ref="mouseMoveElement" style="border:1px dashed red;height:200px;"> 17 Move mouse here 18</div> 19 20@code { 21 private ElementReference mouseMoveElement; 22 private DotNetObjectReference<Index>? selfReference; 23 private string message = "Move the mouse in the box"; 24 25 [JSInvokable] 26 //public void HandleMouseMove(int x, int y) 27 public void HandleMouseMove(Position e) 28 { 29 //message = $"Mouse move at {x}, {y}"; 30 message = $"Mouse move at {e.OffsetX}, {e.OffsetY}"; 31 StateHasChanged(); 32 } 33 34 protected override async Task OnAfterRenderAsync(bool firstRender) 35 { 36 if (firstRender) 37 { 38 selfReference = DotNetObjectReference.Create(this); 39 var minInterval = 500; 40 41 await JS.InvokeVoidAsync("onThrottledMouseMove", 42 mouseMoveElement, selfReference, minInterval); 43 } 44 } 45 46 public void Dispose() => selfReference?.Dispose(); 47}

結果は以下のようになります。

イメージ説明

上の例では、e.offsetX, e.offsetY だけですが、Position クラスを拡張して他のプロパティも渡すことができるはずです。お試しください。

投稿2022/11/18 07:36

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

bjnes

2022/11/18 08:08

eそのものはシリアライズ不可能なオブジェクトっぽいですね。 詰め替えが必要なことがわかりました。 そのうえで、MouseEvetArgs等.netのクラスを使っていこうと思います。 MouseEvetArgs自体はJSON対応できていると思いますので。 お付き合いいただきありがとうございました。
退会済みユーザー

退会済みユーザー

2022/11/18 08:57

> そのうえで、MouseEvetArgs等.netのクラスを使っていこうと思います。MouseEvetArgs自体はJSON対応できていると思いますので。 そうですね、確認してみましたが、Position クラス定義などは使わなくても、MouseEvetArgs を使ってそれにデシリアライズできますね。JS 側の連想配列で渡されないプロパティの値はそれぞれの型のデフォルト値で初期化されます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問