Search code examples
asp.netasp.net-corerazorblazor

Hide and show components in blazer using timer


I have two Blazor custom components, Hello World 1, and Hello World 2, and a background UI timer on the razor page to hide and show components to demonstrate the proper use of StateChange and Invoke. However, the two components do not toggle the state in 3 seconds.

Index.razor

@page "/index"

<h3>Background Timer Example</h3>

@if (showComponent)
{
  <div class="alert alert-success" role="alert">
    This is a visible component!
  </div>
}

<HelloWorld1 @ref="helloWorld1" />
<HelloWorld2 @ref="helloWorld2" />


<button class="btn btn-primary" @onclick="ToggleComponent">Toggle Component</button>

@code {

  private bool showComponent = true;
  private bool showHelloWorld1 = true;
  private bool showHelloWorld2 = true;

  private HelloWorld1 helloWorld1;
  private HelloWorld2 helloWorld2;

  // Timer interval in milliseconds
  private const int TimerInterval = 3000;

  private System.Threading.Timer timer;

  protected override void OnInitialized()
  {
    // Initialize the timer when the component is first initialized
    timer = new System.Threading.Timer(ToggleComponentVisibility, null, TimerInterval, TimerInterval);
  }

  private async void ToggleComponentVisibility(object state)
  {
    // Toggle the visibility of the component
    showComponent = !showComponent;
   
    // Toggle the visibility of HelloWorld1 component
    showHelloWorld1 = !showComponent;

    // Toggle the visibility of HelloWorld2 component
    showHelloWorld2 = !showComponent;
    
    // Notify the framework that the state has changed
    await InvokeAsync(() => StateHasChanged());
  }

  private async Task ToggleComponent()
  {
    // Toggle the visibility of the component
    showComponent = !showComponent;
    showHelloWorld1 = !showComponent;
    showHelloWorld2 = !showComponent;
    // Notify the framework that the state has changed
    // Note: Use InvokeAsync for thread safety
    await InvokeAsync(() => StateHasChanged());
  }

  // Dispose the timer when the component is disposed
  public void Dispose()
  {
    timer.Dispose();
  }
}

HelloWorld1.razor

<h4>Hello from HelloWorld1!</h4>

@if (!showHelloWorld1)
{
    <p>Hidden!</p>
}
else
{
  <p>Visible!</p>
}

@code {
    [Parameter]
    public bool showHelloWorld1 { get; set; }
}

HelloWorld2.razor

<h4>Hello from HelloWorld2!</h4>

@if (!showHelloWorld2)
{
    <p>Hidden!</p>
}
else
{ 
    <p>Visible!</p>
}
@code {
    [Parameter]
    public bool showHelloWorld2 { get; set; }
}

Solution

  • You've only added @ref to reference the child component instance, but haven't pass the value. Add showHelloWorld1="showHelloWorld1" to pass it.

    Meanwhile, the value-changing order of showComponent needs modifying since changing first will cause the two child components value to be wrong.

    Index.razor

    @page "/index"
    
    <h3>Background Timer Example</h3>
    
    @if (showComponent)
    {
        <div class="alert alert-success" role="alert">
            This is a visible component!
        </div>
    }
    
    <HelloWorld1 @ref="helloWorld1" showHelloWorld1="showHelloWorld1" />
    <HelloWorld2 @ref="helloWorld2" showHelloWorld2="showHelloWorld2" />
    
    
    <button class="btn btn-primary" @onclick="ToggleComponent">Toggle Component</button>
    
    @code {
    
        private bool showComponent = true;
        private bool showHelloWorld1 = true;
        private bool showHelloWorld2 = true;
    
        private HelloWorld1 helloWorld1;
        private HelloWorld2 helloWorld2;
    
        // Timer interval in milliseconds
        private const int TimerInterval = 3000;
    
        private System.Threading.Timer timer;
    
        protected override void OnInitialized()
        {
            // Initialize the timer when the component is first initialized
            timer = new System.Threading.Timer(ToggleComponentVisibility, null, TimerInterval, TimerInterval);
        }
    
        private async void ToggleComponentVisibility(object state)
        {
            // Toggle the visibility of HelloWorld1 component
            showHelloWorld1 = !showComponent;
    
            // Toggle the visibility of HelloWorld2 component
            showHelloWorld2 = !showComponent;
    
            // Toggle the visibility of the component
            showComponent = !showComponent;
    
            // Notify the framework that the state has changed
            await InvokeAsync(() => StateHasChanged());
        }
    
        private async Task ToggleComponent()
        {
            // Toggle the visibility of the component
            showHelloWorld1 = !showComponent;
            showHelloWorld2 = !showComponent;
            showComponent = !showComponent;
            // Notify the framework that the state has changed
            // Note: Use InvokeAsync for thread safety
            await InvokeAsync(() => StateHasChanged());
        }
    
        // Dispose the timer when the component is disposed
        public void Dispose()
        {
            timer.Dispose();
        }
    }
    

    enter image description here