admin管理员组

文章数量:1391937

I can't seem to solve this without using integers or different class or event names per button (which isn't scalable). I have a custom ripple-effect that I've created in Blazor and need each button on the page to receive a "ripple" class when clicked and then remove that class after a second or two.

@using System.Timers
<button class="primary-btn @buttonClass" @onclick="AddRipple">Action 1</button>
<button class="primary-btn @buttonClass" @onclick="AddRipple">Action 2</button>
@code {
    // Set Ripple Class
    private string buttonClass = "";
    private void AddRipple()
    {
        buttonClass = "ripple";
        StartTimer();
    }
    private void StartTimer()
    {
        var timer = new Timer(1000);
        timer.Elapsed += RemoveClass;
        timer.AutoReset = false;
        timer.Start();
    }
    private void RemoveClass(object source, ElapsedEventArgs e)
    {
        buttonClass = "";
        ((Timer)source).Dispose();
        InvokeAsync(StateHasChanged);
    }
}

I have created and tested this functionality, but it applies the class change to every button on the page when any one button is clicked. How can I make the event fire and apply only the class change on the actual button clicked?

--UPDATE-- I created a custom razor component and that worked beautifully. I should have realized that! DOH! Here is a step by step guide if anyone is new at this like me:

I can't seem to solve this without using integers or different class or event names per button (which isn't scalable). I have a custom ripple-effect that I've created in Blazor and need each button on the page to receive a "ripple" class when clicked and then remove that class after a second or two.

@using System.Timers
<button class="primary-btn @buttonClass" @onclick="AddRipple">Action 1</button>
<button class="primary-btn @buttonClass" @onclick="AddRipple">Action 2</button>
@code {
    // Set Ripple Class
    private string buttonClass = "";
    private void AddRipple()
    {
        buttonClass = "ripple";
        StartTimer();
    }
    private void StartTimer()
    {
        var timer = new Timer(1000);
        timer.Elapsed += RemoveClass;
        timer.AutoReset = false;
        timer.Start();
    }
    private void RemoveClass(object source, ElapsedEventArgs e)
    {
        buttonClass = "";
        ((Timer)source).Dispose();
        InvokeAsync(StateHasChanged);
    }
}

I have created and tested this functionality, but it applies the class change to every button on the page when any one button is clicked. How can I make the event fire and apply only the class change on the actual button clicked?

--UPDATE-- I created a custom razor component and that worked beautifully. I should have realized that! DOH! Here is a step by step guide if anyone is new at this like me: https://toxigon/building-reusable-components-in-blazor

Share Improve this question edited Mar 14 at 13:46 jottin asked Mar 14 at 0:59 jottinjottin 4312 silver badges13 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 1

Your thinking about this the wrong way. Build the functionality into a custom button component. Totally scalable.

Here's a demo MyButton component that changes colour for 2 seconds. It uses the primitive System.Threading.Timer to load a one time timer task onto the application timer. When this expires it calls OnTimerExpired which renders the component. The component implements IDisposable to clear down any running timers when the component is disposed.

@implements IDisposable

<button class="@_buttonClass" @onclick="AddRipple">@ChildContent</button>

@code {
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public EventCallback OnClick { get; set; }

    private IDisposable? _disposer;
    private bool _rippling;
    private string _buttonClass => _rippling ? "btn btn-danger" : "btn btn-success";

    private async Task AddRipple()
    {
        _rippling = true;
        _disposer = new System.Threading.Timer(this.OnTimerExpired, null, TimeSpan.FromSeconds(2), TimeSpan.Zero);
        await OnClick.InvokeAsync();
    }

    private void OnTimerExpired(object? data)
    {
        _rippling = false;
        this.InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        _disposer?.Dispose();
    }
}

See https://shauncurtis.github.io/Posts/Timers.html for more detailed info on timers.

From my understanding you need a list to control the state of each button class which uses independent timer.

@page "/"
<style>
    .ripple{
    color:red;
    }
</style>

@using System.Timers
<button  class="primary-btn @buttonClass[1]" @onclick="()=>AddRipple(1)">Action 1</button>
<button  class="primary-btn @buttonClass[2]" @onclick="()=>AddRipple(2)">Action 2</button>

@code {
    //create list of 3 items to match index 1 and 2.
    private List<string> buttonClass = new List<string>(new string[3]);

    private void AddRipple(int i)
    {
        buttonClass[i] = "ripple";
        StartTimer(i);
    }
    private void StartTimer(int i)
    {
        var timer = new Timer(1000);
        timer.Elapsed += (sender,e)=> RemoveClass(sender,e,i);
        timer.AutoReset = false;
        timer.Start();
    }
    private void RemoveClass(object source, ElapsedEventArgs e,int i)
    {
        buttonClass[i] = "";
        ((Timer)source).Dispose();
        InvokeAsync(StateHasChanged);
    }
}

本文标签: