How do you bind a Button Command to a member metho

2019-07-27 08:13发布

问题:

I have a ListView in my MVVM WPF implementation, it has a DataTemplate with a button inside. The ListView is bound to a collection of complex objects in the ViewModel.

 <ListView ItemsSource="{Binding Path=ComplexObjects}"
          SelectedItem="{Binding Path=SelectedObject}"
          Width="Auto">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="My Property">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Margin="6,2,6,2">
                            <TextBlock Text="{Binding MyProperty}"/>
                        </StackPanel>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
    </GridViewColumn>
            <GridViewColumn Header="First Name">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Margin="6,2,6,2">
                            <Button Command="{Binding ???}"/>
                        </StackPanel>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
    </GridView>
</ListView.View>

All the text fields are bound with no problem, but can I bind the Button Command to a member method of the ComplexObject? If so is there any way to pass parameters?

I have a feeling I'm probably just evading using an ICommand.

Thanks.

回答1:

You could bind an ICommand on the ViewModel, passing the instance to invoke the method on as a parameter. The ViewModel can then call the appropriate method on the right ComplexObject.

For example:

<DataTemplate>
    <StackPanel Margin="6,2,6,2">
        <Button Command="{Binding DoSomethingCommand, RelativeSource={RelativeSource AncestorType={x:Type ViewModelType}, Mode=FindAncestor}" CommandParameter="{Binding}"/>
    </StackPanel>
</DataTemplate>

Then the viewmodel could look like so:

public ICommand DoSomethingCommand
{
    get { return new DelegateCommand<object>(DoSomething); }
}

private void DoSomething(object instance)
{
    var complexObject = instance as ComplexObject;
    if (complexObject != null)
        complexObject.SomeMethod();
}


回答2:

If you really wanted to get crazy I suppose you could make your own button custom control with a dependency property that is a delegate, and you could then bind to a property that returns the same type of delegate. And then in your custom control class you could invoke the delegate when it gets clicked.


There is always the standard ICommand, if you go that route this is how...

<Button Command={Binding CommandProperty} />

Use Kent Boogaart's DelegateCommand class from his blog post. Then...

In the class you are binding to:

private ICommand _commandField;

public ICommand CommandProperty
{
  get
  {
    if (_commandField == null) _commandField = new DelegateCommand(CommandMethod);

    return _commandField;
  }
}

private void CommandMethod() 
{
  // do stuff...
}


回答3:

Yes for Button you will need to use ICommand established in your ComplexObject:

<Button Command="{Binding Path = CommandName}"/>

If your method is in the View Model that holds the ComplexObjects collection name your control or window Me and use something like this:

<Button Command="{Binding ElementName=Me, Path=DataContext.CommandName}" />

You could use click or preview mouse down, but if you're wanting to bind the method in XAML, you would still need to route that event to a command. It's just easier to bind the command.