2011-03-05 4 views
13

잠재적으로 많은 행을 가질 수있는 DataGrid가 있습니다. 사용자가 행 중 하나를 마우스 오른쪽 버튼으로 클릭 할 때마다 각 행에 대한 컨텍스트 메뉴를 표시하고 사용자가 옵션을 클릭 할 때 작업 (동일한 동작이지만 현재 선택된 행에 따라 다른 데이터 항목)을 수행해야합니다.DataGrid 행에 대한 컨텍스트 메뉴 만들기

가장 적합한 전략은 무엇입니까?

ContextMenuOpening 이벤트를 사용하여 메뉴를 만들지 만 각 행의 ContextMenu가 과도하다고 두려워합니다. 일종의 "게으른로드"컨텍스트 메뉴입니다. DataGrid에 하나의 ContextMenu 만 사용해야합니까? 하지만 이걸로 나는 올바른 이벤트를 결정하는 것과 같은 더 많은 작업을 할 것입니다.

답변

29

내가 아는 한, 일부 동작은 행에 따라 비활성화되거나 활성화되므로 아무 것도 없습니다. 하나의 ContextMenuDataGrid을 입력하십시오.

행 수준의 상황에 맞는 메뉴가 있습니다.

<UserControl.Resources> 
    <ContextMenu x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 
     <MenuItem Header="Edit" Command="{Binding EditCommand}"/> 
    </ContextMenu> 
    <Style x:Key="DefaultRowStyle" TargetType="{x:Type DataGridRow}"> 
     <Setter Property="ContextMenu" Value="{StaticResource RowMenu}" /> 
    </Style> 
</UserControl.Resources> 

<DataGrid RowStyle="{StaticResource DefaultRowStyle}"/> 

DataGrid

는 명령보기 모델의 목록에 바인딩이 있어야 컨텍스트 메뉴가 UserControl의 자원 수집에 생성됩니다

public class ItemModel 
{ 
    public ItemModel() 
    { 
     this.EditCommand = new SimpleCommand 
     { 
      ExecuteDelegate = _ => MessageBox.Show("Execute"), 
      CanExecuteDelegate = _ => this.Id == 1 
     }; 
    } 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public ICommand EditCommand { get; set; } 
} 

을 나는 단 하나의 객체가 생각하는 값이 아닌 참조에 의해 DataGrid 행과 연결됩니다.

안에 Command에 대한 ContextMenu의 또 다른 예가 있습니다.

<ContextMenu x:Key="RowMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 
     <MenuItem Header="Edit" CommandParameter="{Binding}" 
        Command="{Binding DataContext.DataGridActionCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" /> 
    </ContextMenu> 

모델 :

public class MainViewModel 
{ 
    public MainViewModel() 
    { 
     this.DataGridActionCommand = new DelegateCommand<ItemModel>(m => MessageBox.Show(m.Title), m => m != null && m.Id != 2); 
    } 

    public DelegateCommand<ItemModel> DataGridActionCommand { get; set; } 
    public List<ItemModel> Items { get; set; } 
} 

public class ItemModel 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
} 

그러나 문제가 MenuItem ISN이 '가 나는 DataGrid 또한 CommandParameter 속성은 Command 속성 앞에 위치해야 DataContext으로 올바른 뷰 모델을 가지고 있다고 가정 CanExecute이 false를 반환하면 비활성화 된 항목으로 표시됩니다. 가능한 해결 방법은 ItemModel 안에 ParentModel 속성을 사용하는 것이지만 첫 번째 해결 방법과 크게 다르지 않습니다.

public class ItemModel 
{ 
    public int Id { get; set; } 
    public string Title { get; set; } 
    public MainViewModel ParentViewModel { get; set; } 
} 

//Somewhere in the code-behind, create the main view model 
//and force child items to use this model as a parent model 
var mainModel = new MainViewModel { Items = items.Select(item => new ItemViewModel(item, mainModel)).ToList()}; 

그리고 MenuItem의 XAML에서이 더 간단 할 것이다 :

<MenuItem Header="Edit" CommandParameter="{Binding}" 
       Command="{Binding ParentViewModel.DataGridActionCommand}" /> 
+0

덕분에 샘플을 위해, 나는 그것을 시도 줄거야 여기 는 전술 한 솔루션의 예입니다. 하지만, 당신과 마찬가지로, 같은 의심의 여지가 있습니다, 단 하나의 컨텍스트 메뉴 객체가 있습니까? 나는 이것을 파헤쳐 야 할 것이다. – Jay

+0

나는 이것을 테스트하고 각 행의 ContextMenus의 해시 코드를 비교하여 동일한 값을 제공하므로 동일한 객체 여야합니다. 멋지다! 각 행에 대해 실제로 명령이 필요한가요? 기본 ViewModel 내부에있는 상위 명령과 같이 사용하고 싶었습니다. MenuItem에서 명령 바인딩을 조정하면됩니다. 나는 그것을 작동시킬 수 없다! 젠장 ... – Jay

+0

@Jay 정적 RoutedCommand를 의미합니까? 실제로 행 수준 명령 대신 이벤트 처리기 또는 전역 명령을 사용할 수 있습니다. 내일 비슷한 것을 구현하려고합니다. 질문에 명령 코드를 추가하면 도움이 될 것입니다. – vorrtex