2009-12-18 5 views
7

내 응용 프로그램에 메뉴가 있습니다. 예상대로 같은계층 적 데이터 형식의 명령 바인딩

<MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" > 
     <MenuItem.ItemTemplate>      
      <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
             ItemsSource="{Binding Path=ChildrenItems}">       
       <MenuItem Header="{Binding Name}" Command="{Binding RunOperationCommand}" /> 
      </HierarchicalDataTemplate> 
     </MenuItem.ItemTemplate> 
    </MenuItem> 

메뉴가 보이지만, 명령은 각 메뉴 항목에 대한 해고되지 않은 : 나는 계층 적 데이터 템플릿을 사용하여 시각화하고있어! 더군다나 디버거에서 볼 수있는 바운더리가 아닙니다 : ICommand 프로퍼티의 get 접근자가 결코 실행되지 않았습니다. 왜 이렇게됩니까? 평소와 같이 이렇게

완벽하게 작동합니다

<Menu> 
    <MenuItem Header="SomeHeader" Command="{Binding RunOperationCommand}"/> 
<Menu> 

답변

7

제 1 및 제 2의 차이 귀하의 질문에 예를 두 번째 코드 조각에서 당신은 MenuItem.Command에 바인딩됩니다 부모의 데이터 컨텍스트는 RunOperationCommand으로 정의됩니다. HierarchicalDataTemplate이있는 첫 번째 예제에서는 메뉴 항목 인 "로컬"DataContext에 바인딩됩니다. 적절한 속성이 없으므로 바인딩이 실패합니다.

당신은 몇 가지 옵션이 있습니다

  • 하나가 이미 대답했던 것처럼, 명령 속성 메뉴 항목을 확장하는 것입니다;
  • 은 시각적 트리에서 상대 소스에 바인딩됩니다.이 소스 트리는 명령과 함께 데이터 컨텍스트를가집니다.명령이 창문의의 DataContext에 있다고 가정 :

<MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" > 
     <MenuItem.ItemTemplate>      
      <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
             ItemsSource="{Binding Path=ChildrenItems}">       
       <MenuItem Header="{Binding Name}" 
          Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.RunOperationCommand}" 
       /> 
      </HierarchicalDataTemplate> 
     </MenuItem.ItemTemplate> 
    </MenuItem> 

유사한 명령에서 대한
<Window.Resources> 
    <coreView:CommandReference x:Key="RunOperationCommand" 
           Command="{Binding RunOperationCommand}" /> 
</Window.Resources> 

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" > 
     <MenuItem.ItemTemplate>      
      <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
             ItemsSource="{Binding Path=ChildrenItems}">       
       <MenuItem Header="{Binding Name}" 
          Command="{StaticResource RunOperationCommand}" 
       /> 
      </HierarchicalDataTemplate> 
     </MenuItem.ItemTemplate> 
    </MenuItem> 
+0

감사 정적 리소스를 확인 repl 와이. "부모"와 "로컬"데이터 인터페이스에 대한 귀하의 생각에 관해서. 나는 그들이 왜 다른지 이해하지 못한다. 나는 menu와 menuitem이 parent datacontext를 파생해야한다고 생각했다. datacontext가 종속성 속성의 기능 중 하나가 아닌가? –

+0

메뉴와 메뉴 항목에 동일한 데이터 컨텍스트가있는 경우 {Binding Name}은 항상 공통 datacontext의 동일한 속성 Name에 바인딩됩니다. 하지만 Name을 실제 메뉴 항목의 엔터티에 바인딩하려고합니다. 따라서 {RunOperationCommand 바인딩}은 같은 효과를 주며 메뉴 항목에서 RunOperationCommand를 검색합니다. 그것은 당신의 질문에 대답합니까? –

+0

아, 고마워! 나는 그것을있어! –

1

이 문제를 파고 계속합니다. DataTemplate이 다른 MenuItem 내에서 MenuItem을 생성하기 때문에 꽤 좋은 항목이 아니며 클릭 동작에 일부 인공물을 추가하기 때문에 ItemsConttainer Style을 사용하여 다른 방법으로 시도했습니다. link text에 설명되어 있습니다.

<Menu Height="23" DockPanel.Dock="Top" ItemsSource="{Binding ApplicationMenu}" > 
       <Menu.ItemContainerStyle> 
        <Style TargetType="{x:Type MenuItem}"> 
         <Setter Property="Header" Value="{Binding Name}" /> 
         <Setter Property="Command" Value="{Binding RunOperationCommand}"/> 
         <Setter Property="CommandParameter" Value="123"/> 
         <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" /> 
        </Style> 
       </Menu.ItemContainerStyle> 
       <!--<MenuItem />--> 
</Menu> 

나는 ApplicationMenu 내 사용자 정의 RMenuItem 클래스의 관찰 모음이라고 언급 잊어 버린. 이렇게이 방법은 또한 작동한다, 그러나 명령은 일하지 않는다 !!! 그러나 흥미로운 기능 - 메뉴 바인딩을 사용하여 MenuSource를 설정하면 명령 줄 바인딩이 작동하지 않는다는 것을 알았습니다. MenuItems를 정적으로 추가하면 (마지막 줄의 주석 처리 만 제거하면됩니다) - ItemContainerStyle에 정의 된 명령 바인딩이 작동합니다! - ((왜 그렇게 되나요?) 하지만 내 목표는 아닙니다. RouteCommand를 할당 할 수있는 컬렉션을 기반으로 메뉴를 만드는 메커니즘을 만들고 싶습니다 (메뉴 항목에 바로 가기 키가 있음). MVVM 접근 방식을 사용하면 상황이 복잡해집니다 : ViewModel 레이어에 menuitems 콜렉션이 있고 ViewModel에 간단한 ICommands를 사용하는 반면 RoutedCommands는 View의 기능입니다. 그래서 생각을위한 음식이 있습니다 ... -))

1

내 문제의 일부에 대한 해결책을 찾은 것처럼 보입니다. 우리가 각 메뉴 항목에 대해 특정 명령 인스턴스를 작성해야하는 것처럼 보이기 때문에 명령이 바인딩되지 않습니다. 핵심 문제는 모든 menuitem이 동일한 명령을 실행하며 차이점은 명령 매개 변수의 값에만 있다는 것입니다. 그래서 그렇게해야

샘플 메뉴 항목 클래스 :

public class RMyMenuItem 
{ 
    public string Name { get; set; } 

    public string InputGesture { get; set; } 

    public ICommand ItemCommand 
    { get; set; } 

    public List<RMyMenuItem> ChildrenItems { get; set; } 
} 

속성을 뷰 모델에 :

public ObservableCollection<RMyMenuItem> ApplicationMenu 
{ 
    get 
    { 
     //RApplicationMainMenu menu = new RApplicationMainMenu(0); 
     //return new ObservableCollection<RMenuItem>(menu.Items); 
     return new ObservableCollection<RMyMenuItem>() 
     { 
     new RMyMenuItem() 
      { 
       Name = "item1",      
       ItemCommand = new DelegateCommand((param) => RunOperationExecute(param)), 
       ChildrenItems = new List<RMyMenuItem>() 
       { 
     new RMyMenuItem() 
     { 
      Name = "item2", 
      ItemCommand = new DelegateCommand((param) => RunOperationExecute(param)) 
     } 
       } 
      } 
    }; 
    } 

그리고 XAML을 :

<Menu.ItemContainerStyle> 
     <Style TargetType="{x:Type MenuItem}"> 
      <Setter Property="Header" Value="{Binding Name}" /> 
      <Setter Property="MenuItem.Command" Value="{Binding ItemCommand}"/> 
      <Setter Property="MenuItem.CommandParameter" Value="123"/> 
      <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" />      
     </Style> 
    </Menu.ItemContainerStyle> 
}