Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 关于使用Caliburn.Micro MVVM WPF进行视图导航的建议_C#_Wpf_Mvvm_Caliburn.micro - Fatal编程技术网

C# 关于使用Caliburn.Micro MVVM WPF进行视图导航的建议

C# 关于使用Caliburn.Micro MVVM WPF进行视图导航的建议,c#,wpf,mvvm,caliburn.micro,C#,Wpf,Mvvm,Caliburn.micro,我是Caliburn Micro的新手,希望得到一些关于开发我的应用程序界面和视图间导航的建议。 我的想法是有一个主窗口,其中包含一个按钮菜单,每个按钮都与特定视图相关。每个视图将存储在一个单独的WPF用户控件中。主窗口还将包含绑定到viewmodel上的可观察选项卡集合的选项卡控件。每次单击菜单上的按钮时,我都希望添加一个新选项卡,其中包含一个ContentPresenter,它将动态加载视图及其相应的viewmodel 所以我的问题是: 1) 我应该在这里使用屏幕集合吗 2) UserCon

我是Caliburn Micro的新手,希望得到一些关于开发我的应用程序界面和视图间导航的建议。 我的想法是有一个主窗口,其中包含一个按钮菜单,每个按钮都与特定视图相关。每个视图将存储在一个单独的WPF用户控件中。主窗口还将包含绑定到viewmodel上的可观察选项卡集合的选项卡控件。每次单击菜单上的按钮时,我都希望添加一个新选项卡,其中包含一个ContentPresenter,它将动态加载视图及其相应的viewmodel

所以我的问题是:

1) 我应该在这里使用屏幕集合吗

2) UserControl是否应该实现屏幕界面

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

提前感谢大家

更新

经过大量阅读和社区的帮助,我终于解决了这个问题。这是生成的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);
    }    
}
class AppViewModel:Conductor.Collection.OneActive
{
公共void OpenTab(类型为TipoVista)
{
boolbfound=false;
Screen myScreen=(Screen)Activator.CreateInstance(类型为TipoVista);
myScreen.DisplayName=myScreen.ToString();
foreach(项目中的屏幕项目)
{
if(miItem.ToString()==myScreen.ToString())
{
bFound=真;
激活肽(miItem);
}                
}
如果(!bFound)激活项(myScreen);
}
公共ObservableCollection myMenu{get;set;}
公共ObservableCollection myDirectLinks{get;set;}
公共ICommand opentab命令
{
得到
{                
返回新的RelayCommand(param=>this.OpenTab((Type)param),null);
}
}       
公共AppViewModel()
{
OpenTab(typeof(ClientsViewModel));
MenuModel menu=新建MenuModel();
myMenu=menu.getMenu();
myDirectLinks=menu.getLinks();
}        
公共无效关闭选项卡(屏幕参数)
{            
停用项(参数,真);
}    
}

我必须从OpenTab命令中保留ICommand,因为Caliburn.micro的名称约定在DataTemplate中似乎不起作用。希望它能帮助别人。多亏了所有的我使用
Caliburn.Micro
做了一些非常类似的事情,并基于示例中包含的
SimpleMDI
示例,进行了一些调整以满足我的需要

与示例中非常相似,我有一个主
ShellViewModel

public class ShellViewModel : Conductor<IScreen>.Collection.OneActive
{
}
在这种情况下,我不需要使用任何特定的依赖项或从程序中的任何其他位置创建
ViewModels

其他时候,当我需要从应用程序的其他地方触发
ViewModel
时,我会使用
Caliburn.Micro
EventAggregator
发布自定义事件(例如
OpenNewBrowser
),这些事件可以由实现相应接口的类(例如
IHandle
)来处理,因此,您的主
视图模型
可以有一个简单的
句柄
方法,负责打开所需的
视图

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)
    }
}
公共类YourViewModel:Conductor.Collection.OneActive,IHandle
{
// ...
公共无效句柄(OpenNewBrowser myEvent)
{
//在此处创建新的ViewModel实例,或获取现有实例。
//ActivateItem(实例)
}
}
文档的第二部分可能会很有用,特别是简单的MDI部分

我在评论中提到的其他代码:

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

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 ActivateOrOpen(),其中T:Screen
{
var currentItem=this.Items.FirstOrDefault(x=>x.GetType()==typeof(T));
如果(currentItem!=null)
{
激活项(当前项);
}
其他的
{
ActivateItem(Activator.CreateInstance());
}
}
用法如下:

public void OpenBrowser()
{
    this.ActivateOrOpen<BrowserViewModel>();
}
public void OpenBrowser()
{
这是。活化丙烯();
}

非常感谢!这正是我需要的!我自己做了一些测试,也发现可以根据我的需要调整SimpleMDI simple。我所做的唯一不同的事情是如何打开新视图(使用ActivateItem),因为我有一个菜单,我想在其中将每个菜单选项链接到特定视图,所以我使用“Screen myScreen=(Screen)Activator.CreateInstance(ViewType as Type);”将ViewType作为对viewmodel类类型的引用传递。如果您看到我的更新,我会发布我的AppViewModel。再次感谢你!这是有意义的=D我有时使用一种通用方法来控制我只需要一个实例的屏幕,我将在编辑中发布它,而不是尝试在这里插入它。
public void OpenBrowser()
{
    this.ActivateOrOpen<BrowserViewModel>();
}