How to fire event from button inside datagrid in s

2019-04-08 18:40发布

问题:

I have button at first column in datagrid. I am using MVVM and try to bind Command to Command in ViewModel but when I click button in each row, it don't work (It don't call Command in ViewModel) but if I move that button out of datagrid it's working properly.

How can I fire event from button inside datagrid in MVVM?

Update 1:

XAML's code is:

<datagrid:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal" 
                        VerticalAlignment="Center">
            <Button x:Name="button" Content="View" Margin="5" DataContext="{StaticResource XDataContext}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <i:InvokeCommandAction Command="{Binding ViewOrganizationCommand}"
                                                CommandParameter="{Binding ElementName=dtgOrganizations, Path=SelectedItem}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>
    </DataTemplate>
</datagrid:DataGridTemplateColumn.CellTemplate>

ViewModel's code is:

public ViewModelCommand ViewOrganizationCommand { get; set; }

回答1:

Instead of using EventTrigger, why not simply bind to Button.Command directly, like so?

<Button 
    ...other properties...
    Command="{Binding ViewOrganizationsCommand}"
    CommandParameter="{Binding}"/>

That will bind the command, and set the CommandParameter to the DataContext of the Button, which presumably is a good thing to bind the parameter to. If it's not, just bind CommandParameter to something else that helps you uniquely identify the specific row being clicked on.



回答2:

This article brings the solution with DataContextProxy. Applying this solution makes possible to write a button code like Austin Lamb's answer.



回答3:

The command binding using the Event Trigger looks fine (This is how i always do it), But I suspect that your command is never assigned to (You are using Automatic Properties) I usually do it like this:

private ViewModelCommand viewOrganizationCommand;

public ViewModelCommand ViewOrganizationCommand 
      {
         get
         {
            if (viewOrganizationCommand  == null)
               viewOrganizationCommand = new ViewModelCommand(Action, CanDoIt);
            return viewOrganizationCommand;
         }
      }


回答4:

try setting you Button's DataContext to the StackPanel and set the Command and CommandParameter of the Button.

<datagrid:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal" 
                        VerticalAlignment="Center" DataContext="{StaticResource XDataContext}">
            <Button x:Name="button" Content="View" Margin="5" Command="{Binding ViewOrganizationCommand}" CommandParameter="{Binding ElementName=dtgOrganizations, Path=SelectedItem}" >
            </Button>
        </StackPanel>
    </DataTemplate>
</datagrid:DataGridTemplateColumn.CellTemplate>


回答5:

I solved this problem by use EventToCommand behavior in MVVMLight Toolkit



回答6:

Each row of the DataGrid has it's DataContext set to that object. If the ItemSource for the grid is an ObservableCollection, each row's DataContext is the Organization object.

There are two ways to handle this.

  1. Create a wrapping or extension ViewModel that exposes the command. Then the command should fire.Here is some psuedo code.

    public class OrganizationExtensionViewModel
    {
        <summary>
        /// Private currentOrginization property.
        /// </summary>          
        private Organization currentOrginization;
    
        public Organization CurrentOrganization
        {
            get
            {
                return this.currentOrginization;
            }
    
            set
            {
                if (this.currentOrginization != value)
                {
                    this.currentOrginization = value;
                    this.RaisePropertyChanged("CurrentOrganization");
                }
            }
        }
    
        public ViewModelCommand ViewOrganizationCommand { get; set; }
        public OrganizationExtensionViewModel(Organization o)
        {
            this.CurrentOrganization = o;
            this.ViewOrganizationCommand = new ViewModelCommand(this.ViewOrgnaizationClicked);
        }
    }
    
  2. Define the ViewModel in the xaml as a StaticResource and refer to it as the binding path.

... In the grid

<Button x:Name="button" Content="View" Margin="5" Command="{Binding ViewOrganizationCommand, Source={StaticResource viewModel}}" />