Нажатие кнопки привязки к методу - PullRequest
48 голосов
/ 20 августа 2010

У меня есть сетка данных, связанная с наблюдаемой коллекцией объектов.То, что я хочу сделать, - это иметь кнопку, которая будет выполнять метод объекта, представляющего строку кнопки, на которой была нажата кнопка.Итак, теперь у меня есть что-то вроде этого:

            <DataGridTemplateColumn Header="Command">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Button Name="cmdCommand" Click="{Binding Command}" 
                                Content="Command"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

, который не работает и выдает следующую ошибку:

Click = "{Binding Command}" недопустим.«{Binding Command}» не является допустимым именем метода обработчика событий.Допустимы только методы экземпляра в сгенерированном классе или в классе с выделенным кодом.

Я смотрел на привязку команды, но похоже, что это просто закончится переходом к одной внешней команде, а не к объекту, связанному сстрока.У меня это работает, используя обработчик событий в коде, а затем направляет его к элементу, привязанному к выбранной строке (так как строка выбирается при нажатии кнопки), но это кажется плохим способом обработки этого, и я предполагаю, что 'Я просто что-то здесь упускаю.

Ответы [ 5 ]

85 голосов
/ 20 августа 2010

Я делаю это все время. Вот посмотрите на пример и как вы бы это реализовали.

Измените свой XAML, чтобы использовать свойство Command кнопки вместо события Click. Я использую имя SaveCommand, поскольку за ним легче следовать, чем с именем Command.

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

Ваш CustomClass, к которому привязан Button, теперь должен иметь свойство SaveCommand типа ICommand. Он должен указывать на метод в CustomClass, который вы хотите запустить при выполнении команды.

public MyCustomClass
{
    private ICommand _saveCommand;

    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand == null)
            {
                _saveCommand = new RelayCommand(
                    param => this.SaveObject(), 
                    param => this.CanSave()
                );
            }
            return _saveCommand;
        }
    }

    private bool CanSave()
    {
        // Verify command can be executed here
    }

    private void SaveObject()
    {
        // Save command execution logic
    }
}

Приведенный выше код использует RelayCommand, который принимает два параметра: метод для выполнения и значение true / false, если команда может выполняться или нет. Класс RelayCommand представляет собой отдельный файл .cs с кодом, показанным ниже. Я получил это от Джоша Смита :)

/// <summary>
/// A command whose sole purpose is to 
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;        

    #endregion // Fields

    #region Constructors

    /// <summary>
    /// Creates a new command that can always execute.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Creates a new command.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;           
    }

    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameters)
    {
        return _canExecute == null ? true : _canExecute(parameters);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameters)
    {
        _execute(parameters);
    }

    #endregion // ICommand Members
}
26 голосов
/ 20 августа 2010

У вас есть различные возможности.Самый простой и самый уродливый это:

XAML

<Button Name="cmdCommand" Click="Button_Clicked" Content="Command"/> 

Код позади

private void Button_Clicked(object sender, RoutedEventArgs e) { 
    FrameworkElement fe=sender as FrameworkElement;
    ((YourClass)fe.DataContext).DoYourCommand();     
} 

Еще одно решение (лучше) - предоставить свойство ICommand для вашего YourClass.Эта команда уже имеет ссылку на ваш YourClass -объект и поэтому может выполнять действие с этим классом.

XAML

<Button Name="cmdCommand" Command="{Binding YourICommandReturningProperty}" Content="Command"/>

Потому чтово время написания этого ответа было опубликовано много других ответов, я перестаю писать больше.Если вас интересует один из показанных мной способов или вы считаете, что я допустил ошибку, оставьте комментарий.

7 голосов
/ 30 марта 2016

Вот перевод VB.Net ответа Рэйчел выше.

Очевидно, что привязка XAML такая же ...

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

Ваш пользовательский класс будет выглядеть так ...

''' <summary>
''' Retrieves an new or existing RelayCommand.
''' </summary>
''' <returns>[RelayCommand]</returns>
Public ReadOnly Property SaveCommand() As ICommand
    Get
        If _saveCommand Is Nothing Then
            _saveCommand = New RelayCommand(Function(param) SaveObject(), Function(param) CanSave())
        End If
        Return _saveCommand
    End Get
End Property
Private _saveCommand As ICommand

''' <summary>
''' Returns Boolean flag indicating if command can be executed.
''' </summary>
''' <returns>[Boolean]</returns>
Private Function CanSave() As Boolean
    ' Verify command can be executed here.
    Return True
End Function

''' <summary>
''' Code to be run when the command is executed.
''' </summary>
''' <remarks>Converted to a Function in VB.net to avoid the "Expression does not produce a value" error.</remarks>
''' <returns>[Nothing]</returns>
Private Function SaveObject()
    ' Save command execution logic.
   Return Nothing
End Function

И, наконец, класс RelayCommand выглядит следующим образом ...

Public Class RelayCommand : Implements ICommand

ReadOnly _execute As Action(Of Object)
ReadOnly _canExecute As Predicate(Of Object)
Private Event ICommand_CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged

''' <summary>
''' Creates a new command that can always execute.
''' </summary>
''' <param name="execute">The execution logic.</param>
Public Sub New(execute As Action(Of Object))
    Me.New(execute, Nothing)
End Sub

''' <summary>
''' Creates a new command.
''' </summary>
''' <param name="execute">The execution logic.</param>
''' <param name="canExecute">The execution status logic.</param>
Public Sub New(execute As Action(Of Object), canExecute As Predicate(Of Object))
    If execute Is Nothing Then
        Throw New ArgumentNullException("execute")
    End If
    _execute = execute
    _canExecute = canExecute
End Sub

<DebuggerStepThrough>
Public Function CanExecute(parameters As Object) As Boolean Implements ICommand.CanExecute
    Return If(_canExecute Is Nothing, True, _canExecute(parameters))
End Function

Public Custom Event CanExecuteChanged As EventHandler
    AddHandler(ByVal value As EventHandler)
        AddHandler CommandManager.RequerySuggested, value
    End AddHandler
    RemoveHandler(ByVal value As EventHandler)
        RemoveHandler CommandManager.RequerySuggested, value
    End RemoveHandler
    RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
        If (_canExecute IsNot Nothing) Then
            _canExecute.Invoke(sender)
        End If
    End RaiseEvent
End Event

Public Sub Execute(parameters As Object) Implements ICommand.Execute
    _execute(parameters)
End Sub

End Class

Надеюсь, это поможет любому разработчику VB.Net!

1 голос
/ 20 августа 2010

Клик - это событие. В вашем коде вы должны иметь соответствующий обработчик событий для того, что у вас есть в XAML. В этом случае вам потребуется следующее:

private void Command(object sender, RoutedEventArgs e)
{

}

Команды разные. Если вам нужно подключить команду, вы бы использовали свойство Commmand кнопки и использовали бы некоторые предварительно созданные команды или подключили свои собственные через класс CommandManager (я думаю).

0 голосов
/ 27 мая 2013

Еще несколько пояснений к решению, которое уже дала Рэйчел:

"Приложения WPF с шаблоном дизайна Model-View-ViewModel"

от Джоша Смита

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...