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

标签 wpf mvvm caliburn.micro

我正在关注this tutorialCaliburn.Micro 框架中的 ScreenScreenConductors 上。

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

原始的简单导航示例有一个带有两个按钮的 shell,以及一个显示两个可能屏幕的内容区域,由 ShellViewModel 执行。

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

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

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

我问的问题是:“如何将 ScreenView.xaml 中的按钮“冒泡”到 ScreenConductorViewModel.cs 中的操作?

我当前的代码如下:


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

using Caliburn.Micro;

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

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

使用Caliburn.Micro;

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

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

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

最佳答案

只要您使用显式操作绑定(bind)语法绑定(bind)命令,冒泡就应该可以正常工作。这是因为按名称绑定(bind) CM 检查绑定(bind)到当前虚拟机的 View 上的控件。如果没有匹配的命名控件,则不会创建绑定(bind)。

你可以使用这个:

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

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

编辑:

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

值得通读 CodePlex 网站上的所有文档(虽然有相当多的页面,但它们足够详细地解释了所有内容,以便您将其余部分拼凑起来)。

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

Message 类如下所示:

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

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

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

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

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

在上面您可以看到使用了 $eventargs 特殊值。有几个开箱即用的特殊值,您也可以编写自己的特殊值(查看此问题 Using MessageBinder.SpecialValues in Windows 8 app not working?,其中用户使用 SpecialValues 从控件传递水平鼠标位置以供使用在合成器应用程序中)

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

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

其中 TextBox1Text 值将传递到 VM 上的 MouseClicked 方法。这是在 TextBox 的默认约定绑定(bind)中指定的(查看 ConventionManager.AddElementConvention 及其文档)

冒泡的工作原理是检查可视化树并尝试绑定(bind)到每个级别(发生在 ActionMessage 类中的 SetMethodBinding 中)

它非常简单但有效(它只是使用 VisualTreeHelper 遍历可视化树,直到找到合适的处理程序)

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

关于wpf - Caliburn.Micro:将屏幕中的按钮绑定(bind)到 ScreenConductor 中的命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16345211/

相关文章:

c# - 当设计中已经存在一个或多个选项卡时,如何在 WPF MVVM 中动态添加选项卡控件

android - 在 MVVM 架构中从 ViewModel 添加 fragment

caSTLe-windsor - 温莎城堡 : Set component dependencies on existing object

wpf IValueConverter 不更新 View

WPF 数据网格左列

c# - 如何从作为 listBoxItem 的 stackpanel 访问标签

wpf - 由于 “direct delegate roots”,System.Timers.Timer泄漏

c# - WPF MVVM - 从 ViewModel 访问 View 中 DataGrid 的 DependencyProperty

c# - 使用 Caliburn.Micro 将命令绑定(bind)到 ListView 内的按钮

silverlight - 使用 WCF RIA 和 MVVM 模式验证 UI 上的数据