2017-02-24 122 views
1

如何捕获嵌入到DataGridComboBoxColum中的ComboBox上的选择更改事件?我想为此使用MVVM模式,所以像EventToCommmand解决方案会很好。DataGrid组合框中的SelectionChanged的EventToCommand mvvm/wpf

XAML:

<DataGridComboBoxColumn Header="ViewTemplate" Width="180" SelectedItemBinding="{Binding ViewTemplate}" DisplayMemberPath="Name"> 
    <DataGridComboBoxColumn.ElementStyle> 
     <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> 
      <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/> 
      <Setter Property="IsReadOnly" Value="True"/> 
     </Style> 
    </DataGridComboBoxColumn.ElementStyle> 
    <DataGridComboBoxColumn.EditingElementStyle> 
     <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> 
      <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/> 
     </Style> 
    </DataGridComboBoxColumn.EditingElementStyle> 
</DataGridComboBoxColumn> 

我想用这样的事情,但不知道在哪里/如何设置它在这种特殊情况下。

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="SelectionChanged"> 
     <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding SelectionChangedCommand}"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

按照要求,这是我的XAML全码:

<UserControl x:Class="GrimshawRibbon.Revit.Views.ViewManager.ViewManagerView" 
      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" 
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:local="clr-namespace:GrimshawRibbon.Revit.Views.ViewManager" 
      xmlns:ex="clr-namespace:GrimshawRibbon.Revit.Wpf.Extensions" 
      xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" 
      xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="500"> 
    <UserControl.Resources> 
     <ResourceDictionary> 
      <ResourceDictionary.MergedDictionaries> 
       <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" /> 
       <ResourceDictionary Source="pack://application:,,,/GrimshawRibbon;component/Revit/Wpf/Style/GrimshawTheme.xaml"/> 
      </ResourceDictionary.MergedDictionaries> 
     </ResourceDictionary> 
    </UserControl.Resources> 
    <Grid> 
     <ex:DataGridEx x:Name="dgViews" 
           Style="{StaticResource AzureDataGrid}" 
           Margin="10" 
           AutoGenerateColumns="False" 
           ItemsSource="{Binding Views, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
           CanUserAddRows="False" 
           IsReadOnly="False" 
           SelectionMode="Extended" 
           SelectionUnit="FullRow" 
           SelectedItemsList="{Binding SelectedViews, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"> 
      <i:Interaction.Triggers> 
       <i:EventTrigger EventName="CellEditEnding"> 
        <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding CellEditEndingCommand}"/> 
       </i:EventTrigger> 
      </i:Interaction.Triggers> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/> 
       <DataGridTextColumn Header="ViewType" Binding="{Binding ViewType}" Width="100" IsReadOnly="True"/> 
       <DataGridTextColumn Header="ViewGroup" Binding="{Binding ViewGroup, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="130" IsReadOnly="False"/> 
       <DataGridTextColumn Header="ViewSubGroup" Binding="{Binding ViewSubGroup, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="130" IsReadOnly="False"/> 
       <DataGridCheckBoxColumn ElementStyle="{DynamicResource MetroDataGridCheckBox}" 
             EditingElementStyle="{DynamicResource MetroDataGridCheckBox}" 
             Header="OnSheet" 
             Binding="{Binding OnSheet, Mode=TwoWay}" 
             IsReadOnly="True" 
             Width="80"> 
       </DataGridCheckBoxColumn> 
       <DataGridComboBoxColumn Header="ViewTemplate" Width="180" SelectedItemBinding="{Binding ViewTemplate}" DisplayMemberPath="Name"> 
        <i:Interaction.Triggers> 
         <i:EventTrigger EventName="SelectionChanged"> 
          <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding DataContext.SelectChangeCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"/> 
         </i:EventTrigger> 
        </i:Interaction.Triggers> 
        <DataGridComboBoxColumn.ElementStyle> 
         <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> 
          <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/> 
          <Setter Property="IsReadOnly" Value="True"/> 
         </Style> 
        </DataGridComboBoxColumn.ElementStyle> 
        <DataGridComboBoxColumn.EditingElementStyle> 
         <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}"> 
          <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/> 
         </Style> 
        </DataGridComboBoxColumn.EditingElementStyle> 
       </DataGridComboBoxColumn> 
      </DataGrid.Columns> 
     </ex:DataGridEx> 
    </Grid> 
</UserControl> 

和视图模型:

public class ViewManagerViewModel : ViewModelBaseEx 
{ 
    public ViewManagerModel Model; 
    public ObservableCollection<ViewWrapper> Views { get; private set; } 
    public ObservableCollection<ViewWrapper> ViewTemplates { get; private set; } 
    public IList SelectedViews { get; set; } 
    public RelayCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand { get; set; } 
    public RelayCommand<SelectionChangedEventArgs> SelectChangeCommand { get; set; } 

    public ViewManagerViewModel(Document doc) 
    { 
     Model = new ViewManagerModel(doc); 
     Views = Model.CollectViews(); 
     ViewTemplates = Model.CollectViewTemplates(); 
     CellEditEndingCommand = new RelayCommand<DataGridCellEditEndingEventArgs>(args => OnCellEditEnding(args)); 
     SelectChangeCommand = new RelayCommand<SelectionChangedEventArgs>(args => OnSelectionChanged(args)); 
    } 

    private void OnSelectionChanged(SelectionChangedEventArgs e) 
    { 
     // do something 
    } 

    /// <summary> 
    /// Logic for handling cell editing events. 
    /// </summary> 
    /// <param name="e">DataGrid Row object.</param> 
    private void OnCellEditEnding(DataGridCellEditEndingEventArgs e) 
    { 
     var wrapper = e.Row.Item as ViewWrapper; 
     switch (e.Column.SortMemberPath) 
     { 
      case "Name": 
       Model.ChangeName(wrapper); 
       break; 
      case "ViewGroup": 
       Model.SetParameter(wrapper, "View Group", wrapper.ViewGroup); 
       break; 
      case "ViewSubGroup": 
       Model.SetParameter(wrapper, "View Sub Group", wrapper.ViewSubGroup); 
       break; 
      default: 
       break; 
     } 
    } 

    public override void Apply() 
    { 
     var vw = new List<ViewWrapper>(); 
     foreach (ViewWrapper v in SelectedViews) 
     { 
      vw.Add(v); 
     } 

     Model.Delete(vw); 

     // update collection so that rows get deleted in datagrid 
     foreach (ViewWrapper i in vw) 
     { 
      Views.Remove(i); 
     } 
    } 
} 

回答

2

使用MVVM模式,您不会在视图中处理ComboBox元素的SelectionChanged事件。

相反,你应该实现你的选择在ViewTemplate setter方法改变逻辑,或者你从那里调用的方法,每当一个新的项目在ComboBox选择时设置,.eg:

private ViewWrapper _viewTemplate; 
public ViewWrapper ViewTemplate 
{ 
    get { return _viewTemplate; } 
    set { _viewTemplate = value; SelectionChanged(); } 
} 

这是MVVM的一个角落石头。只要源视图属性被视图设置,视图模型就可以执行一些逻辑。该视图只设置一个属性。它不处理任何事件。

编辑:如果这不是出于某种原因的选项,你应该有一个DataGridTemplateColumn更换DataGridComboBoxColumn,因为你不能套用EventTriggerStyle

<DataGridTemplateColumn Header="ViewTemplate" Width="180"> 
    <DataGridTemplateColumn.CellTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding ViewTemplate.Name}" /> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellTemplate> 
    <DataGridTemplateColumn.CellEditingTemplate> 
     <DataTemplate> 
      <ComboBox ItemsSource="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}" 
             SelectedItem="{Binding ViewTemplate}" 
             DisplayMemberPath="Name"> 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="SelectionChanged"> 
         <cmd:EventToCommand PassEventArgsToCommand="True" 
                  Command="{Binding DataContext.SelectionChangedCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"/> 
        </i:EventTrigger> 
       </i:Interaction.Triggers> 
      </ComboBox> 
     </DataTemplate> 
    </DataGridTemplateColumn.CellEditingTemplate> 
</DataGridTemplateColumn> 
+0

嗯,我不想在视图中处理它。我试图在视图中设置绑定,以便它可以在视图模型中触发适当的命令。这可以吗? – konrad

+0

不需要。关键是你不应该使用EventTrigger来调用一个命令。您应该在源属性(ViewTemplate)的setter中调用该命令,因为当ComboBox中的选择更改时,该属性将被设置。 – mm8

+0

但是'ViewWrapper'类在多个视图模型之间共享。如果我用事件硬连线,那么它在其他视图模型中对我无用。我宁愿在视图中包含这个特定的视图功能。为什么使用'Triggers'不是一个好的MVVM练习? – konrad

0

您可以添加事件处理程序到您的组合框。我添加到网格的展示活动中,您当然可以添加其他活动。

private void Grid1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) 
{ 
    ComboBox cb = e.Control as ComboBox; 
       if (cb!=null) 
       { cb.SelectionChangeCommitted -= new EventHandler(cb_SelectedIndexChanged); 

        // now attach the event handler 
        cb.SelectionChangeCommitted += new EventHandler(cb_SelectedIndexChanged); 
       } 
}} 
0

什么,我会做的是这样的事情 让你的视图模型里面,你将有类似

Viewmodel.cs

public class ViewModel 
{ 
    public ViewModel() 
{ 
      _selectChangeCommand= new RelayCommand(OnSelectChange, CanSelectChange); 

} 
    private RelayCommand _selectChangeCommand; 
    public ICommand SelectChangeCommand { get { return _selectChangeCommand; } } 
    private bool CanSelectChange() 
    { 
     return true; 
    } 

    private void OnSelectChange() 
    { 
     ..//do something in here when you change something in your combo box 
    } 
} 

在你MainWindow.xaml.cs 做些什么像这样:

this.DataContext = new ViewModel(); 

在你的ViewModel.xa毫升文件

<ComboBox....> 
    <i:Interaction.Triggers> 
     <i:EventTrigger EventName="SelectionChanged"> 
      <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding SelectChangeCommand }"/> 
     </i:EventTrigger> 
    </i:Interaction.Triggers> 
</ComboBox> 

一个重要的事情是要确保你的viewmodel.xaml知道哪里来的,以便它可以看到那里的SelectionChangeCommand的定位,所以它可以做绑定引用。仅供参考,对于继电器命令,我的建议是使用Galasoft.MVVMlight,因此您不必自己实施继电器命令。

+0

所以,这是我当时的做法寻找,但不幸的是,它不会触发我的命令。还有什么我需要在这里做的? – konrad

+0

发布你的代码,我会看看它!我可以建议你做的一件事是看看输出窗口,并寻找命令名称... visual studio上的输出窗口会告诉你到底为什么你的命令不会触发 – user7583356

+0

我发布了ViewModel的完整代码和查看。谢谢你的帮助! – konrad