BusyIndicator Problems

Feb 23, 2011 at 9:58 PM

I'm trying to implement a coroutine that sets a BusyIndicator control. However, It doesn't seem to be working.

My Loader IResult which manipulates the BusyIndicator

namespace RageMvvm.Framework
{
    using System;
    using System.Windows;
    using Caliburn.Micro;
    using Microsoft.Windows.Controls;

    public class Loader : IResult
    {
        readonly string m_message;
        readonly bool m_hide;

        public Loader(string message)
        {
            m_message = message;
        }

        public Loader(bool hide)
        {
            m_hide = hide;
        }

        public void Execute(ActionExecutionContext context)
        {
            var view = context.View as FrameworkElement;
            while (view != null)
            {
                var indicator = UiHelper.FindChild<BusyIndicator>(view, "xBusyIndicator");
                
                if (indicator != null)
                {
                    if (!string.IsNullOrEmpty(m_message))
                        indicator.BusyContent = m_message;
                    indicator.IsBusy = !m_hide;
                    break;
                }

                view = view.Parent as FrameworkElement;
            }

            Completed(this, new ResultCompletionEventArgs());
        }

        public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };

        public static IResult Show(string message = null)
        {
            return new Loader(message);
        }

        public static IResult Hide()
        {
            return new Loader(true);
        }
    }

}

This is exactly the same as the code for the Loader in the "IResult and Coroutines" example. The only bit I changed is the part that finds the BusyIndicator. I am able to find the BusyIndicator and change the values, but nothing happens in the UI. (I stepped threw the code and verified that it is working)

My SearchView looks like this:

 

<UserControl
  x:Class="RageMvvm.Views.SearchView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended"
  d:DesignHeight="34"
  mc:Ignorable="d">
  <DockPanel>
    <Border HorizontalAlignment="Center" DockPanel.Dock="Top">
      <StackPanel Orientation="Horizontal">
        <TextBox x:Name="SearchText" Width="225" FontSize="14">
          <TextBox.CaretBrush>
            <SolidColorBrush Color="Gray"/>
          </TextBox.CaretBrush>
        </TextBox>
        <Button
          x:Name="ExecuteSearch"
          Width="45"
          Height="34"
          Content="Go"/>
      </StackPanel>
    </Border>
    <extToolkit:BusyIndicator x:Name="xBusyIndicator">
      <ContentControl x:Name="SearchResults"/>
    </extToolkit:BusyIndicator>
  </DockPanel>
</UserControl>

 

In my SearchViewModel, i do the following

   public IEnumerable<IResult> ExecuteSearch()
        {
            yield return Loader.Show("Searching...");
            var search = new ShowSearch(SearchText);
            yield return search;
            yield return Loader.Hide();
            SearchResults = m_resultsViewModel.With(search.Shows);
        }
Any ideas what is wrong?

Coordinator
Feb 24, 2011 at 1:19 AM

If you know that it is finding the control and changing the values, it may be that there isn't enough time where IsBusy is true for you to see the indicator. I believe that the control has a built in delay, so that it doesn't show itself if the busy time is very short. You might want to check on that.

Feb 24, 2011 at 1:38 AM

Actually, I just observed something that was strange. I had IsBusy set to true in the xaml, and in Execute of Loader, I inverse the hide and show. What I noticed is that the UI freezes while the Execute on ShowSearch is called. It is not async, and just loads in dummy data for now. I don't think it should be executed on the UI Thread, should it?

Feb 24, 2011 at 1:58 AM

OK, threading was the issue. I wrapped the domain logic in ShowEach in ThreadPool.QueueUserWorkItem and it is now working :)

 ThreadPool.QueueUserWorkItem
Feb 24, 2011 at 8:52 AM

If you are developing in .NET 4.0, consider using System.Threading.Tasks APIs instead of the ThreadPool. It seems it is now the 'preferred' way to dispatch calls on other threads (it gives you cancellation and the ability to parallelize jobs easily).

Feb 24, 2011 at 10:15 AM

Oh nice, I will have a look into it. Thanks!