2017-03-15 7 views
0

"MainView"및 일부 중첩 된 뷰가있는 Catel 응용 프로그램이 있습니다. 중첩 된 뷰는 ListView이고 일부 항목은 ContextMenu이고 일부는 MenuItems입니다.Catel - CommandParameter를 전달하지 않는 CommandManager

MainView의 ViewModel에서 전달 된 매개 변수로 무언가를 수행 할 TaskCommand<object>을 만들었습니다. 이 전달 된 매개 변수는 ListView의 현재 SelectedItem이어야합니다. 이 명령은 ICommandManager에 전역 적으로 등록됩니다.

MenuItem의 명령어를 ICommandManager에서 바인딩하면 전달 된 매개 변수는 항상 null이됩니다. 여기

관련 코드 :

NestedView.xaml :

<catel:UserControl 
    x:Name="UserControl" 
    x:Class="My.NameSpace.Views.View" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:catel="http://catel.codeplex.com"> 

... 
    <ListView ItemsSource="{Binding Items}" 
      BorderThickness="0" 
      SelectedItem="{Binding SelectedItem}" 
      HorizontalContentAlignment="Stretch"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
     <TextBlock VerticalAlignment="Center" 
        Margin="2.5" 
        Text="{Binding Description}"> 
      <TextBlock.ContextMenu> 
      <ContextMenu> 
       <MenuItem Header="Do Stuff" 
         Command="{catel:CommandManagerBinding DoStuffCommand}" 
         CommandParameter="{Binding DataContext.SelectedItem, ElementName=UserControl}" /> 
       ... 
      </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    </ListView> 
... 
</catel:UserControl> 

MainViewModel.cs : 당신이 더 많은 코드가 필요하면

public class MainViewModel : ViewModelBase { 
    ... 

    public ICommand DoStuffCommand { get; } 

    public MainViewModel(ICommandManager commandManager, IUIVisualizerService uiVisualizerService, IMessageService messageService) 
    { 
     ... 

     DoStuffCommand = new TaskCommand<object>(OnDoStuffCommandExecute); 

     commandManager.CreateCommand(nameof(DoStuffCommand)); 
     commandManager.RegisterCommand(nameof(DoStuffCommand), DoStuffCommand, this); 
    } 

    private async Task OnDoStuffCommandExecute(object parameter) 
    { 
     // command needs to be in the MainViewModel because there will be some modification on the MainView based on parameter (adding tabs, etc) 
     Debugger.Break(); 
    } 

    ... 
} 

, 나는대로이를 게시 할 수 있습니다 그러나 이것은 충분해야합니다.

나는 또한 Catel의 CommandManager 구현에보고했다이 발견 :

/// <summary> 
    /// Executes the command. 
    /// </summary> 
    /// <param name="commandName">Name of the command.</param> 
    /// <exception cref="ArgumentException">The <paramref name="commandName"/> is <c>null</c> or whitespace.</exception> 
    /// <exception cref="InvalidOperationException">The specified command is not created using the <see cref="CreateCommand"/> method.</exception> 
    public void ExecuteCommand(string commandName) 
    { 
     Argument.IsNotNullOrWhitespace("commandName", commandName); 

     lock (_lockObject) 
     { 
      Log.Debug("Executing command '{0}'", commandName); 

      if (!_commands.ContainsKey(commandName)) 
      { 
       throw Log.ErrorAndCreateException<InvalidOperationException>("Command '{0}' is not yet created using the CreateCommand method", commandName); 
      } 

      _commands[commandName].Execute(null); 
     } 
    } 

나는 내가 MenuItem을 클릭하고 행동을 설명 할 경우이 메서드가 호출 될 것이라고 가정한다.

OnExecute 메서드에 (바인딩 된) 매개 변수를 전달하기위한 적절한 해결책이나 해결 방법이 있습니까? 명령이

의 MenuItem 헤더 = "마 물건" CommandParameter는 = "{DataContext.SelectedItem 바인딩, ElementName을 = UserControl을 XAML에서 바인딩 전에 바인딩 CommandParameter를 미리 설정

답변

1

좋아요, 해결책을 찾았지만 사실 조금 이상합니다.

우선 Geo의 말처럼 Command={...}CommandParamter={...}의 순서를 바꿉니다. 그런 다음 많은 실패한 후에 나는 그것을 작동 시켰습니다. CommandParameter -Binding the Markup과 그 밖의 아무것도 전달하지 마십시오. 그래서 MenuItem 내 XAML 코드는 다음과 같습니다

<MenuItem Header="Do Stuff" 
      CommandParameter="{Binding}" 
      Command="{catel:CommandManagerBinding DoStuffCommand}"/> 

편집 :

확인이 지금은 솔루션 (내 생각)을 얻었다. 위의 방법은 대부분의 경우 작동하지만 @ mm8이 지적하는 문제가 발생할 수 있습니다.

그래서 나는 더 많은 인터넷 검색이 발견 : 내 ViewModel에 직접 결합 및 바인딩을 통해 필요한 값을 얻을 수 있기 때문에 https://stackoverflow.com/a/3668699는,

(가)이 답변 주어진 솔루션에 나를 위해 이제 잘 작동 (업데이트 2 참조) .

+2

ContextMenu와 UserControl이 다른 요소 트리에 있기 때문에 ContextMenu의 MenuItem에서 ElementName = UserControl에 바인딩 할 수 없습니다. Command = "{Binding}"을 사용하여 바인딩 한 MenuItem의 DataContext는 ContextMenu를 열 때 클릭하는 항목입니다. 이것은 현재 선택된 항목과 반드시 ​​같을 필요는 없습니다. – mm8

1
  1. 에서

    감사합니다 } " Command ="{Catel : CommandManagerBinding DoStuffCommand} "

  2. bindin g 컨텍스트가 이고 뷰 모델이 아님을 나타냅니다. 당신이보기 모델에 바인딩하려면 루트 그리드에 이름을 제공해야하고 다음과 같이 바인딩 :

    CommandParameter="{Binding DataContext.SelectedItem, ElementName=rootGrid}" 
    

주를 VM이 내부 내부에 설정되어 있기 때문에 UserControl를 사용하여 작동하지 않는 그리드 (설명을 보려면 문서를 참조하십시오). 그래서 어느 쪽이든을 사용하십시오 UserControl.ViewModel 또는 SomeInnerControl.DataContext

+0

나는''Command = {...}'''''''CommandParameter = {...}''''''''''''''''''''''' 코드를 디버깅했는데''Binding'''-Expression이 제대로 평가되지 않는 것처럼 보입니다. '''MenuItem''의'''Click'''-Event에 대한 뷰의 코드 숨김에 메소드를 추가했으며''CommandParameter'''는 항상 null입니다. 이 코드에서 무엇이 잘못되었는지 전혀 알지 못합니다. – HumpaLumpa007