我正在尝试使用带有WPF的Caliburn.Micro。如何在视图中添加多个视图?
<Window x:Class="ProjectName.Views.MainView"
...>
<Grid>
<views:MyControlView />
</Grid>
</Window>
使用viewmodel的另一个视图:MyControlViewModel
<UserControl x:Class="ProjectName.Views.MyControlView"
...>
<Grid>
...
</Grid>
</UserControl>
如果我只是添加视图,它将不会检测到它具有具有适当名称的viewmodel。我怎么能把它绑在上面呢?
我尝试过使用不同的bootstrappers并使用类似cal:Bind.Model =“path / classname / merge of the two”。试图将其添加到主视图和usercontrol(MyControlView)。我非常感谢有关此事的任何帮助。我几乎陷入困境,我真的想使用Caliburn.Micro:)
最诚挚的问候, diamondfish
编辑:我仍然无法让它工作,问题似乎是在引导程序或其他东西。但只是为了澄清,这是我的代码,我正在为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>
MainViewModel代码:
public partial class MainViewModel : PropertyChangedBase
{
}
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>
MyControlView代码:
public class MyControlViewModel : PropertyChangedBase
{
public string MyProp
{
get { return "Working"; }
}
}
错误的屏幕截图:http://clip2net.com/s/1gtgt
我试过了
cal:Bind.Model="Test.ViewModels.MyControlViewModel"
也是。还尝试了cal-reference:
xmlns:cal="http://www.caliburnproject.org"
我的项目http://clip2net.com/s/1gthM
的屏幕截图由于文档主要用于silverlight,有时用于Caliburn而不是CM,我可能已经错误地实现了bootstrapper。对于这个测试项目,就像这样:(使用App.xaml中的.xaml-change)
public class BootStrapper : Bootstrapper<MainViewModel>
{
}
请帮帮我吧!看起来这是我遗漏的一些基本内容:)
答案 0 :(得分:16)
编辑 - 新(更完整)答案如下:
好的,C.M正在为你做很多事情,这就是让你的课程和xaml准备好让C.M能够找到它。如上所述,我更喜欢将代码显式化,而不是依赖于框架的隐式代码假设。
因此,来自默认C.M项目的Bootstrapper就好了。
public class AppBootstrapper : Bootstrapper<MainViewModel>
{
// ... You shouldn't need to change much, if anything
}
“Bootstrapper”部分非常重要,它指示应用程序启动时哪个ViewModel是您的第一个或主屏幕。
[Export(Typeof(MainViewModel))]
public class MainViewModel : Screen, IShell
{
[ImportingConstructor]
public MainViewModel(YourFirstViewModel firstViewModel, YourSecondViewModel secondviewModel) // etc, for each child ViewModel
{
}
}
在[ImportingConstructor]
中,除了指定MainViewModel需要存在其他ViewModel之外,您不需要执行任何操作。在我的特定情况下,我喜欢我的MainViewModel是一个容器,只有容器,事件逻辑在别处处理。但你可以很容易地在这里使用你的Handle逻辑 - 但那是其他的讨论。
现在每个子视图模型也需要自己导出,所以C.M知道在哪里找到它们。
[Export(Typeof(YourFirstViewModel))]
public class YourFirstViewModel : IShell
{
// VM properties and events here
}
如果您只使用默认构造函数,则无需指定导入构造函数。
现在,您对这些内容的每个视图都会显示如下:
<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>
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>
这到底是怎么回事?
好吧,C.M在引导程序中看到,由于指定了public class AppBootstrapper : Bootstrapper<MainViewModel>
的行,MainViewModel是起点。 MainViewModel
要求在其构造函数中需要YourFirstViewModel
和YourSecondViewModel
(以及其他ViewModel),因此C.M构造每个。所有这些ViewModel最终都会出现在IoC中(以后会让您的生活变得更加轻松 - 再次,还有其他讨论)。
C.M处理代表您分配datacontext到每个视图,因为您指定要绑定到哪个VM与cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"
运气好的话,应该让你开始吧。另请参阅C.M示例项目Caliburn.Micro.HelloEventAggregator
,因为它完全符合您的要求(尽管,它被描述为事件聚合器演示,这也非常有用 - 但同样,另一个讨论)
(敬畏的原始答案,见下文)
你需要这样做:
<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>
注意第cal:Bind.Model="Your.Namespace.Here.YourViewModel"
行,它指定了将此视图绑定到的精确视图模型。
不要忘记导出你的班级类型,或者c.m找不到它。
[Export(typeof(YourViewModel))]
public class YourViewModel : IShell
{
...
}
然后您可以根据需要嵌套用户控件。这是使用C.M的一种非常好的方式,你会发现它具有高度可扩展性。唯一的缺点是View和ViewModel必须在同一个项目中(据我所知)。但是这种方法的优势在于,如果您愿意,可以将View和View Model类分离到不同的命名空间(在同一个项目中),以保持组织有序。
作为对c.m的评论,我更喜欢这种方法,实际上,即使我不需要嵌套View UserControls等等。我宁愿明确地声明一个View必须使用的女巫VM(并且仍然允许C.M处理IoC中所有繁重的工作),而不是让c.m从隐含代码中“弄明白”。
即使有一个好的框架:显式代码比隐含代码更易于维护。指定绑定的视图模型具有明确说明您的数据上下文预期的好处,因此您不需要稍后猜测。
答案 1 :(得分:16)
更好的方法是在主视图上使用ContentControl
,并在MainViewModel
MyControlViewModel
上为其提供与<ContentControl x:Name="MyControlViewModel" />
类型相同的公共属性。 E.g。
<强> MainView.xaml 强>
// 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(...); }
}
<强> MainViewModel.cs 强>
{{1}}
答案 2 :(得分:1)
在文件App.xaml.cs中,在方法GetInstance中添加以下行
protected override object GetInstance(Type service, string key) { if (service == null && !string.IsNullOrWhiteSpace(key)) { service = Type.GetType(key); key = null; } // the rest of method }