Caliburn.Micro指挥:触发/动作射击超过预期

时间:2013-12-06 22:28:39

标签: c# silverlight silverlight-5.0 caliburn.micro

我正在尝试整理一个非常简单的示例应用程序,但它并没有像预期的那样工作。

以下是该方案:

Caliburn.Micro,MVVM,Silverlight 5.0 - 来自https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation的简单导体示例(简单导航)

我刚刚整理了一个实例: https://db.tt/kTIjKvRx

-> hit enter in textbox (messagebox displays 1x)
-> go to master and go back to login
-> hit enter in textbox (messagebox displays 2x!)

ShellViewModel

public class ShellViewModel : Conductor<object> {
    public ShellViewModel() {
        ShowLogin();
    }

    public void ShowLogin() {
        ActivateItem(new LoginViewModel());
    }

    public void ShowMaster() {
        ActivateItem(new MasterViewModel());
    }
}

编辑:

与此相同的结果:

public class ShellViewModel : Conductor<object> {
    public ShellViewModel() {
        LoginModel = new LoginViewModel();
        MasterModel = new MasterViewModel();
        ShowLogin();
    }

    public LoginViewModel LoginModel { get; set; }
    public MasterViewModel MasterModel { get; set; }

    public void ShowLogin() {
        ActiveItem = LoginViewModel;
    }

    public void ShowMaster() {
        ActiveItem = MasterViewModel;
    }
}

ShellView

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" x:Class="Hele.ShellView"
    d:DesignWidth="438" d:DesignHeight="200">
<Grid>
    <StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top">
        <Button x:Name="ShowLogin" Width="100" Height="30" Content="Login"/>
        <Button x:Name="ShowMaster" Width="100" Height="30" Content="Master"/>

        <ContentControl x:Name="ActiveItem" " />
</Grid>
</UserControl>

LoginView

<UserControl ... >

<Grid x:Name="LayoutRoot">
    <StackPanel>
    <TextBlock>Login</TextBlock>
        <TextBox x:Name="Message" Text="{Binding Message, Mode=TwoWay}" >

            <i:Interaction.Triggers>
                <iex:KeyTrigger Key="Enter">
                    <cal:ActionMessage MethodName="Login" />
                </iex:KeyTrigger>
            </i:Interaction.Triggers>

        </TextBox>        
    </StackPanel>
</Grid>
</UserControl>

LoginViewModel

public class LoginViewModel : Screen
{
    public string Message { get; set; }

    public void Login()
    {
        MessageBox.Show("login messagebox");
    }
}

MasterView and MasterViewModel are just empty, nothing interesting there.

上面的例子工作正常,点击登录按钮显示登录视图后,在Master显示主视图。

在登录视图中,有一个具有事件触发器的文本框。点击Enter键后,它会从viewmodel调用一个方法并显示一个消息框。

问题:

当进入主视图并返回登录结束时按Enter键 - 它会显示消息框两次!

掌握并再次回来 - &gt;它将显示3x ..等等。

我认为触发器只能触发一次。我们怎样才能实现这种行为?

1 个答案:

答案 0 :(得分:0)

我认为这是因为每次加载视图时都会执行ActivateItem,这会将事件处理程序重新绑定到视图。尝试设置ActiveItem属性(具有x:Name =“ActiveItem”的ContentControl绑定到该属性)。还可以尝试使用公共变量来保存视图模型:

public class ShellViewModel : Conductor<object> {
    public ShellViewModel() {
        ShowLogin();
    }

    public LoginViewModel { get; set; }
    public MasterViewModel { get; set; }

    public void ShowLogin() {
        ActiveItem = LoginViewModel;
    }

    public void ShowMaster() {
        ActiveItem = MasterViewModel;
    }
}

修改

我能够重现这一点,这似乎是表达式交互的一个问题。如果我使用附加到按键的常规EventTrigger,它可以正常工作:

        <TextBox Width="50" Text="{Binding Message, Mode=TwoWay}" >
            <i:Interaction.Triggers>
                <!--<iex:KeyTrigger Key="Enter">
                    <cm:ActionMessage MethodName="Page1KeyPress" />
                </iex:KeyTrigger>-->
                <i:EventTrigger EventName="KeyDown">
                    <cm:ActionMessage MethodName="Page1KeyPress" >
                        <cm:Parameter Value="$source" />
                        <cm:Parameter Value="$eventArgs" />
                    </cm:ActionMessage>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>

    public void Page1KeyPress(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
            MessageBox.Show("Page 1 Key Press");
    }