Когда использовать ValueChanged и ValueExpression в Blazor? - PullRequest
3 голосов
/ 12 марта 2020

Я вижу этот общий шаблон в некоторых библиотеках (MatBlazor, Telerik), имеющий свойства ValueChanged и ValueExpression, и это меня действительно смущает.

В чем разница между обоими? И когда его использовать?

Ответы [ 2 ]

2 голосов
/ 12 марта 2020

На самом деле вы забыли о третьем элементе: Значение.

Эта троица используется при двухстороннем связывании данных с компонентом, и акцент делается на компонент. Он в основном используется в компонентах Blazor Forms, таких как InputText. Значение - это свойство, которое должно быть предоставлено в форме @bind-Value="model.PropertyName", например:

<InputText @bind-Value="employee.FirstName" />

ValueChanged имеет тип EventCallback<TValue> и обозначает обратный вызов, который обновляет связанное значение

Как видите, я здесь не пользуюсь. Это необязательно. Компилятор знает свою работу, и он позаботится об этом, что означает, что он добавляет «делегат» EventCallback со всеми необходимыми настройками за вашей спиной.

Что касается ValueExpression; это относится к выражению, которое идентифицирует связанное значение. Он автоматически создается компилятором, и вам редко, если когда-либо придется его устанавливать.

Теперь сравните вышеприведенное с приведенным ниже кодом, который создает двустороннюю привязку данных между родительским компонентом и дочерним компонентом. Обратите внимание, что я не использую троицу (Value, ValueChanged и т. Д. c.), Но сам шаблон:

ParentComponent.razor

@page "/ParentComponent"

<h1>Parent Component</h1>

<ChildComponent @bind-Text="Text" /> 

ChildComponent.razor

    @code {

    [Parameter]
    public string Text
    {
        get { return text; }
        set
        {
            if (text != value) {
                text = value;
                if (TextChanged.HasDelegate)
                {
                    TextChanged.InvokeAsync(value);
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> TextChanged { get; set; }
  }

Это то же самое, верно?

Надеюсь, это поможет ...

Когда я буду использовать ValueChanged и ValueExpression в Blazor ?? Я создаю оболочку для ввода из другой библиотеки, это случай для использования этой троицы?

Как я уже говорил выше, ValueChanged и ValueExpression - это свойства, определенные в компоненте InputText, и в большинстве случаев вы ими не пользуетесь.

Теперь еще раз посмотрите на два компонента, которые я определил выше, ParentComponent и ChildComponent. Измените Text и TextChanged на Value и ValueChanged, и мои компоненты все еще действительны и работают. Это только наименование. Что мне делать в ChildComponent? Определите свойство параметра с именем Text (расшифровывается как Value). Поскольку я хочу включить двустороннюю привязку данных между родительским компонентом и дочерним компонентом, мне также необходимо определить свойство параметра, называемое здесь TextChanged (расшифровывается как ValueChanged). Текст переходит к TextChanged, значение переходит к ValueChanged, а год переходит к YearChanged. И это именование является лишь условным обозначением. Главное, что вы должны определить свойство и EventCallback одного и того же типа данных свойства. В родительском компоненте вы предоставляете свойство следующим образом:

<ChildComponent @bind-Text="NameOfAPropertyDefinedInTheParentComponent" /> or `<ChildComponent @bind-Value="NameOfAPropertyDefinedInTheParentComponent" />` or <ChildComponent @bind-Year="NameOfAPropertyDefinedInTheParentComponent" />

В моих компонентах выше также есть код, как, например, в дочернем компоненте, который вызывает TextChanged «делегат» для передачи значения для родительского компонента это именно то, что «делегат» ValueChanged делает в компонентах, в которых он определен. Но вы как пользователь не должны использовать его. Посмотрите на мои компоненты ... Это прекрасно работает. Не нужно трогать. Если вы, как пользователь моего компонента, хотите создать его подкласс, вам нужно знать, что вы делаете, и как правильно создать подкласс компонента Blazor. Но мои компоненты, частично представленные здесь, относительно просты. Предположим, вы хотите создать текст для ввода пароля на основе InpuText, что не только выполнимо, но и довольно просто ... в этом случае вы не собираетесь ничего менять, кроме внешнего вида компонента InputText, чтобы вместо звездочек отображались символы нормальный текст. Остальная часть компонента не изменилась. Вы не обрабатываете события и так далее. Это, конечно, не означает, что автору компонента никогда не понадобится вызывать EventCallback где-то в его коде. Лично у меня никогда не было веской причины для запуска делегата ValueChanged при использовании компонента InputText. И я только однажды должен был предоставить ValueExpression, так как компилятор не смог идентифицировать связанное значение. Я поищу это, и если я найду это, я отправлю это здесь ...

0 голосов
/ 01 апреля 2020

Я хотел бы добавить несколько вариантов использования для ValueChanged и ValueExpression,

Прежде всего, как сказал enet, эти свойства больше похожи на троицу свойств, в которых у вас есть Foo, FooChanged и FooExpression и используется в двухсторонней привязке данных, например, @bind-Foo="SomeProperty".

Чтобы создать пользовательский компонент со свойством, которое можно использовать с @bind-, необходимо укажите эти 3 свойства (только при условии, что Foo и FooChanged также работают) как [Parameter] и вызовите FooChanged, когда свойство в вашем пользовательском компоненте изменится.

например, с enet

[Parameter]
public TValue Foo
{
    get => text
    set
    {
        if (text != value) {
            text = value;
            if (FooChanged.HasDelegate)
            {
                FooChanged.InvokeAsync(value);
            }
        }
    }
}

[Parameter]
public EventCallback<TValue> FooChanged { get; set; }

[Parameter]
public Expression<Func<TValue>> FooExpression { get; set; }  

Добавление @bind-Foo будет аналогично передаче Value и ValueChanged, с той лишь разницей, что @bind- будет устанавливать только свойство, но если вы добавите свой собственный ValueChanged, вы можете делайте все, что хотите (проверка, изменение значения для установки и т. д. c).

сценарии использования

1 - создание компонента, который переносит другой компонент с помощью @bind-

Если у вас есть компонент, который уже имеет @bind-Foo, и вы хотите создать компонент поверх это и все еще передать в качестве параметра @bind-Foo, вы можете иметь только одно свойство и передать @bind-Foo, вам нужно передать свойства Foo, FooChanged и / или FooExpression.

например

CustomInputWrapper.razor

<div>
    <p>My custom input wrapper</p>
    @* If you pass @bind-Value it won't work*@
    @* You need to pass the properties that are used in the bind*@
    <InputText Text="@Value" TextChanged="@ValueChanged" TextExpression="@ValueExpression" />
</div>

@code {    
    [Parameter]
    public virtual string Value { get; set; }

    [Parameter]
    public EventCallback<string > ValueChanged { get; set; }

    [Parameter]
    public Expression<Func<string >> ValueExpression { get; set; }        
}

Такая ситуация с обертыванием другого компонента часто случается, если вы создаете много пользовательских компонентов или не хотите напрямую использовать какой-либо сторонний компонент.

Пример моего проекта: в моем проекте я использую MatBlazor и Telerik, но не все компоненты в обеих библиотеках полностью стабильны, поэтому я создал оболочку для всех компонентов и однажды, когда одна из этих библиотек полностью стабильна, я буду использовать только одну библиотеку. Это позволяет мне иметь свои собственные компоненты, и если я хочу изменить один, я изменяю только одну вещь в своем пользовательском компоненте и изменяю все приложение.

2 - Добавление значения по умолчанию

Если вы хотите иметь значение по умолчанию в пользовательском компоненте , вы можете просто передать значение по умолчанию свойству.

[Parameter]
public virtual DateTime Value { get; set; } = new DateTime(/* some default value*/);

Но это будет большой проблемой, если вы используете это компонент внутри формы.

Почему ? Потому что вы будете изменять только значение внутри вашего компонента, но если свойство будет передано в @bind-Value, оно не будет изменено.

Чтобы добавить это значение по умолчанию и заставить его работать в двустороннем связывании данных Вам нужно позвонить ValueChanged и передать значение по умолчанию. Это заставит ваш компонент иметь значение по умолчанию, а также изменит любое свойство в @bind-Value на значение по умолчанию.

например

// Lifecycle after all parameters are set
protected override void OnParametersSet()
{
    // Check if the ValueChanged is set
    if (ValueChanged.HasDelegate)
    {
        ValueChanged.InvokeAsync(DateTime.Now);
    }
}

3 - используйте тот случай, когда вам действительно нужно FooExpression

... эту часть я пока не знаю, но я действительно ее ищу. Как только я найду его, обновлю здесь.


Вариант использования этих свойств будет использоваться больше, если вы создаете пользовательские компоненты и должны работать со свойством binded или изменить способ работы привязки.

Если вы используете только уже изготовленные компоненты, то в редких случаях вам придется его использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...