2014-12-19 11 views
1

[이 문제를 진단하는 첫 번째 찌르기에서 잘못된 질문을했습니다. 이제 수정되었습니다.]Caliburn Micro Conductor.OneActive를 사용할 때 블렌드 상호 작용 이벤트 트리거가 여러 번 실행되는 이유는 무엇입니까?

Conductor.Collection.OneActive에서 상속하는 하나의 주 창이있는 WPF 응용 프로그램이 있습니다. 탐색 요청을 처리하고 상태가 유지되도록보기 모델의 캐시를 유지합니다. 이 비공개 컬렉션은 base.Items 컬렉션과 거의 동일하지만 모든 뷰 모델이 IScreen이 아닙니다.

모든 항목이 올바르게 작동하고 하나의 활성 항목에서 다른 항목으로 이동할 때 상태가 유지됩니다. 그러나 상호 작용 트리거에 버그가 있습니다. 활성 항목이 IScreen 인 경우 트리거는 매번 다시 연결되는 것처럼 탐색 당 추가 시간을 실행합니다. 일반 트리거는이 작업을 수행하지 않고 상호 작용 라이브러리의 작업 만 트리거합니다. 활성 항목이 PropertyChangedBase에서 상속받은 IScreen이 아닌 경우이 문제는 보이지 않지만 탐색 중에는 뷰의 상태를 잃게됩니다.

보기로 네 번 이동하면 해당 이벤트는 네 번, 다섯 번, 다섯 번씩 실행됩니다.

이것은 동일한 as this question처럼 보이지만 특정 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; 
    } 
} 

내 MainWindow를 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> 
.... 
+0

을 : http://stackoverflow.com/a/8835349/81317 ActiveItem이 설정되면 자식 컨트롤 Loaded 이벤트가 발생합니다. KeyTrigger는 Load에 연결되어 있으므로 여러 번로드됩니다. 자체 KeyTrigger 클래스를 만들고 KeyTrigger에서 상속하면 OnEvent 메서드를 재정의하고 여러 첨부 파일을 중지 할 수 있습니다. 그러나 ActivateItem을 수행 할 때마다 Load 이벤트가 얼마나 많은 영향을 받는지 궁금합니다. 잘못된 일을하고 있거나 KeyTrigger에 문제가있어 회피 할 수 없습니다. –

+1

디 컴파일러를 사용하여 추가 조사를 수행하면 KeyTrigger가 Load 중에 키 누르기 이벤트 처리기를 연결하지만 UserControl이 언로드 될 때 OnDetaching 호출이 발생하지 않으므로 대칭이 아니어야합니다. 따라서 UserControl은 활성화 될 때마다 Load 이벤트를 가져오고 KeyTrigger는 유선 상태입니다. –

답변

1

this question here has a better answer, 허용되는 답변에 댓글에 숨겨져있는 것 같습니다. KeyTrigger 클래스는 문제가되며 하위 컨트롤이 ContentControl에 다시로드 될 때마다 이벤트가 첨부됩니다. @gunter는 "실제 문제는 OnLoaded에 관한 것이고 탭 컨트롤의 요소는 여러 개의 OnLoaded 이벤트를 얻습니다." 그런 다음 @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(); 
    }