Search code examples
c#wpftoolkitcaliburn.microsimple-injector

Caliburn binding exception


Let me explain my problem. Please excuse me for the long question. Here it goes.

I have a View (BusyProviderView)

<Grid>
    <xctk:BusyIndicator x:Name="aaa" IsBusy="{Binding IsRunning}" >
        <xctk:BusyIndicator.BusyContentTemplate>
            <DataTemplate>
                <Grid cal:Bind.Model="{Binding}">
                    <TextBlock Name="Message"/>
                </Grid>
            </DataTemplate>
        </xctk:BusyIndicator.BusyContentTemplate>
    </xctk:BusyIndicator>
</Grid>

Which has View model:

    public class BusyProviderViewModel : PropertyChangedBase, IBusyProvider
{
//two properties with INPC, Message and IsRunning
}

Again I have a Shell view

<Window x:Class="MvvmTest.ShellView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ShellView" Height="300" Width="300">
<Grid>
    <Button Height="25" x:Name="Run">Run</Button>
    <ContentControl x:Name="BusyProvider"/>
</Grid>

Which has a view model

public class ShellViewModel : PropertyChangedBase, IShellViewModel
{
    private IBusyProvider busyProvider;

    public ShellViewModel(IBusyProvider busy)
    {
        this.BusyProvider = busy;
    }

    public IEnumerable<IResult> Run()
    {
        yield return new DummyOperation(this.BusyProvider);
    }

    public IBusyProvider BusyProvider
    {
        get
        {
            return this.busyProvider;
        }
        set
        {
            if (Equals(value, this.busyProvider))
            {
                return;
            }
            this.busyProvider = value;
            this.NotifyOfPropertyChange(() => this.BusyProvider);
        }
    }
}

DummyOperation Looks

public class DummyOperation : IResult
{
    public IBusyProvider Provider { get; set; }

    public DummyOperation(IBusyProvider provider)
    {
        Provider = provider;
    }

    public void Execute(ActionExecutionContext context)
    {
        BackgroundWorker worker = new BackgroundWorker();
        worker.DoWork += (a, b) =>
            {
                Provider.IsRunning = true;
                Provider.Message = "Working";
                Thread.Sleep(TimeSpan.FromSeconds(5));
                Provider.Message = "Stopping";
                Thread.Sleep(TimeSpan.FromSeconds(5));
                Provider.IsRunning = false;
            };
        worker.RunWorkerCompleted += (a, b) =>
            { Completed(this, new ResultCompletionEventArgs()); };
        worker.RunWorkerAsync();

    }

    public event EventHandler<ResultCompletionEventArgs> Completed;
}

Finally I have BootStrapper

public class AppBootstrapper : Bootstrapper<IShellViewModel>
{
    private Container container;

    protected override void Configure()
    {
        this.container = new Container();
        this.container.Register<IWindowManager,WindowManager>();
        this.container.Register<IShellViewModel,ShellViewModel>();
        this.container.Register<IBusyProvider, BusyProviderViewModel>();
    }

    protected override object GetInstance(Type serviceType, string key)
    {

        return this.container.GetInstance(serviceType);
    }


    protected override IEnumerable<object> GetAllInstances(Type serviceType)
    {
        return this.container.GetAllInstances(serviceType);
    }
    protected override void BuildUp(object instance)
    {
        this.container.Verify();
    }
}

Looks Like I have set everything, But When I try to run it throws an exception. enter image description here

I am sure the problem is causing by

 <DataTemplate>
            <Grid cal:Bind.Model="{Binding}">
                <TextBlock Name="Message"/>
            </Grid>
        </DataTemplate>

cal:Bind.Model="{Binding}

Once I remove above statement the program runs without a crash but no binding.

If you look at the Image,

 protected override object GetInstance(Type serviceType, string key)
    {

        return this.container.GetInstance(serviceType);
    }

serviceType is passed as a NULL, and key is "Please Wait...." , Where that comes from ??


Solution

  • It seems by default the Extended Toolkit's BusyIndicator uses the string "Please Wait...." for the BusyContent. So inside the DataTemplate the DataContext will be the above mentioned string and this causes the confusion and exception in Caliburn.

    To fix it you need to set the BusyContent on the BusyIndicator to the current DataContext and it will work:

    <xctk:BusyIndicator x:Name="aaa" IsBusy="{Binding IsRunning}" 
                                     BusyContent="{Binding}" >
        <xctk:BusyIndicator.BusyContentTemplate>
            <DataTemplate>
                <Grid cal:Bind.Model="{Binding}">
                    <TextBlock Name="Message"/>
                </Grid>
            </DataTemplate>
        </xctk:BusyIndicator.BusyContentTemplate>
    </xctk:BusyIndicator>