【问题标题】:Advice on Views navigation using Caliburn.Micro MVVM WPF关于使用 Caliburn.Micro MVVM WPF 进行视图导航的建议
【发布时间】:2014-04-21 18:25:13
【问题描述】:

我是 Caliburn Micro 的新用户,想了解一些关于开发我的应用程序界面和视图之间导航的路径的建议。 我的想法是有一个包含按钮菜单的 MainWindow,每个按钮都与一个特定的视图相关。每个视图都将存储在单独的 WPF UserControl 中。 mainWindow 还将包含一个 TabControl 绑定到 viewmodel 上的选项卡的 ObservableCollection。每次单击菜单上的按钮时,我都想添加一个带有 ContentPresenter 的新选项卡,该选项卡将动态加载视图及其相应的视图模型。

所以我的问题:

1) 我应该在这里使用 Screen Collection 吗?

2) UserControl 是否应该实现 Screen 接口?

3) 我如何告诉 MainWindow ViewModel 在新添加的选项卡上加载哪个视图以保持视图模型解耦?

提前感谢大家。

更新

经过大量阅读和社区的一些帮助,我设法解决了这个问题。这是生成的 AppViewModel:

class AppViewModel : Conductor<IScreen>.Collection.OneActive
{
    public void OpenTab(Type TipoVista)
    {
        bool bFound = false;
        Screen myScreen = (Screen)Activator.CreateInstance(TipoVista as Type);
        myScreen.DisplayName = myScreen.ToString();
        foreach(Screen miItem in Items)
        {
            if (miItem.ToString() == myScreen.ToString())
            {
                bFound = true;
                ActivateItem(miItem);
            }                
        }
        if (!bFound) ActivateItem(myScreen);        
    }

    public ObservableCollection<MenuItem> myMenu { get; set; }
    public ObservableCollection<LinksItem> myDirectLinks { get; set; }

    public ICommand OpenTabCommand
    {
        get
        {                
            return new RelayCommand(param => this.OpenTab((Type) param), null);
        }
    }       

    public AppViewModel()
    {
        OpenTab(typeof(ClientsViewModel));            
        MenuModel menu = new MenuModel();
        myMenu = menu.getMenu();
        myDirectLinks = menu.getLinks();
    }        

    public void CloseTab(Screen param)
    {            
        DeactivateItem(param, true);
    }    
}

我必须保留 OpenTabCommand 中的 ICommand,因为 Caliburn.micro 的命名约定似乎在 DataTemplate 中不起作用。希望它可以帮助别人。谢谢大家

【问题讨论】:

    标签: c# wpf mvvm caliburn.micro


    【解决方案1】:

    我使用Caliburn.Micro 做了一些非常相似的事情,并基于示例中包含的SimpleMDI 示例,并进行了一些调整以满足我的需求。

    就像在示例中一样,我有一个主要的ShellViewModel

    public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
    {
    }
    

    对应的ShellView 包含TabControl - &lt;TabControl x:Name="Items"&gt;,将其绑定到ConductorItems 属性。

    在这种特殊情况下,我的ShellView 上还有一个ContextMenu,绑定(使用Caliburn.Micro 约定)到一系列实例化的命令和Activated 各种其他ViewModels(通常使用对应的UserControl,使用Conductor上的ActivateItem方法。

    public class YourViewModel: Conductor<IScreen>.Collection.OneActive
    {
        // ...
    
        public void OpenItemBrowser()
        {
            // Create your new ViewModel instance here, or obtain existing instance.
            // ActivateItem(instance)
        }
    }
    

    在这种情况下,我不需要使用任何特定依赖项或从程序中的任何其他位置创建 ViewModels

    在其他时候,当我需要从应用程序的其他地方触发ViewModel 时,我使用了Caliburn.Micro EventAggregator 来发布自定义事件(例如OpenNewBrowser),这可以由实现相应接口的类(例如IHandle&lt;OpenNewBrowser&gt;),因此您的主要ViewModel 可以有一个简单的Handle 方法负责打开所需的View

    public class YourViewModel: Conductor<IScreen>.Collection.OneActive, IHandle<OpenNewBrowser>
    {
        // ...
    
        public void Handle(OpenNewBrowser myEvent)
        {
            // Create your new ViewModel instance here, or obtain existing instance.
            // ActivateItem(instance)
        }
    }
    

    This section 的文档可能会有用,尤其是 Simple MDI 部分。

    我在 cmets 中提到的附加代码:

    我有时会使用通用方法来确保如果我有特定类型的屏幕的现有实例,则切换到它,或者如果没有,则创建一个新实例。

    public void ActivateOrOpen<T>() where T : Screen
    {
        var currentItem = this.Items.FirstOrDefault(x => x.GetType() == typeof(T));
    
        if (currentItem != null)
        {
            ActivateItem(currentItem);
        }
        else
        {
            ActivateItem(Activator.CreateInstance<T>());
        }
    }
    

    像这样使用:

    public void OpenBrowser()
    {
        this.ActivateOrOpen<BrowserViewModel>();
    }
    

    【讨论】:

    • 非常感谢!这正是我需要的!我自己做了一些测试,还发现可以使 SimpleMDI 简单地适应我的需要。我唯一不同的是如何打开新视图(使用ActivateItem),因为我有一个菜单,我想将每个菜单选项链接到特定视图,所以我使用“Screen myScreen = (Screen)Activator.CreateInstance(ViewType as Type );"将 ViewType 作为对 viewmodel 类类型的引用传递。如果您看到我的更新,我会发布我的 AppViewModel。再次感谢您!
    • 有道理 =DI 有时会使用通用方法来控制我只想要一个实例的屏幕,我会在编辑中发布它,而不是试图将它楔入这里。跨度>
    猜你喜欢
    • 2023-03-07
    • 2013-11-08
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    相关资源
    最近更新 更多