简体   繁体   English

在DataGrid mvvm / wpf内的ComboBox上的SelectionChanged的EventToCommand

[英]EventToCommand for SelectionChanged on ComboBox inside of DataGrid mvvm/wpf

How can I catch the Selection Changed event that fires on a ComboBox that is embedded into a DataGridComboBoxColum ? 如何捕获嵌入到DataGridComboBoxColumComboBox上触发的Selection Changed事件? I would like to use MVVM pattern for this so something like a EventToCommmand solution would be nice. 我想为此使用MVVM模式,因此类似EventToCommmand解决方案的东西会很好。

XAML: 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 would like to use something like this but don't know where/how to set it up in this particular case. 我想使用类似的方法,但不知道在这种情况下在哪里/如何设置它。

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

As requested this is my full code for XAML: 根据要求,这是我的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>

and view model: 并查看模型:

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);
        }
    }
}

Using the MVVM pattern you don't handle the SelectionChanged event for the ComboBox element in the view. 使用MVVM模式,您不会处理视图中ComboBox元素的SelectionChanged事件。

Instead you should implement your selection changed logic in the setter of the ViewTemplate property, or in a method that you call from there, that gets set whenever a new item is selected in the ComboBox , .eg: 相反,您应该在ViewTemplate属性的setter或从那里调用的方法中实现选择更改的逻辑,只要在ComboBox选择了一个新项,该逻辑就会被设置,例如:

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

This is one of corner stones of MVVM. 这是MVVM的基础之一。 Whenever the source property gets set by the view, the view model can perform some logic. 只要视图设置了source属性,视图模型就可以执行一些逻辑。 The view only sets a property. 该视图仅设置一个属性。 It doesn't handle any event. 它不处理任何事件。

Edit: If this is not an option for some reason you should replace the DataGridComboBoxColumn with a DataGridTemplateColumn because you cannot apply an EventTrigger to a Style : 编辑:如果这不是出于某种原因,你应该更换一个选项DataGridComboBoxColumnDataGridTemplateColumn ,因为你不能在申请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>

You can add eventhandler to your combobox. 您可以将事件处理程序添加到组合框。 I added to grid's showing event, you can add another event of course. 我已添加到网格的显示事件,您当然可以添加另一个事件。

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);
                }
}}

what i would do is something like this so inside your viewmodel, you will have something like 我会做的是这样的事情,所以在您的viewmodel中,您将拥有类似的东西

Viewmodel.cs 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
    }
}

In your MainWindow.xaml.cs do something like this: 在您的MainWindow.xaml.cs中执行以下操作:

this.DataContext = new ViewModel();

In your ViewModel.xaml file 在您的ViewModel.xaml文件中

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

One important thing is to make sure that your viewmodel.xaml knows where it references from so that it can see where the SelectionChangeCommand is located so it can do the binding. 一件重要的事情是确保viewmodel.xaml知道它从哪里引用,以便可以看到SelectionChangeCommand的位置,以便进行绑定。 FYI, for the relaycommand, my advice is to use the Galasoft.MVVMlight so you don't have to implement relaycommand yourself. 仅供参考,对于中继命令,我的建议是使用Galasoft.MVVMlight,这样您就不必自己实现中继命令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM