为什么混合交互事件触发火灾多次使用卡利微Conductor.OneActive什么时候?(Why d

2019-10-21 11:28发布

[请注意,我问我的第一个尝试错误的问题,在这个诊断 - 现在改正]

我有从Conductor.Collection.OneActive继承一个主窗口WPF应用程序。 它可以处理导航请求,并不断使状态保持的ViewModels的缓存。 这家私人收藏是几乎相同的base.Items集合,但并非所有的ViewModels的是IScreen。

一切工作正常,当我们移动从一个活动项目到另一个状态得以保持。 然而,与交互触发的错误。 当主项是IScreen,触发器触发每一个导航额外的时间,因为如果他们再次每次有线连接起来; 正常触发不这样做,只是从互动库的人。 如果活动项目不是IScreen - 从PropertyChangedBase只是继承了 - 我们没有看到这个问题,也是我们在导航过程中失去了视图的状态。

如果您导航到一个视图四次,该事件将触发四次,五次,五,依此类推。

这似乎是相同的,因为这问题,但我不能用自己的解决方案,因为我不知道具体的ViewModels是什么,他们不能创建公共属性。

我的主窗口类看起来是这样的:

public sealed class MainWindowViewModel : Conductor<object>.Collection.OneActive, IHandle<NavigateToUriMessage>
{
    public void Handle(NavigateToUriMessage message)
    {
        var ignoredUris = RibbonUri.GetItems().Where(t => t.SubTabs.Count > 0).Select(t => t.Uri);

        Func<string, bool> isMatch = uri => uri == message.Uri;

        if (isMatch(RibbonUri.BookkeepingBatchView.Uri))
            GetAndActivateViewModel<BatchPanelViewModel>(message);           
        ...
    }

    private T GetAndActivateViewModel<T>(NavigateToUriMessage message) where T : class
    {
        var vm = GetViewModel<T>(message.Uri);
        ActivateItem(vm);
        return (T) vm;
    }

    private object GetViewModel<T>(string uri) where T : class
    {
        if (viewModelCache.ContainsKey(uri))
            return viewModelCache[uri];
        var vm = viewModelFactory.Create<T>();
        viewModelCache.Add(uri, vm);
        return vm;
    }
}

我的主窗口XAML看起来像这样:

<Window x:Class="Ui.Views.MainWindowView"
      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" 
      d:DataContext="{d:DesignInstance Type=viewModels:MainWindowViewModel, IsDesignTimeCreatable=False}"
      mc:Ignorable="d"
      WindowState="Maximized" >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1"/>
            <RowDefinition/>
            <RowDefinition Height="1"/>
            <RowDefinition Height="25"/>
        </Grid.RowDefinitions>
        <ContentControl x:Name="MainRibbon" Grid.Row="0" Margin="0" />
        <Grid Background="#FFBBBBBB" Grid.Row="1" />
        <ContentControl Grid.Row="2" x:Name="ActiveItem" Background="White" />
        <Grid  Grid.Row="3" Background="#FFBBBBBB"/>
        <ContentControl x:Name="BottomStatusBar" Grid.Row="4"/>
    </Grid>
</Window>

而在当前项目视图中的XAML看起来像这样:

<DataGrid Focusable="True" FocusVisualStyle="{x:Null}" SelectionMode="Single" HeadersVisibility="None" IsReadOnly="True" GridLinesVisibility="None" AutoGenerateColumns="False" Background="Transparent" BorderThickness="0"  Grid.Row="3" Grid.RowSpan="2">
            <i:Interaction.Triggers>
                <ei:KeyTrigger Key="Left" FiredOn="KeyUp" ActiveOnFocus="True" >
                    <cal:ActionMessage MethodName="TryCollapseSelectedItem"/>
                </ei:KeyTrigger>
                <ei:KeyTrigger Key="Right" FiredOn="KeyUp" ActiveOnFocus="True" >
                    <cal:ActionMessage MethodName="TryExpandSelectedItem"/>
                </ei:KeyTrigger>
            </i:Interaction.Triggers>
 ....

Answer 1:

看来, 这个问题在这里有一个更好的答案 ,虽然藏在评论中接受的答案。 该KeyTrigger类是有问题的和活动连接每个子控件重新加载到ContentControl中的时间。 @gunter说,“真正的问题似乎是在装载的,并且在标签控件元素得到多个装载的事件挂钩。” 然后@dain说,“好吧,我看看。嗯,KeyTrigger是一个公共类,这样可以延长它并重写的OnEvent防止多个事件处理附件?”

所以,我实现了@岱恩的建议下,推翻了KeyTrigger类,并停止该事件被连接好多次:

public class MyKeyTrigger : KeyTrigger
{
    private bool eventAttached;

    protected override void OnEvent(EventArgs eventArgs)
    {
        if (eventAttached) return;
        base.OnEvent(eventArgs);
        eventAttached = true;
    }

    protected override void OnDetaching()
    {
        eventAttached = false;
        base.OnDetaching();
    }


文章来源: Why do Blend Interaction event triggers fire multiple times when using a Caliburn Micro Conductor.OneActive?