Search code examples
c#blazorparameter-passingblazor-webassemblyeventhandler

How to pass EventHandler as parameter in Blazor


Trying to pass an EventHandler to a Blazor component. Error I'm getting: The event AppState.IntegerChanged can only appear on the left hand side of +=

Seems like this should work, is it a blazor limitation or am I doing something wrong?

Getting compiler error in MixedNumber.razor trying to assign event to ValueChanged.

Thanks

MixedNumber.razor

@inject AppState AppState      
      
<CustomInput [email protected]> </CustomInput>
<CustomInput [email protected]> </CustomInput>
<CustomInput [email protected]> </CustomInput>

@code {
    [Parameter] public EventHandler<CustomValidationResult> ValueChanged { get; set; }

    public void MixedValueChanged()
    {
        CustomValidationResult result = new() { Integer = 1, Numerator = 10, Denominator = 100 };
        AppState.OnMixedChanged(result);
    }

    public class CustomValidationResult
    {
        public double Integer { get; set; }
        public double Numerator { get; set; }
        public double Denominator { get; set; }
    }
}

CustomInput.razor

@code {
    [Parameter] public EventHandler<double>? ValueChanged { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        ValueChanged += valueChanged;
    }

    public void valueChanged(object sender, double newValue)
    {
        //do something
    }

}

AppState.cs

public class AppState
{
    public static event EventHandler<double>? IntegerChanged;
    public static event EventHandler<double>? NumeratorChanged;
    public static event EventHandler<double>? DenominatorChanged;

    public static void OnMixedChanged(MixedNumber.CustomValidationResult result)
    {
        IntegerChanged?.Invoke(new object(), result.Integer);
        NumeratorChanged?.Invoke(new object(), result.Numerator);
        DenominatorChanged?.Invoke(new object(), result.Denominator);
    }

}

Solution

  • is it a blazor limitation

    No.

    or am I doing something wrong?

    Yes.

    public static event EventHandler<double>? IntegerChanged;

    An event is a special kind of property, only stricter. It does not even allow read-access, only (un)subscribing with += and -=. It protects abuse of the underlying delegate that is a value type.

    You code as-is will compile when you simply remove the event keyword. But it won't work because you subscribe to a copy of the delegate. And when you think that is confusing: that is why the event mechanism was invented.

    And there is a strong Blazor guideline against setting a [Parameter] from the inside.

    Now for a solution: I don't see a need for an event here. It's much simpler.

    Give CustomInput a Value property and you're done. You can use OnParameterSet() to react to a value change. And since it is an Input, you probably want to include a Callback.

    @code {
        [Parameter] 
        public double Value { get; set; } // don't use the set in this file
    
        [Parameter] 
        public EventCallback<double> ValueChanged { get; set; } // same
    
        ...  ValueChanged.InvokeAsync(localValue);
    }
    
    @inject AppState AppState      
          
    <CustomInput @[email protected]> </CustomInput>
    
    // or:
    
    <CustomInput [email protected] ValueChanged=AppState.NumeratorChanged > </CustomInput>