Привязка данных в Blazor: как распространять значения из компонента? - PullRequest
0 голосов
/ 20 сентября 2019

У меня есть довольно простой компонент, который выглядит следующим образом:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               @bind="@Value" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

    [Parameter]
    public string Value { get; set; }
}

Теперь я добавляю это на страницу примерно так:

<MVVMTest Value="@_value" />
<p>
    You entered in MVVMTest:
    @_value
</p>

@functions {
    private string _value;
}

Когда я ввожу текст в поле вводаполе, оно корректно обновляется на Вы ввели здесь: , но не передали * Вы ввели в MVVMTest ":

MVVM not working

Чтомне нужно сделать, чтобы это правильно распространялось?

Я мог бы подумать о подключении Action<string> в качестве второго [Parameter], который я запускаю внутри компонента, когда текст изменяется, но это похоже нахакский и окольный путь. Это как это нужно сделать, или есть лучший способ?

Followup 1

Ответ от Иссака не работает, потому что он спотыкается о @bind-value:oninput="@((e) => ValueChanged.Invoke(e.Value))" сCannot convert lambda expression to type 'object' because it is not a delegate type.

Я должен был сделать это окольным путем:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               @bind="@Value" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

    private string _value;

    [Parameter]
    public string Value {
        get => _value;
        set {
            if(Equals(value, _value)) {
                return;
            }
            _value = value;
            OnValueChanged.InvokeAsync(value).GetAwaiter().GetResult();
        }
    }

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

И использовать это как:

@inject HttpClient http
@page "/test"
<div class="top-row px-4">
    Test Page
</div>

<div class="content px-4">
    <MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
    <p>
        You entered in MVVMTest:
        @_value
    </p>
</div>

@functions {
    private string _value;
}

Не красиво, но это работает.Мой «настоящий» компонент более сложен, так как измененное значение вызывает вызовы к базовой службе ASP.net Core, поэтому я должен сделать детальнуюобнаружение, кто меняет то, что нужно избегать бесконечных циклов.

Конечно, было бы лучше, если бы Blazor поддерживал XAML / WPF-подобный MVVM, хотя ...

Followup 2

Я вернулсяк решению Иссака и с дополнительным приведением, я заставил его работать:

<form>
    <div class="form-group">
        <label for="sampleText">Sample Text</label>
        <input type="text"
               class="form-control"
               id="sampleText"
               aria-describedby="sampleTextHelp"
               placeholder="Enter a text"
               value="@Value"
               oninput="@((Func<ChangeEventArgs, Task>)(async e => await OnValueChanged.InvokeAsync(e.Value as string)))" />
        <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
    </div>
</form>
<p>You entered here: @Value</p>

@code {

    private string _value;

    [Parameter]
    public string Value { get; set; }

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

Использование:

<MVVMTest Value="@_value" OnValueChanged="@(v => _value = v)" />
<p>
    You entered in MVVMTest:
    @_value
</p>

@functions {
    private string _value;
}

Это уже известная проблема в Blazor.Я споткнулся об этом уже на прошлой неделе и опубликовал обходной путь на форуме разработчиков VS .

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Для этого необходимо добавить параметр EventCallback:

@code {

    [Parameter]
    public string Value { get; set; }

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

прочитать раздел Привязка данных / Параметры компонента

0 голосов
/ 20 сентября 2019

Первое решение:

  • Определить пару Value и сопутствующее ей событие ValueChanged, соответствующее типу параметра Value
  [Parameter]
  public string Value { get; set; }

   [Parameter]
   public EventCallback<string> ValueChanged { get;set; }
  • Добавьте к входному тегу атрибут value, связанный со свойством Value, например: value="@Value" Также добавьте директиву @oninput, значением которой является локальный метод, который вызывается при вводе в текстовое поле @oninput="@OnValueChanged"

    Обратите внимание, что метод OnValueChanged обновляет значение свойства Value, а затем вызывает ValueChanged EventCallback «делегат» для обновления свойства _value, определенного в родительском компоненте.

Обратите внимание, чтоДиректива @bind не используется в этом решении.В следующем решении я продемонстрирую, как его использовать.

form>
            <div class="form-group">
                <label for="sampleText">Sample Text</label>
                <input type="text"
                       class="form-control"
                       id="sampleText"
                       aria-describedby="sampleTextHelp"
                       placeholder="Enter a text"
                       value="@Value"
           @oninput="@OnValueChanged"  
                       />
                <small id="sampleTextHelp" class="form-text text-muted">Enter a text to test the databinding</small>
            </div>
        </form>
        <p>You entered here: @Value</p>

        @code {
           private string value;

        [Parameter]
        public string Value
        {
            get
            {
                return this.value ?? "";
            }
            set
            {
                if (this.value!= value)
                {
                    this.value= value;
                }
            }
        }

            [Parameter]
            public string Value { get; set; }

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

           private Task OnValueChanged(ChangeEventArgs e)
        {
            Value = (string)e.Value;
            return ValueChanged.InvokeAsync(Value );
        }
        }  

Использование:

<MVVMTest bind-Value="@_value" />
<p>
    You entered in MVVMTest:
    @_value
</p>

@code {
     public string _value  { get; set; }

}

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

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