Caliburn.Micro GetAllInstances只返回一个viewModel(Caliburn.Micro MVVM)

时间:2017-07-03 16:19:20

标签: c# wpf mvvm inversion-of-control caliburn.micro

我一直在尝试将Caliburn.Micro MVVM框架集成到C#WPF项目中,我处于中间位置。

我目前只有三种视图模型:

  • ShellViewModel - (带有ContentControl的窗口视图)
  • AboutViewModel - (用户控制视图)
  • ChatViewModel - (另一个用户控制视图)

目前我正在尝试在AboutView上使用一个绑定到' Chat()'在AboutViewModel上的方法,应该将用户带到ChatView,但我正在使用AboutViewModel进行测试。 (如处理程序所示)

我需要的是所有的Screen / ViewModel都是Singleton并且只有一个实例,当我尝试更改页面时,它会返回已经存在的页面。

这里的问题是我在IoC.GetAllInstances(),ShellViewModel中只注册了一个实例,即使我在引导程序中尝试了多个配置,我也无法以某种方式注册我的其他ViewModel使他们的实例"可达"

我感谢您的时间,以下是我认为与此问题相关的代码:

这是我的引导程序:

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));

    }
}

和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");
    }
}

修改1:

P.S。:我曾经将我的ShellViewModel作为Conductor.Collection.OneActive。仍然没有工作。也许AllActive可能有用吗?...

2 个答案:

答案 0 :(得分:1)

重写用于caliburn micro的SelectAssemblies方法以查找所有视图:

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

更多关于引导程序here

答案 1 :(得分:0)

我实际上现在找到了一个解决方案,而没有弄乱Assemblies。

我注意到ShellViewModel的实例是可访问的,通过将实例保存到对象并进行调试,我注意到我创建的所有viewModel实例都在&#39; Items&#39;中。

基本上这就是我在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);

    }