Show BusyIndicator with IResult and Coroutines

Feb 12, 2011 at 2:16 PM

Hi, I try port solution from this tutorial http://devlicio.us/blogs/rob_eisenberg/archive/2010/08/21/caliburn-micro-soup-to-nuts-part-5-iresult-and-coroutines.aspx to my WPF app.

As BusyIndicator I use control from Windows.ExtendedToolkit.

First I define the shell, it is WPF window.

Shell view :

<Window x:Class="MefTest.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended" Width="250" Height="520"
        >
    <Grid>
        <extToolkit:BusyIndicator IsBusy="{Binding Path=ShellIsBusy, Mode=OneWay,
                                                UpdateSourceTrigger=PropertyChanged}" 
                                  BusyContent="{Binding Path=BusyMessage,Mode=OneWay,
                                                    UpdateSourceTrigger=PropertyChanged}">
            <ContentControl x:Name="ActiveItem" />

        </extToolkit:BusyIndicator>
    </Grid>
</Window>

Shell view model class:

    public interface IShellViewModel{}

    [Export(typeof(IShellViewModel))]
    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive, IShellViewModel
    {
        readonly ScreenOneViewModel _initialialScreen;

        [ImportingConstructor]
        public ShellViewModel(ScreenOneViewModel initialialScreen)
        {
            this._initialialScreen = initialialScreen;
        }

        protected override void OnInitialize()
        {
            ActivateItem(_initialialScreen);
            base.OnInitialize();
        }

    }

 

ScreenOneView:

<UserControl x:Class="MefTest.ScreenOneView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:Micro="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro" 
             xmlns:extToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended" mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    
    <extToolkit:BusyIndicator IsBusy="{Binding Path=ShellIsBusy, Mode=OneWay,
                                                UpdateSourceTrigger=PropertyChanged}" 
                                  BusyContent="{Binding Path=BusyMessage,Mode=OneWay,
                                                    UpdateSourceTrigger=PropertyChanged}">
        <StackPanel>
        <Label>Screen 1</Label>
        <Button Micro:Message.Attach="[Event Click]=[Action GoFoward()]"  Height="35" Width="120"/>
    </StackPanel>
  </extToolkit:BusyIndicator>
</UserControl>



ScreenOneViewModel:

    [Export(typeof(ScreenOneViewModel))]
    public class ScreenOneViewModel:Screen
    {
        public IEnumerable<IResult> GoFoward()
        {
            yield return Loader.Show("Downloading...");
            Thread.Sleep(3000);
            yield return Loader.Hide();
        }
    }



Loader class is same:

    public class Loader : IResult
    {
        readonly string message;
        readonly bool hide;

        public Loader(string message)
        {
            this.message = message;
        }

        public Loader(bool hide)
        {
            this.hide = hide;
        }

        public void Execute(ActionExecutionContext context)
        {
            var view = context.View as FrameworkElement;
            while(view != null)
            {
                var busyIndicator = view as BusyIndicator;
                if(busyIndicator != null)
                {
                    if(!string.IsNullOrEmpty(message))
                        busyIndicator.BusyContent = message;
                    busyIndicator.IsBusy = !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);
        }
    }
After fire GoFoward method from ScreenOneViewModel I would like show busy indicator control.

Problem is here: var busyIndicator = view as BusyIndicator; busyIndicator is null. I use BusyIndicator in ScreenOneView and also in shell.
What is the root of problem?


Mar 1, 2011 at 12:17 PM

Had a similar problem. Solved it only in the V2 by finding a similar question on the forum.

The problem was that I've been missing a piece in the bootstrapper:

builder.With.ShellFramework();
Nov 5, 2014 at 3:07 AM
Edited Nov 5, 2014 at 3:08 AM
Late reply, but if anyone stumbled across this post for similar reasons, I found that I had to replace this line
var view = context.View as FrameworkElement;
as
var view = context.Source as FrameworkElement;
Note: i am using the Xceed busy indicator and not the WPFToolkit one, but the principal is the same.

I have also refactored my code to not be var view, but var source.