Caliburn.Micro Conductor: Trigger/Action firing more than exptected

拥有回忆 提交于 2019-12-24 06:58:08

问题


I'm trying to put together a very simple example app, but it is not working as intented.

Here is the scenario:

Caliburn.Micro, MVVM, Silverlight 5.0 - simple Conductor example from https://caliburnmicro.codeplex.com/wikipage?title=Screens%2c%20Conductors%20and%20Composition&referringTitle=Documentation (Simple Navigation)

I just put together a live example: 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());
    }
}

EDIT:

Same results with this:

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.

The above example just works fine, after clicking on Login button shows login view, on Master shows master view.

In the Login View there is a textbox which has an event trigger. After hitting Enter key, it calls a method from viewmodel and displays a messagebox.

The problem:

When going to master view and going back to login end hitting Enter - it shows the messagebox twice!

Going to master and again back -> it will display it 3x.. and so on.

I think the Trigger should fire only once. How can we achieve this behavior?


回答1:


I think it's because your doing the ActivateItem each time your loading the view which rebinds the event handlers to the view. Try setting the ActiveItem property instead (which the ContentControl with x:Name="ActiveItem" is bound to). Also try using public variables to hold your view models:

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;
    }
}

EDIT

I was able to reproduce this and it seems to be an issue with the Expression Interactions. If I use a regular EventTrigger attached to key down it works fine:

        <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");
    }


来源:https://stackoverflow.com/questions/20434699/caliburn-micro-conductor-trigger-action-firing-more-than-exptected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!