Closed gurunathancs1991 closed 5 years ago
A workaround (maybe even the correct way):
<GenericEvents TValue="string" EventOne="@EventOne"></GenericEvents>
I agree that this still seems like an issue as creating verbose markup when handling events (without databinding).
Take the InputSelect
for example. ValueChanged
either requires T
to be defined or a lambda expression within ValueChanged
. Compounding the problem is ValueExpression
which is also required, this is leading to some very clumsy looking markup @(()=>
. This isn't going to be the DX people expect when coming from jQuery, WebForms or even React.
<p>Current value: @form.MyProperty</p>
<EditForm Model="form">
<InputSelect ValueChanged="@DoThing"
T="string"
ValueExpression="@(()=> form.MyProperty)">
<option value="0">0</option>
<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>
</InputSelect>
</EditForm>
@code {
MyForm form = new MyForm();
void DoThing(string s)
{
form.MyProperty = s;
}
public class MyForm
{
public string MyProperty { get; set; }
}
}
<InputSelect ValueChanged="@((string s) => DoThing(s))"
ValueExpression="@(()=> form.MyProperty)">
<option value="0">0</option>
<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>
</InputSelect>
From what I can tell, the problem is that the compiler does not use the the generic type parameter for type inference in method calls. Here's a fairly trivial example:
public void Foo()
{
Tester<int>(2, TestAction);
// This fails complaining about type inference
Tester<int>(2, CreateDelegate(TestAction));
}
public void TestAction(int x) { }
public void Tester<T>(T value, Action<T> input) { }
public static Action<T> CreateDelegate<T>(Action<T> action) => action;
We effectively get the same code when we code-gen a Razor file like this:
<InputSelect ValueChanged="ChangedInt" />
@code {
public void ChangedInt(int value)
{
}
}
using Microsoft.AspNetCore.Components;
namespace razor1.Pages
{
public class Index : Microsoft.AspNetCore.Components.ComponentBase
{
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder)
{
__Blazor.razor1.Pages.Index.TypeInference.CreateInputSelect_0(builder, 0, 1, Microsoft.AspNetCore.Components.EventCallback.Factory.Create(this,
ChangedInt
));
}
public void ChangedInt(int value)
{
}
}
}
namespace __Blazor.razor1.Pages.Index
{
internal static class TypeInference
{
public static void CreateInputSelect_0<T>(global::Microsoft.AspNetCore.Components.RenderTree.RenderTreeBuilder builder, int seq, int __seq0, global::Microsoft.AspNetCore.Components.EventCallback<T> __arg0)
{
builder.OpenComponent<global::Microsoft.AspNetCore.Components.Forms.InputSelect<T>>(seq);
builder.AddAttribute(__seq0, "ValueChanged", __arg0);
builder.CloseComponent();
}
}
}
The compiler fails the type inferrence, picks the wrong overload for EventCallback.Factory.Create
and generates the method group conversion error reported here.
From playing around, one of the ways to solve this would be to modify the code in TypeInference
to pass the Action<T>
in and produce the EventCallback<T>
in there. This works well, but we now have the pain of having to code-gen an overload per overload of EventCallback.Factory.Create<T>
. Changing the code-gen is going to be fairly involved, so I'm sending it back to triage to consider for a later release.
Workarounds that have been pointed out by others in the thread that work:
1) Specify the type parameter
<InputSelect T="int" ValueChanged="ChangedInt" />
(I filed an issue to do a pass over blazor input elements to consider renaming T
to TValue
or something slightly better)
2) Use a delegate or perform an explicit cast
<InputSelect ValueChanged="(int x) => ChangedInt(x)" />
<InputSelect ValueChanged="(Action<int>)ChangedInt" />
Thanks for contacting us, @gurunathancs1991. As @pranavkm has pointed out, you will have to go with one of the provided workarounds here. Type inference will always have limitations and it's unfortunate that this is one of them.
EdCharbeneau commented on 23 Jul wrote: but this solution is not working with ASP.NET Core and Blazor updates in .NET Core 3.0 Preview 9.19424.4
Current value: @form.MyProperty
@code { MyForm form = new MyForm();
void DoThing(string s)
{
form.MyProperty = s;
}
public class MyForm
{
public string MyProperty { get; set; }
}
} <InputSelect ValueChanged="@((string s) => DoThing(s))" ValueExpression="@(()=> form.MyProperty)">
<option value="100">100</option>
<option value="200">200</option>
<option value="300">300</option>
Sorry my mistake: EdCharbeneau was OK: the solution works very well
Description:
When using
EventCallBack<T>
, I countered an issue abouterror CS1503: Argument 2: cannot convert from 'method group' to 'EventCallback'
I have checked other github blogs which related to this, mostly reported that, this has been fixed in preview 7 version. Right now, i have tested with preview 7 build but could not get resolve it.
Here the link which i checked earlier. https://github.com/aspnet/AspNetCore/issues/10077 https://github.com/aspnet/AspNetCore/issues/8385 https://github.com/aspnet/AspNetCore/pull/10730 https://github.com/aspnet/AspNetCore/issues/10077
Whether any syntax changes required to resolve in preview 7 version?
Screenshot:
Please find my component structure:
Rendering Page [Index razor page]
MyGenComponent.razor
Events.razor
GenericEvents.razor
NonGenericEvents.razor
To Reproduce
Clone this Github repository and run the application
https://github.com/gurunathancs1991/BlazorGenericEvents
We are also expecting the solution for this thread too
https://github.com/aspnet/AspNetCore/issues/12116
Additional context