将方法绑定到WPF中的按钮

本文关键字:按钮 WPF 方法 绑定 | 更新日期: 2023-09-27 18:28:17

我有这个控制台应用程序,我现在想把它做成一个WPF应用程序。我是WPF的新手,所以我不确定从这里到哪里去。我目前有以下功能来启动服务器:

 public static void StartListening(string[] prefixes)
    {
        HttpListener listener = new HttpListener();
        if (prefixes == null || prefixes.Length == 0)
            throw new ArgumentException("prefixes");
        foreach (string s in prefixes)
        {
            listener.Prefixes.Add("http://" + s + "/");
        }
        listener.Start();
        Console.WriteLine("'nListening...");
        listener.BeginGetContext(new AsyncCallback(OnRequest), listener);
    }

现在我想在WPF中点击一个按钮就可以做到这一点。我的MainWindow.xaml.cs中已经有了以下内容,但我可以使用如何将StartServerButton_Click绑定到我的StartListening()方法的提示。我一直在考虑使用ICommand,但对于这个相当简单的问题,它似乎是一个过于复杂的解决方案。

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        try
        {
            IPAddress[] addrs = Array.FindAll(Dns.GetHostEntry(string.Empty).AddressList,
               a => a.AddressFamily == AddressFamily.InterNetwork);
            ServerOutputTextBox.AppendText("Your IPv4 address is: ");
            foreach (IPAddress addr in addrs)
            {
                ServerOutputTextBox.AppendText(addr.ToString());
            }
            //Automatically set the IP address
            string[] ips = addrs.Select(ip => ip.ToString()).ToArray();
            Response.StartListening(ips);
        }
        catch (Exception e)
        {
            MessageBox.Show(e.Message);
        }
    }

    private void StartServerButton_Click(object sender, RoutedEventArgs e)
    {
    }

将方法绑定到WPF中的按钮

到目前为止,这两个答案都向您展示了如何使用代码隐藏点击事件来启动您的方法,但是,由于您的标题询问了将Button.Command属性绑定到DataContext的问题,我想我应该发布一个关于如何做到这一点的答案。

您确实需要一个ICommand值才能绑定Button.Command。此外,出于绑定目的,您通常想要所谓的RelayCommandDelegateCommand,这只是一种奇特的方式来表示一个能够指向其他地方执行的一些无关代码的命令。

如果您使用的是第三方框架,如Microsoft PRISM或MVVM Light,它们都已经有了专门用于此的类,或者您可以创建自己版本的RelayCommand以用于绑定。

以下是我不想使用第三方库时通常使用的RelayCommand类:

/// <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
{
    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;
    /// <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;
    }
    #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
}

然后,您的DataContext类将公开此RelayCommand的一个实例,该实例将转到用于绑定目的的方法,如以下

public ICommand StartServerCommand
{
    get
    {
        // If command hasn't been created yet, create it
        if (_startServerCommand == null)
        {
            _startServerCommand = new RelayCommand(
                param => StartServer()
            );
        }
        return _startServerCommand;
    }
}
private void StartServer()
{
    var ips = GetIpAddresses();
    Response.StartListening(ips);
}

话虽如此,从您迄今为止给出的代码示例来看,您似乎没有正确利用WPF的绑定系统,因此此解决方案可能不适合您,并且可能更简单地使用其他方法所示的OnClick方法。

在理想的情况下,您的数据和业务逻辑都将存在于与UI无关的类中,这些类用作UI组件后面的DataContext,并且您将使用绑定从数据类中提取数据以在UI中显示。

如果你想了解更多关于如何正确使用WPF的信息,我的博客上有一些初学者文章可能会对你有所帮助:

  • 你所说的"DataContext"是什么
  • 一个简单的MVVM示例

根据您的代码判断,加载窗口后,IP不会更改。因此,将ips设为私有,并在按钮点击处理程序中使用:

public partial class MainWindow : Window {
private string[] ips;
public MainWindow()
{
    InitializeComponent();
    try
    {
        IPAddress[] addrs = Array.FindAll(Dns.GetHostEntry(string.Empty).AddressList,
           a => a.AddressFamily == AddressFamily.InterNetwork);
        ServerOutputTextBox.AppendText("Your IPv4 address is: ");
        foreach (IPAddress addr in addrs)
        {
            ServerOutputTextBox.AppendText(addr.ToString());
        }
        //Automatically set the IP address
        ips = addrs.Select(ip => ip.ToString()).ToArray();
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
}

private void StartServerButton_Click(object sender, RoutedEventArgs e)
{
     Response.StartListening(ips);
}

我不太确定你的问题是否正确。但这就是你想要的吗?

Xaml:

<Button Click=StartServerButton_Click/>

代码背后:

private void StartServerButton_Click(object sender, RoutedEventArgs e)
{
    DoSomething();
}