【问题标题】:Caliburn.Micro GetAllInstances only returns one viewModel(Caliburn.Micro MVVM)Caliburn.Micro GetAllInstances 只返回一个 viewModel(Caliburn.Micro MVVM)
【发布时间】:2017-12-06 23:50:24
【问题描述】:

我一直在尝试将 Caliburn.Micro MVVM 框架集成到一个 C# WPF 项目中。

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

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

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

我需要的是所有 Screen/ViewModels 都是 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 可以工作?...

【问题讨论】:

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


    【解决方案1】:

    实际上我现在找到了一个解决方案,而不会弄乱程序集。

    我注意到 ShellViewModel 的实例是可访问的,通过将实例保存到对象中并对其进行调试,我注意到我创建的所有 viewModel 实例都在“项目”中。

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

    【讨论】:

    • 现在我注意到我不必要地创建了一个新实例。将编辑,一秒钟。
    【解决方案2】:

    覆盖 caliburn micro 的 SelectAssemblies 方法以定位所有视图:

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

    更多关于引导程序here

    【讨论】:

    • 谢谢,一会儿试试。我会更新的。
    • 我在不同的程序集中有视图和视图模型,这解决了我在这一行中获取 null 的问题:ViewModelLocator.LocateForView(_shell.Value); 谢谢
    猜你喜欢
    • 2013-10-22
    • 1970-01-01
    • 2014-05-09
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多