使用WPF和Caliburn.Micro在视图内添加多个视图 [英] Add multiple views inside a view using WPF and Caliburn.Micro

查看:155
本文介绍了使用WPF和Caliburn.Micro在视图内添加多个视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Caliburn.Micro与WPF结合使用.如何在一个视图中添加多个视图?

I'm trying to learn using Caliburn.Micro with WPF. How can I add multiple views inside a view?

<Window x:Class="ProjectName.Views.MainView"
         ...>
<Grid>
        <views:MyControlView  />
</Grid>
</Window>

另一个视图,其视图模型为:MyControlViewModel

Another view, with viewmodel: MyControlViewModel

<UserControl x:Class="ProjectName.Views.MyControlView"
         ...>
<Grid>
    ...
</Grid>
</UserControl>

如果我只是添加视图,它将不会检测到它具有一个具有适当名称的viewmodel.我如何将其绑定到它?

If i just add the view, it won't detect that it has a viewmodel with the appropriate name. How can i bind this to it?

我尝试了不同的引导程序,并使用了诸如cal:Bind.Model ="path/classname/merge of two"之类的东西.尝试将其添加到主视图和用户控件(MyControlView).非常感谢您对此事的帮助.我非常困惑,我真的想使用Caliburn.Micro:)

I have tried out with different bootstrappers and using something like cal:Bind.Model="path/classname/merge of the two". Have tried to add that to the mainview and to the usercontrol (MyControlView). I'm VERY grateful for any help regarding this matter. I'm pretty much stuck, and I really want to use Caliburn.Micro :)

最好的问候, 钻石鱼

我仍然无法使它正常工作,问题似乎出在引导程序或其他问题上.但是,为了澄清一下,这是我正在为一个测试项目运行的代码.

I still can't get it to work, the problem seems to be in the bootstrapper or something else. But just to clarify, here is my code I'm running for a testproject.

MainView xaml:

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代码:

MainViewModel code:

public partial class MainViewModel : PropertyChangedBase
{
}

MyControlView xaml:

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代码:

MyControlView code:

public class MyControlViewModel : PropertyChangedBase
{
    public string MyProp
    {
        get { return "Working"; }
    }
}

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

我尝试过

cal:Bind.Model="Test.ViewModels.MyControlViewModel" 

也是.还尝试了cal-reference:

as well. Also tried the cal-reference:

xmlns:cal="http://www.caliburnproject.org"

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

由于文档主要是针对Silverlight的,有时是针对Caliburn而非CM的,因此我可能实现了bootstrapper错误.对于这个测试项目,它就像这样:(带有App.xaml中的.xaml-change)

Since the documentation mostly is for silverlight and sometimes is for Caliburn and not CM, I might have implemented the bootstrapper wrong. For this test-project, it's just like this: (with the .xaml-change in App.xaml)

public class BootStrapper : Bootstrapper<MainViewModel>
{
}

请在这里帮助我!看来这是我缺少的一些基本知识:)

Please help me out here! It seems like it is some basic stuff I'm missing :)

推荐答案

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

EDIT - New (more complete) Answer Below:

好吧,C.M正在为您做很多事情,这都是为了让您的课程和xaml为C.M做好准备以便能够找到它.如上所述,我更喜欢将代码编写为显式的,而不是依靠框架的隐式代码假设.

Ok, C.M is doing a lot of stuff for you, it's all about getting your classes and xaml prepared for C.M to be able to find it. As said above, I prefer to be write code explicit, rather than rely in implicit code assumptions by the framework.

因此,默认C.M项目中的Bootstrapper很好.

So, the Bootstrapper, from the default C.M project is just fine.

public class AppBootstrapper : Bootstrapper<MainViewModel>
{
    // ... You shouldn't need to change much, if anything
}

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

The section `Bootstrapper' is very important, is it indicates which ViewModel is your first, or main screen, when the app starts up.

[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逻辑-但这是另一段讨论了.

In the [ImportingConstructor] you don't need to do anything other than specify that the MainViewModel requires the presence of the other ViewModels. In my particular case, I like my MainViewModel to be a container, and container only, the event logic is handled elsewhere. But you could just as easily have your Handle logic here - but that's a while other discussion.

现在每个子视图模型也需要导出自己,以便C.M知道在哪里可以找到它们.

Now each child View Model also needs to export themselves so C.M knows where to find them.

[Export(Typeof(YourFirstViewModel))]
public class YourFirstViewModel : IShell
{
    // VM properties and events here
}

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

No need to specify an Importing Constructor if you are just using a default constructor.

现在,您用于这些视图的每个视图都将类似于:

Now, each of your Views for these will look something like:

<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或子视图之一

XAMl or one of the child-views

<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要求在其构造函数中需要一个YourFirstViewModelYourSecondViewModel(以及其他ViewModel),因此C.M构造每个.所有这些ViewModel最终都存在于IoC中(以后使您的生活更加轻松-再次进行其他讨论).

Well, C.M sees in the bootstrapper, that MainViewModel is the starting point because of the line specifying public class AppBootstrapper : Bootstrapper<MainViewModel>. MainViewModel requires that a YourFirstViewModel and YourSecondViewModel (and other ViewModels) are required in it's constructor, so C.M constructs each one. All of these ViewModels end up in the IoC (making your life much easier later - again, a whole other discussion).

C.M代表您为每个视图分配数据上下文,因为您可以使用cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"

C.M handles assigning the datacontext, on your behalf, to each of the views because you specify which VM to bind to with the line like cal:Bind.Model="Your.Namespace.ViewModels.YourFirstViewModel"

如果有运气,那应该会让您入门.还要参考C.M示例项目Caliburn.Micro.HelloEventAggregator,因为它确实可以满足您的需求(尽管它被描述为Event Aggregator演示,它也非常有用-但再次讨论)

With any luck, that should get you started. Also refer to the C.M example project Caliburn.Micro.HelloEventAggregator as it does exactly what you are looking for (Although, it's described as an Event Aggregator demo, which is also very useful - but again, another discussion)

(尊敬的原始答案,如下)

(Original Answer for reverence, below)

您需要执行以下操作:

<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"行,该行指定了将该视图绑定到的确切视图模型.

Notice the line cal:Bind.Model="Your.Namespace.Here.YourViewModel" which specifies the exact View Model to bind this View to.

别忘了导出您的类类型,否则c.m找不到它.

Don't forget to export your class type, or c.m can't find it.

[Export(typeof(YourViewModel))]
public class YourViewModel : IShell
{
    ...
}

然后,您可以根据需要嵌套用户控件.这是使用C.M的一种很好的方法,您会发现它具有高度的可扩展性.唯一的缺点是View和ViewModel必须在同一项目中(据我所知).但是这种方法的优势在于,您可以根据需要将View和View Model类分成不同的命名空间(在同一项目中),以保持事物的井井有条.

Then you can nest your User Controls as you see fit. It's a very good way to make use of C.M, and you will find it highly scalable. The only weakness is that the View and ViewModel must be in the same project (as far as I can tell). But the strength of this approach is you can separate the View and View Model classes into different Namespaces (within the same project) if you wish, to keep things organized.

作为对c.m的评论,实际上,即使我不必嵌套View UserControls之类,我还是喜欢这种方法.我宁愿明确声明声明与View绑定的VM(并且仍然让C.M处理IoC中的所有繁重工作),而不是让c.m从隐式代码中找出来".

As a commentary on c.m I prefer this method, actually, even if I don't have to nest View UserControls and such. I would rather explicitly declare witch VM a View is bound to (and still let C.M handle all the heavy lifting in IoC) than let c.m "figure it out" from implied code.

即使有一个好的框架:显式代码也比隐式代码更具可维护性.指定绑定的View模型的好处是可以清楚地说明期望数据上下文是什么,因此您以后无需猜测.

Even with a good framework: explicit code is more maintainable than implied code. Specifying the bound View Model has the benefit of clearly stating what your data context is expected to be, so you won't need to guess later.

这篇关于使用WPF和Caliburn.Micro在视图内添加多个视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆