使用 WPF 和 Caliburn.Micro 在视图中添加多个视图
Posted
技术标签:
【中文标题】使用 WPF 和 Caliburn.Micro 在视图中添加多个视图【英文标题】:Add multiple views inside a view using WPF and Caliburn.Micro 【发布时间】:2011-12-14 08:22:14 【问题描述】:我正在尝试学习将 Caliburn.Micro 与 WPF 结合使用。如何在一个视图中添加多个视图?
<Window x:Class="ProjectName.Views.MainView"
...>
<Grid>
<views:MyControlView />
</Grid>
</Window>
另一个视图,带有视图模型:MyControlViewModel
<UserControl x:Class="ProjectName.Views.MyControlView"
...>
<Grid>
...
</Grid>
</UserControl>
如果我只是添加视图,它不会检测到它有一个具有适当名称的视图模型。我怎样才能将它绑定到它?
我尝试过使用不同的引导程序并使用类似 cal:Bind.Model="path/classname/merge of the two" 之类的东西。已尝试将其添加到主视图和用户控件(MyControlView)。我非常感谢有关此事的任何帮助。我几乎被卡住了,我真的很想使用 Caliburn.Micro :)
最好的问候, 钻石鱼
编辑:我仍然无法让它工作,问题似乎出在引导程序或其他东西上。但为了澄清,这是我正在为一个测试项目运行的代码。
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,因此我可能错误地实现了引导程序。对于这个测试项目,它就像这样:(使用 App.xaml 中的 .xaml-change)
public class BootStrapper : Bootstrapper<MainViewModel>
请帮帮我!似乎这是我缺少的一些基本东西:)
【问题讨论】:
-编辑帖子以包含 MVVM 标签,欢迎来到 S.O! 检查分析器 - 我添加了关于导出类型的部分。这是 c.m 找到与 View 相关的 ViewModel 的重要要求。 【参考方案1】:编辑 - 新的(更完整的)答案如下:
好的,C.M 正在为您做很多事情,都是为了让您的课程和 xaml 为 C.M 找到它做好准备。如上所述,我更喜欢显式地编写代码,而不是依赖于框架的隐式代码假设。
所以,默认 C.M 项目中的引导程序就可以了。
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 在引导程序中看到 MainViewModel 是起点,因为指定 public class AppBootstrapper : Bootstrapper<MainViewModel>
的行。 MainViewModel
要求其构造函数中需要 YourFirstViewModel
和 YourSecondViewModel
(以及其他 ViewModel),因此 C.M 构造每一个。所有这些 ViewModel 最终都会出现在 IoC 中(让您以后的生活更轻松 - 再次,完全是另一个讨论)。
C.M 代表您将数据上下文分配给每个视图,因为您可以使用 cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"
之类的行指定要绑定到哪个 VM
运气好的话,这应该可以帮助您入门。另请参阅 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 绑定到的虚拟机(并且仍然让 C.M 处理 IoC 中的所有繁重工作),而不是让 c.m 从隐含的代码中“弄清楚”。
即使有一个好的框架:显式代码比隐式代码更易于维护。指定绑定的 View Model 的好处是可以清楚地说明您的数据上下文应该是什么,因此您以后无需猜测。
【讨论】:
感谢您说明它应该是怎样的。虽然,我无法让它工作。请查看我的原始帖子并检查更新的部分。很想解决这个问题:) 你在正确的轨道上 - 我们只是错过了一些愚蠢的东西。添加了关于导出的信息。 呸,这行不通:S 我尝试添加一个 MefBootstrapper 类并实现了 IShell 接口,但仍然没有。如果您有时间查看我的项目,请随时查看 :) johanbjarnle.se/temp/CaliburnTest.rar caliburnmicro.codeplex.com/… 这个例子展示了如何做你所追求的。一个内部有两个子视图模型的主视图模型(或外壳)。 很好的答案,这应该取代 Caliburn 的入门/n00b 指南 :)【参考方案2】:更好的方法是在主视图上使用ContentControl
,并将其与MainViewModel
上的MyControlViewModel
类型的公共属性命名相同。例如
MainView.xaml
<ContentControl x:Name="MyControlViewModel" />
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(...);
【讨论】:
我得到了这个工作。但它似乎没有充分利用 C.M?虽然这样做的好方法,但非常感谢! 我还发现在VS中使用ContentControl进行编辑时,在MainView中看不到MyControl的界面。有没有办法做到这一点? 您正在使用 CM,这就是将 ContentControl 的名称与您的视图模型属性的名称相匹配、定位视图、将视图注入 ContentControl 并将该视图的控件绑定到查看模型属性。这是使用 Caliburn.Micro 查看合成的推荐方法。 至于Visual Studio Designer内部运行的约定,我认为目前还不可能,因此您需要分别编辑每个视图的界面。【参考方案3】:在文件 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
【讨论】:
修复了在我的引导程序中使用 Ninject 时我的值不能为空的错误。非常感谢:)以上是关于使用 WPF 和 Caliburn.Micro 在视图中添加多个视图的主要内容,如果未能解决你的问题,请参考以下文章
使用 Caliburn.Micro 的单实例 WPF 应用程序
使用 Caliburn.Micro 4.0.x 和 WPF 的对话框
WPF Caliburn.Micro 和 TabControl 与 UserControls 问题
WPF MVVM(Caliburn.Micro+Metro)-配置Caliburn.Micro