یک نکتهی تکمیلی: روش تعریف data binding دو طرفه در کامپوننتها
در مطلب جاری، binding دو طرفه بررسی شد؛ که نکتهی مورد بحث آن، به ویژگیهای استاندارد HTML مانند ویژگی value یک input استاندارد اختصاص داشت. اما اگر بخواهیم در کامپوننتهای سفارشی خود، این binding دو طرفه را تعریف کنیم تا قابل اعمال به خواص و ویژگیهای #C باشد (مانند bind-ProprtyName@)، روش کار به نحو دیگری است. نمونهی آن کامپوننت استاندارد InputText خود Blazor است که در اینجا هم دارای bind-Value@ است؛ اما این Value (شروع شدهی با حروف بزرگ) یک خاصیت #C تعریف شدهی در کلاس InputText است و نه یک ویژگی استاندارد HTML که عموما با حروف کوچک شروع میشوند:
<InputText @bind-Value="employee.FirstName" />
الف) یک پارامتر عمومی به نام Value باید در کلاس کامپوننت جاری تعریف شود تا بتوان از طریق والد آن، مقداری را دریافت کرد (یک طرف binding به این نحو تشکیل میشود):
[Parameter] public string Value { set; get; }
[Parameter] public EventCallback<string> ValueChanged { get; set; }
نکتهی مهم: در اینجا بجای EventCallback، از Action هم میتوان استفاده کرد:
تفاوت اصلی و مهم آن با EventCallback، در فراخوانی نشدن خودکار متد StateHasChanged، در پایان کار آن است. زمانیکه EventCallback ای فراخوانی میشود، Blazor به صورت خودکار در پایان کار آن، متد StateHasChanged را نیز فراخوانی میکند تا والد دربرگیرندهی کامپوننت جاری، مجددا رندر شود (به همراه تمام کامپوننتهای فرزند آن). اما <Action<T فاقد این درخواست خودکار رندر و به روز رسانی مجدد UI است.
[Parameter] public Action<string> ValueChanged { get; set; }
ج) برای فعالسازی اعتبارسنجی استاندارد فرمهای Blazor، نیاز به خاصیت ویژهی سومی نیز هست (که اختیاری است):
[Parameter] public Expression<Func<string>> ValueExpression { get; set; }
مرحلهی آخر این طراحی، فراخوانی پارامتر ValueChanged است تا به کامپوننت والد این تغییرات را اطلاع رسانی کنیم. روش استاندارد آن به صورت زیر است:
private string _value; [Parameter] public string Value { get => _value; set { var hasChanged = string.Equals(_value, value, StringComparison.Ordinal); if (hasChanged) { _value = value; if (ValueChanged.HasDelegate) { _ = ValueChanged.InvokeAsync(value); } } } }
در این قطعه کد، بررسی ValueChanged.HasDelegate را هم مشاهده میکنید. زمانیکه پارامتر Value ای با طی سه مرحلهی فوق تعریف شد، قرار نیست حتما توسط bind-Value@ مورد استفاده قرار گیرد. میتوان Value را به صورت یک طرفه هم مورد استفاده قرار داد. در این حالت دو پارامتر ب و ج دیگر توسط Blazor ایجاد و مقدار دهی نشده و رهگیری نخواهند شد. یعنی تعریف bind-Value@ در سمت والد، معادل سیم کشی خودکار به ValueChanged و ValueExpression از طرف Blazor است و تعریف دستی آنها ضرورتی ندارد. اما میتوان bind-Value@ را هم تعریف نکرد و فقط نوشت Value. در این حالت از تنظیمات ب و ج صرفنظر میشود. بنابراین ضروری است که بررسی کنیم آیا پارامتر ValueChanged واقعا متصل به روال رویدادگردانی شدهاست یا خیر. اگر خیر، نیازی به اطلاع رسانی و فراخوانی متد ValueChanged.InvokeAsync نیست.