使用WPF和Caliburn.Micro在视图中添加多个视图

dia*_*ish 14 c# wpf mvvm caliburn caliburn.micro

我正在尝试使用带有WPF的Caliburn.Micro学习.如何在视图中添加多个视图?

<Window x:Class="ProjectName.Views.MainView"
         ...>
<Grid>
        <views:MyControlView  />
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

另一个视图,使用viewmodel:MyControlViewModel

<UserControl x:Class="ProjectName.Views.MyControlView"
         ...>
<Grid>
    ...
</Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

如果我只是添加视图,它将不会检测到它具有具有适当名称的viewmodel.我怎么能把它绑在上面呢?

我已尝试使用不同的bootstrappers并使用类似cal:Bind.Model ="path/classname/merge of the two".试图将其添加到主视图和usercontrol(MyControlView).我非常感谢有关此事的任何帮助.我几乎卡住了,我真的想用Caliburn.Micro :)

最好的问候,钻石鱼

编辑:我仍然无法让它工作,问题似乎是在引导程序或其他东西.但只是为了澄清,这是我的代码,我正在运行testproject.

MainView xaml:

<Window x:Class="Test.Views.MainView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
    xmlns:views="clr-namespace:Test.Views"
    Title="MainWindow" Height="360" Width="640">
<Grid>
    <views:MyControlView />
</Grid>
Run Code Online (Sandbox Code Playgroud)

MainViewModel代码:

public partial class MainViewModel : PropertyChangedBase
{
}
Run Code Online (Sandbox Code Playgroud)

MyControlView xaml:

<UserControl x:Class="Test.Views.MyControlView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro"
         cal:Bind.Model="Test.MyControlViewModel"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <TextBlock Text="{Binding MyProp}"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)

MyControlView代码:

public class MyControlViewModel : PropertyChangedBase
{
    public string MyProp
    {
        get { return "Working"; }
    }
}
Run Code Online (Sandbox Code Playgroud)

错误的屏幕截图:http://clip2net.com/s/1gtgt

我试过了

cal:Bind.Model="Test.ViewModels.MyControlViewModel" 
Run Code Online (Sandbox Code Playgroud)

同样.还尝试了cal-reference:

xmlns:cal="http://www.caliburnproject.org"
Run Code Online (Sandbox Code Playgroud)

我的项目http://clip2net.com/s/1gthM的屏幕截图

由于文档主要用于silverlight,有时用于Caliburn而不是CM,我可能已经错误地实现了bootstrapper.对于这个测试项目,它就像这样:(在App.xaml中使用.xaml-change)

public class BootStrapper : Bootstrapper<MainViewModel>
{
}
Run Code Online (Sandbox Code Playgroud)

请帮帮我吧!好像这是我缺少的一些基本内容:)

Eth*_*gon 17

编辑 - 新(更完整)答案如下:

好的,CM正在为你做很多事情,这都是为了让你的类和xaml为CM准备好找到它.如上所述,我更喜欢将代码显式化,而不是依赖于框架的隐式代码假设.

所以,来自默认CM项目的Bootstrapper就好了.

public class AppBootstrapper : Bootstrapper<MainViewModel>
{
    // ... You shouldn't need to change much, if anything
}
Run Code Online (Sandbox Code Playgroud)

"Bootstrapper"部分非常重要,它指示应用程序启动时哪个ViewModel是您的第一个或主屏幕.

[Export(Typeof(MainViewModel))]
public class MainViewModel : Screen,  IShell
{
    [ImportingConstructor]
    public MainViewModel(YourFirstViewModel firstViewModel, YourSecondViewModel secondviewModel) // etc, for each child ViewModel
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

[ImportingConstructor]除了指定MainViewModel需要存在其他ViewModel之外,您不需要执行任何操作.在我的特定情况下,我喜欢我的MainViewModel是一个容器,只有容器,事件逻辑在别处处理.但你可以很容易地在这里使用你的Handle逻辑 - 但这是其他一些讨论.

现在每个子视图模型也需要自己导出,因此CM知道在哪里找到它们.

[Export(Typeof(YourFirstViewModel))]
public class YourFirstViewModel : IShell
{
    // VM properties and events here
}
Run Code Online (Sandbox Code Playgroud)

如果您只是使用默认构造函数,则无需指定导入构造函数.

现在,您对这些视图的每个视图将如下所示:

<UserControl x:Class="Your.Namespace.MainView"
             xmlns:views="clr-namespace:Your.Namespace.Views"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.ViewModels.MainViewModel"
             MinWidth="800" MinHeight="600">
    <StackPanel x:Name="RootVisual">
        <views:YourFirstView />
        <views:YourSecondView />
        <!-- other controls as needed -->
    </StackPanel>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

XAMl或其中一个子视图

<UserControl x:Class="Your.Namespace.Views.YourFirstView"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"
             MinWidth="800" MinHeight="600">
    <Grid x:Name="RootVisual">
        <!-- A bunch of controls here -->
    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事?

好吧,CM在引导程序中看到,由于行指定,MainViewModel是起点public class AppBootstrapper : Bootstrapper<MainViewModel>.MainViewModel要求在它的构造函数中需要a YourFirstViewModelYourSecondViewModel(以及其他ViewModel),因此CM构造每一个.所有这些ViewModel最终都会出现在IoC中(以后会让您的生活变得更轻松 - 再次,整个其他讨论).

CM处理代表您为每个视图分配datacontext,因为您指定要绑定到哪个VM的行 cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"

运气好的话,应该让你开始吧.另请参阅CM示例项目,Caliburn.Micro.HelloEventAggregator因为它完全符合您的要求(尽管,它被描述为Event Aggregator演示,这也非常有用 - 但同样,另一个讨论)

(尊敬的原始答案,见下文)

你需要这样做:

<UserControl x:Class="Your.Namespace.Here.YourView"
             xmlns:cal="http://www.caliburnproject.org"
             cal:Bind.Model="Your.Namespace.Here.YourViewModel"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="1024">
  <YourControlLayout />
</UserControl>
Run Code Online (Sandbox Code Playgroud)

请注意cal:Bind.Model="Your.Namespace.Here.YourViewModel"指定要将此View绑定到的精确视图模型的行.

不要忘记导出您的类类型,否则cm无法找到它.

[Export(typeof(YourViewModel))]
public class YourViewModel : IShell
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以根据需要嵌套用户控件.这是一种使用CM的非常好的方法,你会发现它具有高度的可扩展性.唯一的缺点是View和ViewModel必须在同一个项目中(据我所知).但是这种方法的优点是,如果您愿意,可以将View和View Model类分离到不同的命名空间(在同一个项目中),以保持组织有序.

作为对cm的评论,我更喜欢这种方法,实际上,即使我不需要嵌套View UserControl等.我宁愿明确地声明一个View被绑定的女巫VM(并且仍然允许CM处理IoC中所有繁重的工作),而不是让cm从隐含代码中"弄明白".

即使有一个好的框架:显式代码比隐含代码更易于维护.指定绑定的视图模型的好处是可以清楚地说明您的数据上下文是什么,因此您不需要稍后猜测.


dev*_*tal 17

更好的方法是ContentControl在主视图上使用,并为其提供与MainViewModel类型的公共属性相同的名称MyControlViewModel.例如

MainView.xaml

<ContentControl x:Name="MyControlViewModel" />
Run Code Online (Sandbox Code Playgroud)

MainViewModel.cs

// Constructor
public MainViewModel()
{
  // It would be better to use dependency injection here
  this.MyControlViewModel = new MyControlViewModel();     
}

public MyControlViewModel MyControlViewModel
{
  get { return this.myControlViewModel; }
  set { this.myControlViewModel = value; this.NotifyOfPropertyChanged(...); }
}
Run Code Online (Sandbox Code Playgroud)

  • 您正在使用CM,即将ContentControl的名称与视图模型属性的名称相匹配,查找视图,将视图注入ContentControl,以及将该视图的控件绑定到视图模型属性.这是使用Caliburn.Micro查看构图的推荐方法. (2认同)