wpf 绑定按钮点击一个方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3531772/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 22:02:57  来源:igfitidea点击:

Binding Button click to a method

wpf

提问by Mark

I have a datagrid bound to an observable collection of objects. What I want to do is have a button that will execute a method of the object representing the row of the button that was clicked. So what I have now is something like this:

我有一个绑定到可观察对象集合的数据网格。我想要做的是有一个按钮,该按钮将执行表示单击的按钮行的对象的方法。所以我现在拥有的是这样的:

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

Which doesn't work and reports the following error:

哪个不起作用并报告以下错误:

Click="{Binding Command}" is not valid. '{Binding Command}' is not a valid event handler method name. Only instance methods on the generated or code-behind class are valid.

Click="{绑定命令}" 无效。“{Binding Command}”不是有效的事件处理程序方法名称。只有生成或代码隐藏类上的实例方法才有效。

I've looked at command binding but that looks like it would just end up going to a single external command instead of to the object bound to the row. I have it working using an event handler on the code behind and then routing it to the item bound to the selected row (since the row gets selected when the button is clicked) but that seems like poor way of handing this and I assume I'm just missing something here.

我看过命令绑定,但看起来它最终只会转到单个外部命令,而不是绑定到行的对象。我让它在后面的代码上使用事件处理程序工作,然后将其路由到绑定到所选行的项目(因为单击按钮时该行被选中),但这似乎处理这个问题的方式很糟糕,我假设我'我只是在这里遗漏了一些东西。

回答by Rachel

I do this all the time. Here's a look at an example and how you would implement it.

我一直这样做。下面是一个示例以及如何实现它。

Change your XAML to use the Command property of the button instead of the Click event. I am using the name SaveCommand since it is easier to follow then something named Command.

更改 XAML 以使用按钮的 Command 属性而不是 Click 事件。我使用 SaveCommand 这个名字,因为它比名为 Command 的东西更容易理解。

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

Your CustomClass that the Button is bound to now needs to have a property called SaveCommand of type ICommand. It needs to point to the method on the CustomClass that you want to run when the command is executed.

Button 绑定到的 CustomClass 现在需要有一个名为 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
    }
}

The above code uses a RelayCommand which accepts two parameters: the method to execute, and a true/false value of if the command can execute or not. The RelayCommand class is a separate .cs file with the code shown below. I got it from Josh Smith :)

上面的代码使用了一个 RelayCommand,它接受两个参数:要执行的方法,以及命令是否可以执行的真/假值。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
}

回答by HCL

You have various possibilies. The most simple and the most ugly is:

你有各种各样的可能性。最简单也最丑的是:

XAML

XAML

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

Code Behind

背后的代码

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


Another solution (better) is to provide a ICommand-property on your YourClass. This command will have already a reference to your YourClass-object and therefore can execute an action on this class.

另一个解决方案(更好)是在您的YourClass. 这个命令已经有一个对你的YourClass-object的引用,因此可以在这个类上执行一个操作。

XAML

XAML

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


Because during writing this answer, a lot of other answers were posted, I stop writing more. If you are interested in one of the ways I showed or if you think I have made a mistake, make a comment.

因为在写这个答案的过程中,贴了很多其他的答案,我就不多写了。如果您对我展示的其中一种方式感兴趣,或者您认为我犯了一个错误,请发表评论。

回答by Fütemire

Here is the VB.Net rendition of Rachel's answer above.

这是上面 Rachel 回答的 VB.Net 版本。

Obviously the XAML binding is the same...

显然 XAML 绑定是相同的......

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

Your Custom Class would look like this...

你的自定义类看起来像这样......

''' <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

And finally the RelayCommand class is as follows...

最后 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

Hope that helps any VB.Net developers!

希望对任何 VB.Net 开发人员有所帮助!

回答by mdm20

Click is an event. In your code behind, you need to have a corresponding event handler to whatever you have in the XAML. In this case, you would need to have the following:

点击是一个事件。在后面的代码中,您需要有一个对应于 XAML 中任何内容的事件处理程序。在这种情况下,您需要具备以下条件:

private void Command(object sender, RoutedEventArgs e)
{

}

Commands are different. If you need to wire up a command, you'd use the Commmand property of the button and you would either use some pre-built Commands or wire up your own via the CommandManager class (I think).

命令不一样。如果你需要连接一个命令,你会使用按钮的 Commmand 属性,你可以使用一些预先构建的命令或通过 CommandManager 类连接你自己的命令(我认为)。

回答by lampi

Some more explanations to the solution Rachel already gave:

对 Rachel 已经给出的解决方案的更多解释:

"WPF Apps With The Model-View-ViewModel Design Pattern"

“具有模型-视图-视图模型设计模式的 WPF 应用程序”

by Josh Smith

通过乔什史密斯

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

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