wpf Caliburn.Micro:将屏幕中的按钮绑定到 ScreenConductor 中的命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16345211/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:43:23  来源:igfitidea点击:

Caliburn.Micro: Binding Button in a Screen to a command in ScreenConductor

wpfmvvmcaliburn.micro

提问by heltonbiker

I'm following this tutorialon Screenand ScreenConductorsin Caliburn.MicroFramework.

我在Framework上和在这个教程中。ScreenScreenConductorsCaliburn.Micro

I'm using WPF, not Silverlight, and I have made the corresponding changes in App.xaml (using MergedDictionary for the Bootstrapper).

我使用的是 WPF,而不是 Silverlight,并且我在 App.xaml 中进行了相应的更改(使用 MergedDictionary 作为 Bootstrapper)。

The original Simple Navigation example has a shell with two buttons, and a content area where two possible screens are displayed, conducted by the ShellViewModel.

最初的简单导航示例有一个带有两个按钮的外壳,以及一个显示两个可能屏幕的内容区域,由ShellViewModel.

Then I tried to move each button to its counterpart View, so that PageOne would have a button to take to PageTwo, and vice-versa. I did it because I don't want the home shell continuously "showing its entrails" across the application.

然后我尝试将每个按钮移动到其对应的 View,以便 PageOne 将有一个按钮可以带到 PageTwo,反之亦然。我这样做是因为我不希望 home shell 在整个应用程序中不断“显示它的内脏”。

The fact is, if I just move a button to a ScreenView, it no longer binds to the command, which is in the ShellViewModel, not in the ScreenViewModel itself. I know these bindings happen by convention, but I don't know if the convention covers this case, or I'd need to configure.

事实是,如果我只是将按钮移动到Screen视图,它不再绑定到命令,该命令位于 中ShellViewModel,而不是在ScreenViewModel 本身中。我知道这些绑定是按约定发生的,但我不知道约定是否涵盖这种情况,或者我需要配置。

The symptom I am facing is: When I run the app, PageOneView shows, with the "Go to Page Two" button in it, but when I click the button nothing happens.

我面临的症状是:当我运行应用程序时,PageOneView 显示,其中包含“转到第二页”按钮,但是当我单击该按钮时,没有任何反应。

The question I ask is: "How is the proper way to "bubble" a button in a ScreenView.xaml to an action in the ScreenConductorViewModel.cs?

我问的问题是:“将 ScreenView.xaml 中的按钮“冒泡”到 ScreenConductorViewModel.cs 中的操作的正确方法是什么?

My current code is below:

我目前的代码如下:



PageOneView.xaml

PageOneView.xaml

<UserControl x:Class="ScreenConductor.PageOneView"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Background="LightGreen">
        <Button x:Name="ShowPageTwo" Content="Show Page Two" HorizontalAlignment="Center" VerticalAlignment="Top" />
    </Grid>
</UserControl>


PageOneViewModel

PageOneViewModel

using Caliburn.Micro;

namespace ScreenConductor {
    public class PageOneViewModel : Screen {
        protected override void OnActivate() {
            base.OnActivate();
        }
    }
}


ShellView.xaml

ShellView.xaml

<Window x:Class="ScreenConductor.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <ContentControl x:Name="ActiveItem" />
</Window>


ShellViewModel.cs

ShellViewModel.cs

using Caliburn.Micro;

使用 Caliburn.Micro;

namespace ScreenConductor 
{
    public class ShellViewModel : Conductor<object> 
    {
        public ShellViewModel() 
        {
            ShowPageOne();
        }

        public void ShowPageOne() 
        {
            ActivateItem(new PageOneViewModel());
        }

        public void ShowPageTwo() 
        {
            ActivateItem(new PageTwoViewModel());
        }
    }
}


回答by Charleh

As long as you bind the command using the explicit action binding syntax the bubbling should work fine. This is because to bind by name CM examines controls on the view bound to the current vm. If there is no matching named control a binding does not get created.

只要您使用显式操作绑定语法绑定命令,冒泡应该可以正常工作。这是因为通过名称绑定 CM 检查绑定到当前 vm 的视图上的控件。如果没有匹配的命名控件,则不会创建绑定。

You can use this:

你可以使用这个:

<SomeControl cal:Message.Attach="SomeMethodOnParentVM" />

This will attempt to bubble the message up the control hierarchy until a suitable handler is found. Note that this will throw an exception if no handler could be found. I recall there being an option to turn this off on the binding but you might want to check the docs (I'm contributing from my mobile at the moment :-)

这将尝试在控件层次结构中向上冒泡消息,直到找到合适的处理程序。请注意,如果找不到处理程序,这将引发异常。我记得有一个选项可以在绑定时关闭此功能,但您可能想查看文档(我目前正在通过我的手机进行贡献:-)

Edit:

编辑:

Ok if you want more info for behind the scenes, the best place to check really is the source. The author Rob Eisenberg mentions that the source is quite small (something like 2700 lines of code I think) so it's easy to inspect and easy to hold in your head

好的,如果您想了解更多幕后信息,最好的检查地点确实是来源。作者 Rob Eisenberg 提到源代码非常小(我认为大约有 2700 行代码),因此很容易检查并且很容易记住

It's worth reading through all the documentation on the CodePlex site (there's a fair few pages but they explain everything in enough detail for you to piece together the rest).

值得通读 CodePlex 站点上的所有文档(有几页,但它们对所有内容进行了足够详细的解释,以便您将其余部分拼凑起来)。

Not sure how much you know about the Messageclass that contains the Attachattached property but this is what kicks off the action binding when the standard control Nameconventions aren't used (I assume you know about attached properties in WPF/SL). You can see the standard named conventions in the ViewModelBinderclass

不确定您对Message包含Attach附加属性的类了解多少,但这是Name在不使用标准控件约定时启动动作绑定的原因(我假设您了解 WPF/SL 中的附加属性)。您可以在ViewModelBinder类中看到标准的命名约定

The Messageclass looks like:

这个Message类看起来像:

http://caliburnmicro.codeplex.com/SourceControl/changeset/view/35582bb2a8dfdd3fcd71a07fa82581ddb93a786f#src/Caliburn.Micro.Silverlight/Message.cs

http://caliburnmicro.codeplex.com/SourceControl/changeset/view/35582bb2a8dfdd3fcd71a07fa82581ddb93a786f#src/Caliburn.Micro.Silverlight/Message.cs

(yes it's the Silverlight source but this is the base for all other versions and it's just a few compiler directives and some additional classes that appear in other version such as WPF/WinRT)

(是的,它是 Silverlight 源,但这是所有其他版本的基础,它只是一些编译器指令和一些出现在其他版本(如 WPF/WinRT)中的附加类)

If you look at the source you can see that when the attached property is set, the Parserclass kicks off to parse the string. The parser actually parses several different formats so you can attach to different events and methods, and also pass properties e.g.

如果查看源代码,您会发现当设置了附加属性时,Parser该类将开始解析字符串。解析器实际上解析了几种不同的格式,因此您可以附加到不同的事件和方法,并传递属性,例如

<Button cal:Message.Attach="[Event Click] = [Action SomeButtonWasClicked()]" /> 

or

或者

<Button cal:Message.Attach="[Event MouseEnter] = [Action MouseEnteredAButton($eventargs)" />

Above you can see that the $eventargsspecial value was used. There are several out-of-box special values, and you can also write your own (check out this SO question Using MessageBinder.SpecialValues in Windows 8 app not working?where a user was using SpecialValuesto pass the horizontal mouse position from controls for use in a synthesizer app)

在上面您可以看到使用了$eventargs特殊值。有几个开箱即用的特殊值,您也可以自己编写(查看这个 SO 问题Using MessageBinder.SpecialValues in Windows 8 app not working?where a user is usedSpecialValuesto pass the level mouse position from controls to use在合成器应用程序中)

You can also pass the CM default property of other controls e.g.

您还可以传递其他控件的 CM 默认属性,例如

<TextBox x:Name="TextBox1" />
<Button cal:Message.Attach="MouseClicked(TextBox1)" />

Where the Textvalue of TextBox1will be passed to the MouseClickedmethod on the VM. This is specified in the default convention bindings for TextBox(look at ConventionManager.AddElementConventionand the docs on that)

其中 的TextTextBox1将传递给MouseClickedVM 上的方法。这是在默认约定绑定中指定的TextBox(查看ConventionManager.AddElementConvention和文档)

The bubbling works by inspecting the visual tree and attempting to bind to each level (happens in SetMethodBindingin ActionMessageclass)

冒泡通过检查可视化树并尝试绑定到每个级别来工作(发生SetMethodBindingActionMessage课堂上)

It's pretty simple but effective (it just uses VisualTreeHelperto walk up the visual tree until a suitable handler is found)

它非常简单但有效(它只是用于VisualTreeHelper在可视化树中向上走,直到找到合适的处理程序)

Not sure what else you might need info on :P

不确定您可能还需要什么信息:P

回答by Michael Schnerring

If you have not yet referenced System.Windows.Interactivity(goes along with the Blend SDK) I'd really recommend it. I suppose a Caliburn.Micro project runs without it though I have never tried it. It's referenced per default as you install Caliburn.Micro via NuGet.

如果您还没有参考System.Windows.Interactivity(与 Blend SDK 一起使用),我真的会推荐它。我想 Caliburn.Micro 项目可以在没有它的情况下运行,尽管我从未尝试过。当您通过 NuGet 安装 Caliburn.Micro 时,默认情况下会引用它。

Your problem can be solved properly with using System.Windows.Interactivity.Interactionalong with Caliburn.Micro.ActionMessagelike this:

你的问题可以适当使用可以解决System.Windows.Interactivity.Interaction伴随着Caliburn.Micro.ActionMessage这样的:

<UserControl x:Class="ScreenConductor.PageOneView"
             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:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:cal="http://www.caliburnproject.org"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Button Content="ShowPageTwo">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <cal:ActionMessage MethodName="ShowPageTwo" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </Grid>
</UserControl>

You can find more about actions here, the official documentation at CodePlex.

您可以在此处找到有关操作的更多信息,CodePlex 的官方文档。

Action messages are going to bubble to the conductor and if no suitable method can be found an Exceptionis thrown.

操作消息将冒泡给指挥员,如果找不到合适的方法,Exception则会抛出。