首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何创建自定义Blazor多选择HTML组件?错误: MultipleSelect需要“ValueExpression”参数的值

如何创建自定义Blazor多选择HTML组件?错误: MultipleSelect需要“ValueExpression”参数的值
EN

Stack Overflow用户
提问于 2022-05-19 00:03:37
回答 1查看 336关注 0票数 1

我正在创建一个自定义Blazor多选择HTML组件。它可以工作,直到我添加验证。此外,如果我禁用多个select,并保留验证,它可以工作。

当多个select (带有验证的)打开时,我得到以下错误:

InvalidOperationException: MultipleSelect requires a value for the 'ValueExpression' parameter. Normally this is provided automatically when using 'bind-Value'.

我无法使用“绑定值”属性,因为我得到了这个错误。

到目前为止,我所找到的文档只针对在不使用多重选择选项时从HTML元素构建自定义组件的问题。

如何创建启用多个select的<select>元素?

自定义多选择组件

MultipleSelect.razor

代码语言:javascript
复制
@using CustomComponents.DataModels
@using System.Linq.Expressions
@using System
@using System.Collections.Generic
@inherits InputBase<string>

<div class="row">
    <div class="col-3">
        <select id="@Id" @bind=@CurrentValue class="form-control @CssClass" multiple="multiple" size="@BoxHieght" style="width:@BoxWidth">
            @foreach (var option in Options)
            {
                <option @onclick="@(() => SelectOption(option))" value="@option.Value">@option.Text</option>
            }
        </select>
    </div>
</div>

@code {
    [Parameter]
    public string Id { get; set; }
    [Parameter]
    public List<Option> Options { get; set; } = new List<Option>();
    [Parameter]
    public Option SelectedOption { get; set; } = new Option { Text = " ", Value = " " };
    [Parameter]
    public int BoxHieght { get; set; } = 5;
    [Parameter]
    public string BoxWidth { get; set; } = "auto";
    [Parameter, EditorRequired]
    public Expression<Func<string>> ValidationFor { get; set; } = default!;

    private void SelectOption(Option option)
    {
        SelectedOption = option;
    }
    protected override bool TryParseValueFromString(string value, out string result, out string validationErrorMessage)
    {
        try
        {
            result = value;
            validationErrorMessage = null;
            return true;
        }
        catch (Exception exception)
        {
            result = null;
            validationErrorMessage = exception.Message;
            return false;
        }

    }    
}

选项数据模型对象

Option.cs

代码语言:javascript
复制
namespace CustomComponents.DataModels
{
    public class Option
    {
        public string Text { get; set; }
        public string Value { get; set; }
    }
}

Web表单模型

FormModel.cs

代码语言:javascript
复制
using CustomComponents.Data.DataModels;

namespace BlazorApp2.Pages.PageModels
{
    public class FormModel
    {
        public Option Option { get; set; } = new Option();
    }
}

数据模型

State.cs

代码语言:javascript
复制
using System.ComponentModel.DataAnnotations;

namespace BlazorApp2.Data.DataModels
{
    public class State
    {
        [Required]
        public string Name { get; set; }
        [Required]
        public string Abbreviation { get; set; }
    }
}

Web表单

Index.razor

代码语言:javascript
复制
@page "/"
@using CustomComponents.Components
@using CustomComponents.Data.DataModels
@using CustomComponents.Pages.PageModels
<PageTitle>Mutiple Select Component</PageTitle>

<EditForm Model="@model" OnValidSubmit="ValidSubmit">  
<DataAnnotationsValidator /> 
<ValidationSummary />
<MyComponent Options="@options" @bind-Value="@model.Option" ValidationFor="() => State.Name"></MyComponent>
Selected option:
<div class="row">
    <div class="col">
        @model.Option.Value  @model.Option.Text
    </div>

</div>
<div class="row">
    <div class="col">
        <button class="btn btn-primary" type="submit">Submit</button>
    </div>
</div>
<div class="row">
    <div class="col">
        @if (formSubmitted) @FormSubmitted
    </div>
</div>
<div class="row">
    <div class="col">
        @if (formSubmitted) @StateSubmitted
    </div>
</div>
</EditForm>

    @code {
    private List<Option> options = new List<Option>();
    public FormModel model = new FormModel();
    public State State { get; set; } = new State();
    private List<State> states = new List<State>
    {
        new State { Name = "Utah", Abbreviation = "UT" },
        new State { Name = "Texas", Abbreviation = "TX" },
        new State { Name = "Florida", Abbreviation = "FL" }
    };
    public string FormSubmitted { get; set; } = "Form submitted.";
    public string StateSubmitted { get; set; } = string.Empty;
    private bool formSubmitted = false;

    protected override void OnInitialized()
    {
        foreach(State state in states)
        {
            options.Add(new Option{ Value = state.Abbreviation, Text = state.Name});
        }
        model.Option = options[0];
    }

    public void ValidSubmit()
    {
        State.Abbreviation = model.Option.Value;
        State.Name = model.Option.Text;
        formSubmitted = true;
        StateSubmitted = $"{State.Abbreviation}  {State.Name}";
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-13 17:55:34

因为继承了组件InputBase,所以必须使用绑定值。我编辑了大量的代码以使其工作。

代码语言:javascript
复制
@using BlazorApp2.Client.Components
@using System.Linq.Expressions
@using System
@using System.Collections.Generic
@using System.Diagnostics.CodeAnalysis
@inherits InputBase<Option>

<div class="row">
    <div class="col-3">
        <select id="@Id" class="form-control" size="@BoxHieght" style="width:@BoxWidth"
        @bind="OptionValueSelected"  @bind:event="oninput">
            @foreach (var option in Options)
            {
                <option value="@option.Value">@option.Text</option>
            }
        </select>

        <p>Selected option:@SelectedOption.Value </p>
    </div>
</div>

@code {
    [Parameter]
    public string Id { get; set; }
    [Parameter]
    public List<Option> Options { get; set; } = new List<Option>();
    [Parameter]
    public Option SelectedOption { get; set; } = new Option { Text = " ", Value = " " };
    [Parameter]
    public int BoxHieght { get; set; } = 5;
    [Parameter]
    public string BoxWidth { get; set; } = "auto";
    [Parameter, EditorRequired]
    public Expression<Func<string>> ValidationFor { get; set; } = default!;

    private string OptionValueSelected
    {
        get => CurrentValue.Value;
        set
        {
            CurrentValue = Options.Find(o => o.Value == value);
        }
    }

    protected override bool TryParseValueFromString(string value,
        [MaybeNullWhen(false)] out Option result, [NotNullWhen(false)] out string validationErrorMessage)
    {
        try
        {
            result = Options.First(o => o.Value == value.ToString());
            validationErrorMessage = null;
            return true;
        }
        catch (Exception exception)
        {
            result = null;
            validationErrorMessage = exception.Message;
            return false;
        }
    }
}

经过很长时间的研究,以下是我所做的一些重要改变:

  • 继承自类型为InputBase的选项,而不是字符串。原因:因此表单上下文知道类型并正确绑定。
  • 将值与带有setter的属性绑定。原因:从字符串转换为选项
  • 从输入基SelectedOption设置CurrectValue的值。原因:提醒表单上下文更改,以便更新主视图。

我在新项目中使用此页面测试了组件:

代码语言:javascript
复制
@page "/"
@using BlazorApp2.Client.Components

<PageTitle>Index</PageTitle>

@code {
    List<Option> options = new List<Option>
    {
        new Option{Text = "Test1", Value = "Test1"},
        new Option{Text = "Test2", Value = "Test2"}
    };
    ExampleModel model;

    protected override void OnInitialized()
    {
        model = new ExampleModel();
    }
}

<h1>Hello, world!</h1>


<EditForm Model="@model">   
<MyComponent Options="@options" @bind-Value="@model.Option"></MyComponent>
</EditForm>
<p>@model.Option.Text : @model.Option.Value</p>

示例模型:

代码语言:javascript
复制
public class ExampleModel
{
    public Option Option { get; set; } = new Option();
}

资源帮助了我的研究:

Blazor元件

Blazor形成组件绑定

Blazor自定义绑定

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72297232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档