1

Is it possible to do the following using the new Blazor framework?

I have a page that displayed a list of people. The list is essentially a bindable list of Person objects.

Desired Result I would like to show each person fade-in independently of each other.

For example: The 1st row starts fading in first. The Nth row person will be the last to fade in.

What I tried I've tried a couple of things using Task.Delay() and tried to get Dispatcher.BeginInvoke() to work.

But now i am starting to think this is not possible without doing some kind of hack.

Is this kind of effect even possible via Blazor? Is there a Dispatcher.BeginInvoke() equivalent?

AlvinfromDiaspar
  • 6,611
  • 13
  • 75
  • 140
  • Dispatcher and Task.Delay are used in multi-threaded environments. Blazor is single-threaded in its current form. You would likely have to use some jquery or css to get your desired effect. – Laurence73 May 03 '19 at 12:01

1 Answers1

3

One option, if your Blazor application is run on client-side, is to use a combination of CSS3 animations to fade in rows and a Task.Delay to add rows delayed.

I will give you an example based on the default Blazor (.NET core 3.0 preview 3) template.

Inspired by this SO answer you could add the following CSS class to your site.css or some costom CSS file:

.fadein {
    -webkit-animation: fadein 1s; /* Safari, Chrome and Opera > 12.1 */
    -moz-animation: fadein 1s; /* Firefox < 16 */
    -ms-animation: fadein 1s; /* Internet Explorer */
    -o-animation: fadein 1s; /* Opera < 12.1 */
    animation: fadein 1s;
}

@keyframes fadein {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* Firefox < 16 */
@-moz-keyframes fadein {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* Safari, Chrome and Opera > 12.1 */
@-webkit-keyframes fadein {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/* Internet Explorer */
@-ms-keyframes fadein {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

Now we will modify the FetchData.razor page, which by default shows a HTML table with some forecast info.

First we add a style class to the table rows <tr> as following:

@foreach (var forecast in forecasts)
{
    <tr class="fadein">
        <td>@forecast.Date.ToShortDateString()</td>
        <td>@forecast.TemperatureC</td>
        <td>@forecast.TemperatureF</td>
        <td>@forecast.Summary</td>
    </tr>
}

Next we will change the type of the forecasts from an array to a List:

List<WeatherForecast> forecasts = new List<WeatherForecast>();

As a last step we replace the forecasts preparation in the OnInitAsync with the following call:

protected override async Task OnInitAsync()
{
    await FadeInItems();
}

and add the method for the delayed fading in:

private async Task FadeInItems()
{
    var items = await Http.GetJsonAsync<WeatherForecast[]>("sample-data/weather.json");

    // don't forget to use the desired sorting / filtering on your collection
    foreach (var item in items)
    {
        forecasts.Add(item);
        base.StateHasChanged();
        await Task.Delay(500);
    }
}

And this should be your result: fade in animation

Based on this demo, you should now be able to apply this method to your Person model and individual razor page(s). Ofcourse the animation, delay and other things are just an example and can be customized.

Raul
  • 2,745
  • 1
  • 23
  • 39
  • Thanks. This is very very thorough! Where does base.StateHasChanged(); come from though? – AlvinfromDiaspar May 06 '19 at 06:12
  • Also, my async function is in the View Model. And the compiler is complaining that i cant directly await a Task without calling ConfigureAwait. – AlvinfromDiaspar May 06 '19 at 06:13
  • 1
    The `StateHasChanged()` signals Blazor to render the page using `WASM`, as the state has changed. You can call the async method in your ViewModel just replace the default `protected override void OnInit()` with `protected override Task OnInitAsync()` like in the above example. – Raul May 06 '19 at 06:33
  • 1
    Two ways to do that: either pass the base class of the page to the ViewModel or cleaner add an event `ViewModelChanged` to your ViewModel and let the page subscribe to it, calling StateHasChanged whenever the ViewModel changed. I am traveling right now, I can give you an example later on, invite me to a SO chat room to keep the comments shorts. – Raul May 06 '19 at 06:43
  • Hi Raul, i have everything compiling with debug outputs to verify the delayed adding of objects. Indeed they are behaving as i expect. However, the UI has all objects fading in at the same time. Any ideas? BTW - i had to do Task.Delay(500).ConfigureAwait(true) – AlvinfromDiaspar May 06 '19 at 15:40
  • In fact, i can see that the view's StateHasChanged is being invoked in a delayed fashion (as expected). But upon deeper analysis, I can see that the UI renders after all task.delays are done. – AlvinfromDiaspar May 06 '19 at 16:09
  • Oh. I think i found the issue. I am not running Blazor as client-side. Dang it. – AlvinfromDiaspar May 06 '19 at 16:37