ironmagician
ironmagician

Reputation: 53

Caliburn.Micro GetAllInstances only returns one viewModel(Caliburn.Micro MVVM)

I've been trying to integrate Caliburn.Micro MVVM framework in a C# WPF project I am in the middle off.

I currently only have three view models:

Currently I am trying to use a button at the AboutView that is bind to the 'Chat()' method at the AboutViewModel and should take the user to the ChatView, yet I am testing this with the AboutViewModel. (As seen in the handler)

What I need is that all the Screen/ViewModels to be Singleton and only have one instance and when I try to change page, it returns to an already existant page.

The issue here is that I only have one instance registered when I do IoC.GetAllInstances(), the ShellViewModel and even though I've tried multiple configurations at the bootstrapper, I cannot register my other ViewModels in a way to make their instances "reachable"

I thank you for your time, and here is the code I think it's relevant for the issue:

Here is my bootstrapper:

public class AppBootstrapper : BootstrapperBase
{
    private SimpleContainer _container = new SimpleContainer();

    public AppBootstrapper()
    {
        Initialize();

        var config = new TypeMappingConfiguration
        {
            DefaultSubNamespaceForViewModels = "ViewModel",
            DefaultSubNamespaceForViews = "View"
        };

        ViewLocator.ConfigureTypeMappings(config);
        Caliburn.Micro.ViewModelLocator.ConfigureTypeMappings(config);
    }

    protected override void Configure()
    {
        _container.Singleton<ShellViewModel, ShellViewModel>();
        _container.Singleton<IWindowManager, WindowManager>();
        //tried registering AboutViewModel in multiple ways
        _container.Singleton<AboutViewModel, AboutViewModel>();
        _container.RegisterSingleton(typeof(AboutViewModel), null,typeof(AboutViewModel));

        /
    }

    protected override void OnStartup(object sender, StartupEventArgs e)
    {
        DisplayRootViewFor<ShellViewModel>();
    }


    protected override object GetInstance(Type service, string key)
    {
        var instance = _container.GetInstance(service, key);
        if (instance != null)
            return instance;
        throw new InvalidOperationException("Could not locate any instances.");
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        _container.BuildUp(instance);
    }


}

ShellViewModel.cs:

public class ShellViewModel : Conductor<object>, IHandle<NavigationMessage>
{
    /// <summary>
    /// Caliburn.Micro event aggregator. (Publish/Subscribe pattern)
    /// </summary>
    public IEventAggregator events = new EventAggregator();
    public ShellViewModel()
    {
        //var aaa = IoC.Get<IEventAggregator>();
        events.Subscribe(this);
        ActivateItem(new AboutViewModel(events));
    }

    public void Handle(NavigationMessage message)
    {
        //var instance = IoC.GetInstance(message.ViewModelType,null);
        var instances = IoC.GetAllInstances(null);
        foreach(var i in instances)
        {

            MessageBox.Show(i.ToString());
        }
        ActivateItem(new AboutViewModel(events));

    }
}

And the AboutViewModel.cs:

/// <summary>
/// ViewModel belonging to the AboutView.xaml.
/// </summary>
/// <seealso cref="AboutView.xaml"/> 
public class AboutViewModel : Screen, IHandle<NavigationMessage>
{
    private readonly IEventAggregator _eventAggregator;
    /// <summary>
    /// Private container for the 'Version' public property.
    /// </summary>
    /// <see cref="Version"/>
    private string _version;

    /// <summary>
    /// Property containing a string of the application's current version (e.g.: 0.1.3.45)
    /// </summary>
    /// <see cref="_version"/> 
    [JsonIgnore]
    public string Version
    {
        get
        {
            return _version;
        }
        set
        {
            _version = value;
            NotifyOfPropertyChange(() => Version);
        }
    }

    /// <summary>
    /// Base constructor for the AboutViewModel class.
    /// </summary>
    public AboutViewModel(IEventAggregator eventAggregator)
    {         
        Logging.Info("Initialize AboutViewModel", this.GetType());
        Logging.Debug("Subscribing to the eventAggregator", this.GetType());
        _eventAggregator = eventAggregator;
        _eventAggregator.Subscribe(this);

        _version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
        Logging.Debug("Version loaded (" + _version + ")", this.GetType());
    }

    /// <summary>
    /// Boolean method connected to the ChatCommand activates or deactivates based on it's return
    /// </summary>
    /// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
    public bool CanChat(object obj)
    {
        return true;
    }
    /// <summary>
    /// Method connected to the ChatCommand that sends the user to the 'Chat' view
    /// </summary>
    /// <param name="obj">Object of type GotoPageMessage received from the messenger</param>
    public void Chat(object obj)
    {

        _eventAggregator.PublishOnUIThread(new NavigationMessage(typeof(AboutViewModel)));
    }

    public void Handle(NavigationMessage message)
    {
        //This handle is used only to know how many instances I have active
        MessageBox.Show("about");
    }
}

Edit 1:

P.S.: I used to have my ShellViewModel as Conductor.Collection.OneActive. Still didn't work. Maybe AllActive may work?...

Upvotes: 1

Views: 788

Answers (2)

ironmagician
ironmagician

Reputation: 53

I actually found a solution right now, without messing with Assemblies.

I noticed that the ShellViewModel's instance was accesible, and by saving the instance into a object and debugging it, I noticed all the viewModel instances I created were there at the 'Items'.

Basically this was what I did, in the handler that is inside the ShellViewModel:

    public void Handle(NavigationMessage message)
    {
        ShellViewModel Shell = (ShellViewModel)IoC.GetInstance(typeof(ShellViewModel), null);
        object Instance = null;

        foreach (var item in Shell.Items)
        {
            if (item.ToString().Contains(message.ViewModelType.ToString()))
                Instance = item;
        }
        object AuxObject = new object();


        if (Instance == null)
        {
            try
            {
                Instance = Activator.CreateInstance(message.ViewModelType, Shell.events);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }
        ActivateItem(Instance);

    }

Upvotes: 0

igorc
igorc

Reputation: 2034

override the SelectAssemblies method for caliburn micro to locate all the views:

protected override IEnumerable<Assembly> SelectAssemblies()
{
   return new[]
   {
       Assembly.GetExecutingAssembly(), typeof(MainViewModel).Assembly
   };
}

more on the bootstrapper here.

Upvotes: 1

Related Questions