首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在我的自定义select blazor组件中进行选择时回调

在我的自定义select blazor组件中进行选择时回调
EN

Stack Overflow用户
提问于 2020-05-17 18:18:44
回答 1查看 663关注 0票数 1

我在修一辆布兹尔·瓦西姆。我想创建自己的自定义select组件。下面的实现可以工作,但是缺少一些东西:在我的自定义select组件中选择某样东西时,不存在回调。我希望能够从我的TestView.razor组件中捕捉到事件。

我的自定义实现InputSelectCustom.cs

代码语言:javascript
复制
public class InputSelectCustom<T> : InputSelect<T>
{
    protected override string FormatValueAsString(T value)
    {
        // Custom code ommitted for clarity
        return base.FormatValueAsString(value);
    }

    protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) 
    {
        if (typeof(T) == typeof(int) ||
            typeof(T) == typeof(int?))
        {
            if (int.TryParse(value, out var resultInt))
            {
                result = (T)(object)resultInt;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else 
        if (typeof(T).IsEnum)
        {
            if (CustomFunctions.EnumTryParse<T>(value, out var resultEnum))
            {
                result = (T)(object)resultEnum;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else
        if (typeof(T).IsNullableEnum())
        {
            if (CustomFunctions.NullableEnumTryParse<T>(value, out var resultEnum))
            {
                result = (T)(object)resultEnum;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else
        {
            return base.TryParseValueFromString(value, out result, out validationErrorMessage);
        }
    }

    protected override Task OnParametersSetAsync()
    {
        return base.OnParametersSetAsync();
    }
}

我的TestView.razor

代码语言:javascript
复制
@page "/test-view"

<EditForm Model="CurrentFilterModel">
    <InputSelectCustom @bind-Value="@CurrentFilterModel.ClassmentFilter">
        <option value="null"> Show all content </option>
        <option value="@EnumClassment.Popular"> Popular </option>
        <option value="@EnumClassment.Featured"> Featured </option>
        <option value="@EnumClassment.Novelty"> Novelty </option>
    </InputSelectCustom>
</EditForm>

@code
{
    public FilterModel CurrentFilterModel = new FilterModel();

    public class FilterModel
    {
        public EnumClassment? ClassmentFilter { get; set; }
    }
}

我的精粹:

代码语言:javascript
复制
public enum EnumClassment
{
    Featured,
    Popular,
    Novelty
}

更新

因此,我需要的是一种每当我所选择的值发生变化时都能得到通知的方式。

一开始,我试着用这个:

代码语言:javascript
复制
<InputSelectCustom @bind-Value="CurrentFilterModel.ClassmentFilter">
    <option value=""> Show all content </option>
    <option value="@EnumClassment.Popular"> Popular </option>
    <option value="@EnumClassment.Featured"> Featured </option>
    <option value="@EnumClassment.Novelty"> Novelty </option>
</InputSelectCustom>

所选的值更改正确,但使用上面的代码,我无法得到有关值更改的通知。根据信息,我需要得到通知,因为每当用户更改选择时,我都想立即执行服务器端对数据过滤的调用。

下面是我的第二次尝试:

代码语言:javascript
复制
<InputSelectCustom @bind-Value="CurrentFilterModel.ClassmentFilter" ValueChanged="ValueChangedForClassmentFilter">
    <option value=""> Show all content </option>
    <option value="@EnumClassment.Popular"> Popular </option>
    <option value="@EnumClassment.Featured"> Featured </option>
    <option value="@EnumClassment.Novelty"> Novelty </option>
</InputSelectCustom>

如您所见,我不能同时使用@bind-ValueValueChanged

所以我的最后一个解决方案是:

代码语言:javascript
复制
<InputSelectCustom Value="@CurrentFilterModel.ClassmentFilter" ValueExpression="@( () => CurrentFilterModel.ClassmentFilter )" ValueChanged="@( (EnumClassment? s) => ValueChangedForClassmentFilter(s) )">
    <option value=""> Show all content </option>
    <option value="@EnumClassment.Popular"> Popular </option>
    <option value="@EnumClassment.Featured"> Featured </option>
    <option value="@EnumClassment.Novelty"> Novelty </option>
</InputSelectCustom>

protected async Task ValueChangedForClassmentFilter(EnumClassment? theUserInput)
{
    // You have to update the model manually because handling the ValueChanged event does not let you use @bind-Value
    // For the validation to work you must now also define the ValueExpression because @bind-Value did it for you
    CurrentFilterModel.ClassmentFilter = theUserInput;
    // Refresh data based on filters
    await FilterCoursesServerSide();
}

这一次,一切都如愿以偿:每当用户选择另一个值时,都会通知我新的值,并且我可以立即执行自定义代码。

请纠正我,如果我错了,或者如果这可以做一个更优雅的方式,因为我是新手,也许我错过了什么。

PS:使用字符串、整数和枚举进行测试。

EN

Stack Overflow用户

回答已采纳

发布于 2020-05-17 19:46:38

你不能那样做,你也不应该那样做。为了什么?但是,您可以像使用单选按钮那样这样做,但是您的自定义组件应该从InputBase派生,并提供Razor标记和逻辑。

当在我的自定义选择组件中选择某些内容时,没有回调。

当然还有回电..。否则,如何使用新值更新您的模型。它是从CurrentValue组件的InputBase属性触发的:

代码语言:javascript
复制
protected TValue CurrentValue
    {
        get => Value;
        set
        {
            var hasChanged = !EqualityComparer<TValue>.Default.Equals(value, 
                       Value);
            if (hasChanged)
            {
                Value = value;
                _ = ValueChanged.InvokeAsync(value);
                EditContext.NotifyFieldChanged(FieldIdentifier);
            }
        }
    }

这是更新模型的代码:

代码语言:javascript
复制
_ = ValueChanged.InvokeAsync(value); 

以下是自定义选择组件的代码。注意,InputSelect不支持诸如int这样的数字类型(不能将它应用到int属性(如public int Country { get; set; } )。也许(不确定,需要检查.)。枚举类型也是如此。我的组件支持这样的价值:

InputSelectNumber.cs

代码语言:javascript
复制
public class InputSelectNumber<T> : InputSelect<T>
{
    protected override bool TryParseValueFromString(string value, out T 
                                 result, out string validationErrorMessage)
    {
        if (typeof(T) == typeof(int))
        {
            if (int.TryParse(value, out var resultInt))
            {
                result = (T)(object)resultInt;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not a valid 
                                                                  number.";
                return false;
            }
        }
        else
        {
            return base.TryParseValueFromString(value, out result, out 
                                                   validationErrorMessage);
        }
    }
 }

用法

代码语言:javascript
复制
  <EditForm EditContext="@EditContext"> 
  <DataAnnotationsValidator />

  <div class="form-group">
    <label for="name">Enter your Name: </label>
    <InputText Id="name" Class="form-control" @bind-Value="@comment.Name"> 
                                                             </InputText>
    <ValidationMessage For="@(() => comment.Name)" />

</div>
<div class="form-group">
    <label for="body">Select your country: </label>
    <InputSelectNumber @bind-Value="@comment.Country">
        <option value="">Select country...</option>
        <option value="1">USA</option>
        <option value="2">Britain</option>
        <option value="3">Germany</option>
        <option value="4">Israel</option>
    </InputSelectNumber>

   <label for="body">Select your country: </label>
    <ValidationMessage For="@(() => comment.Country)" />
</div>

 <p>
    <button type="submit">Submit</button>
 </p>
</EditForm>
<p>Name: @comment.Name</p>
<p>Country: @comment.Country</p>

@code
{
   private EditContext EditContext;
   private Comment comment = new Comment();

   protected override void OnInitialized()
   {
    EditContext = new EditContext(comment);

   }

   public class Comment
  {

    public string Name { get; set; }
    // Note that with the subclassed InputSelectNumber I can use either string 
    // or int. In both cases no error occurs.
    public string Country { get; set; }
    //public int Country { get; set; }
 }
}

每个请求的更新:

请纠正我,如果我错了,或者如果这可以做一个更优雅的方式,因为我是新手,也许我错过了什么。

您的代码很好,您应该这样做。在See my answer here中,我对InputSelect组件做了完全相同的事情。由于您的自定义组件是从InputSelect组件派生出来的,这是最好、最优雅的方法。也许是唯一的办法。

你对巴兹尔来说有多新鲜?;)你的知识超过了这里大多数用户(我指的是那些在这里永久回答问题的用户)。

然而,从表面上看,你想实现的目标,我相信你的方向是错误的。不需要知道select组件的值何时改变了您的操作方式.

相反,您应该为由OnFieldChanged对象公开的EditContext事件实现一个事件处理程序,在该事件处理程序中,可以访问通过事件args传递的新值、操作数据等,甚至可以验证EditContext对象.

一些代码可以指引你:

代码语言:javascript
复制
 private EditContext EditContext;
 private Comment Model = new Comment();

 protected override void OnInitialized()
 {
        EditContext = new EditContext(Model);
        EditContext.OnFieldChanged += EditContext_OnFieldChanged;

        base.OnInitialized();
 }

 // Note: The OnFieldChanged event is raised for each field in the 
                                                 model
    private void EditContext_OnFieldChanged(object sender, 
                                          FieldChangedEventArgs e)
    {
        Console.WriteLine(e.FieldIdentifier.FieldName);

        // more code...

    }

希望这能帮上忙。

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

https://stackoverflow.com/questions/61856605

复制
相关文章

相似问题

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