Skip to content

Strange behavior in events #16410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
uazo opened this issue Mar 16, 2018 · 4 comments
Closed

Strange behavior in events #16410

uazo opened this issue Mar 16, 2018 · 4 comments
Labels
area-blazor Includes: Blazor, Razor Components

Comments

@uazo
Copy link
Contributor

uazo commented Mar 16, 2018

Example:

@for( var page = FirstPage; page <= LastPage; page++ )
{
	<li class="@(this.Values.CurrentPage==page ? "active" : "page-item")">
		<a href="javascript:;" class="page-link" @onclick(() => InvokePageChanged(page))>@(page+1)</a>
	</li>
}

The value of "Page" in InvokePageChanged is always "LastPage".

The only way to make it work is:

@for( var page = FirstPage; page <= LastPage; page++ )
{
	int current = int.Parse(page.ToString());
	<li class="@(this.Values.CurrentPage==page ? "active" : "page-item")">
		<a href="javascript:;" class="page-link" @onclick(() => InvokePageChanged(current))>@(page+1)</a>
	</li>
}
@rstropek
Copy link

As far as I can see, only your working solution turns the lambda function invoking InvokePageChanged into a closure capturing the value of page. See e.g. this StackOverflow post for a more detailed description of the topic.

Does that help?

@uazo
Copy link
Contributor Author

uazo commented Mar 16, 2018

I had already tried with

@for( var page = FirstPage; page <= LastPage; page++ )
{
	int current = page;
	<li class="@(this.Values.CurrentPage==page ? "active" : "page-item")">
		<a href="javascript:;" class="page-link" @onclick(() => InvokePageChanged(current))>@(page+1)</a>
	</li>
}

but it does not work..

the only way is to turn it into a string.
Maybe some optimization of the compiler?

@rstropek
Copy link

Hmm, I tried that and it worked:

@for (var page = 0; page <= 5; page++)
{
    var helper = page;
    <button @onclick(() => InvokePageChanged(helper))>@(helper)</button>
}

@functions {
    void InvokePageChanged(int page)
    {
        Console.WriteLine(page);

    }
}

I also expected it to work because the generated code looks like that:

...
for (var page = 0; page <= 5; page++)
{
    var helper = page;
    ...
    builder.AddAttribute(13, onclick(() => InvokePageChanged(helper)));
    ...
}
...

@SteveSandersonMS
Copy link
Member

SteveSandersonMS commented Mar 16, 2018

Yes, I also just tried that and confirmed it works OK. There's no need to do the conversion to string and back again.

The necessity to declare a variable inside your loop is just how C# lambdas work - they bind to a variable, not to the value that was in the variable when the lambda was constructed. The StackOverflow that @rstropek linked to is a good source of info about this. Also note how it's different if you use foreach instead of for, because foreach logically declares a new variable for each iteration.

@mkArtakMSFT mkArtakMSFT transferred this issue from dotnet/blazor Oct 27, 2019
@mkArtakMSFT mkArtakMSFT added the area-blazor Includes: Blazor, Razor Components label Oct 27, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Dec 4, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

No branches or pull requests

4 participants