Help!! - Problems with binding

Feb 7, 2012 at 3:33 PM

Hi. I am very new to Caliburn so any help will be appreciated.

I have an experimental WPF app running with the a view and a viewModel bound using the conventional syntax e.g. <TextBox Text="{Binding Model.MailingPostcode, Mode=TwoWay}..." .../> and so on (Marki up is generated by Visual Studio from a data source) .

I have changed the viewModel to implement IScreen etc and using the Caliburn.Micro framework.

My understanding is that this should work in a Caliburn Mixro environment as the framework should see that there are bindings in place and therefore not try and apply any conventions.

What happens is that the view is not bound to anything. Wpf complains that there is no data context to retrieve data from.

I have examined the log output and can see that the viewModel is activated and then Wpf complains of thte lack of data, after that Caliburn tells me that it is setting the view's data context to the viewModel (a bit late in the day :-)).

Obviously I am doing something wrong, in the wrong order or not doing the right thing.

Can anyone suggest a course of action.

Regards

Simon



Feb 7, 2012 at 4:31 PM

Can you show us how your bootstrapper is configured and then name of the View and ViewModel in question.  The namespaces in which your app is using could also cause the binding to fail.

Feb 7, 2012 at 5:34 PM

Hi thanks for the response. I have adapted the HelloScreens demo for my purposes

the view is 'SpeedSorter.WpfUI.Sortation.CodeGen.Views.JobView' the associated viewModel is 'SpeedSorter.WpfUI.Sortation.CodeGen.ViewModel.JobViewModel'. The ViewLocator has no trouble in locating the correct view for the ViewModel. the ViewModel is activated as the main component of a JobWorkspace.Edit View. The JobWorkspaceViewModel inherits from 'DocumentWorkspace' from the HelloScreens demo. The relevent emthod is:

public void Edit(TDocument child)
{
    Conductor.ActivateItem(this);
    State = DocumentWorkspaceState.Edit;
    DisplayName = child.DisplayName;
    ActivateItem(child);
}

As far as I can see from stepping into 'AcivateItem(child)' everything is happening as might be expected except that the framework does not assign the JobViewModel to the JobView's datacontext before Wpf does its binding stuff.

The Bootstrapper is fairly straight forward

namespace SpeedSorter.WpfUI
{
    public class SpeedsorterBootStrapper : Bootstrapper<IShell>
    {
        #region Fields
        private CompositionContainer _container;
        #endregion
        static SpeedsorterBootStrapper()
        {
            LogManager.GetLog = type => new DebugLogger(type);
        }
        #region Overrides
        protected override void Configure()
        { //  configure container

            _container = new CompositionContainer(
              new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()));

            var batch = new CompositionBatch();
 
            batch.AddExportedValue<IWindowManager>(new WindowManager());
            batch.AddExportedValue<IEventAggregator>(new EventAggregator());
            batch.AddExportedValue<Func<IMessageBox>>(() => _container.GetExportedValue<IMessageBox>());
            batch.AddExportedValue<Func<JobViewModel>>(() => _container.GetExportedValue<JobViewModel>());
            batch.AddExportedValue(_container);
 
            _container.Compose(batch);
        }
        protected override object GetInstance(Type serviceType, string key)
        {
            string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
            var exports = _container.GetExportedValues<object>(contract);
 
            if (exports.Count() > 0)
                return exports.First();
 
            throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
        }
        protected override IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
        }
        protected override void BuildUp(object instance)
        {
            _container.SatisfyImportsOnce(instance);
        }
        #endregion
    }
}

shout if you need me to give you more info.

regards

Simon
Feb 7, 2012 at 5:36 PM

Sorry the ViewModel namespace is '

SpeedSorter.WpfUI.Sortation.CodeGen.ViewModels' previous post dorpped the s
Feb 7, 2012 at 9:40 PM

What does the JobViewModel inherit from?

Feb 8, 2012 at 10:02 AM

Dependancy object and implements IScreen, IChild, IViewAware, IHaveModeld

Feb 8, 2012 at 3:19 PM

The problem stems from the use of the Visual Studio design tool that allows you to drag a Data Source onto the design surface of a view. The tool generates Xaml that uses a CollectionViewSource which cannot take a DataContext. I ahve removed this and all works. Does anyone know how the CollectionViewSource can be used with Caliburn.Micro?

Feb 8, 2012 at 6:25 PM

that is very interesting, I have never used it before so never had to deal with that issue.  About the only thing I could think of would be to create a Convention that would bind the ItemSource DP of the CollectionViewSource to that of a collection in the ViewModel.