'Avalonia UserControl checking if it is visible before before acting on a timer

I have a loading overlay (with the View inheriting from UserControl and the ViewModel from ViewModelBase) that I display over the current window by putting using a <Grid> and having the regular controls in a <StackPanel> and then the loading screen after it in a <Border>, binding the <Border>'s IsVisible property to control the display of the overlay.

<Window ...>
    <Grid>
        <StackPanel>
            <!-- Window controls here -->
        </StackPanel>
        <Border Background="#40000000" 
                IsVisible="{Binding IsLoading}">
            <views:LoadingScreenView />
        </Border>
    </Grid>
</Window>

In the LoadingScreenViewModel I use an HttpClient to download a JSON file to parse and display on the loading overlay.

It is refreshed in the LoadingScreenViewModel every 10 seconds by using a timer

private IObservable<long> timer = Observable.Interval(TimeSpan.FromSeconds(10),
                                    Scheduler.Default);

and then subscribing to it in the ViewModel's constructor

    public LoadingScreenViewModel()
    {
        LoadingText = "Loading...";

        timer.Subscribe(async _ =>
        {
            var json = await _httpClient.GetStringAsync(...);
            var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
            LoadingText = dict["result"];
        });
    }

The problem is that since I include the LoadingScreenView in the window, this timer is firing every ten second, even when the loading overlay isn't displayed.

Is there any way to check if the overlay itself is visible during that Subscribe(), passing the IsLoading property to the LoadingScreenViewModel, or creating and destroying the View every time it is used?



Solution 1:[1]

I was able to achieve this by adding a bool isVisible property to the LoadingScreenViewModel, having the view inherit from ReactiveUserControl<LoadingScreenViewModel>, and per the discussion at https://github.com/AvaloniaUI/Avalonia/discussions/7876 I achieved this in code-behind by subscribing to changes in the view's TransformedBounds property and determining if the view is visible based on if TransformedBounds is null or not.

public LoadingScreenView()
    {
        InitializeComponent();
        this.WhenAnyValue(v => v.TransformedBounds)
            .Subscribe(x => ViewModel.isVisible = x is not null);
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1