Question

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 ??

Was it helpful?

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>

OTHER TIPS

I think Oleg is right though, you cannot use conventions in a DataTemplate using Caliburn (CaliburnMicro you can). From the Documentation - Other Things to Know

Other Things To Know On all platforms, conventions cannot by applied to the contents of a DataTemplate. This is a current limitation of the Xaml templating system. I have asked Microsoft to fix this, but I doubt they will respond. As a result, in order to have Binding and Action conventions applied to your DataTemplate, you must add a Bind.Model="{Binding}" attached property to the root element inside the DataTemplate. This provides the necessary hook for Caliburn.Micro to apply its conventions each time a UI is instantiated from a DataTemplate.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top