C# 如何通过C中的事件处理程序传回类的实例#

C# 如何通过C中的事件处理程序传回类的实例#,c#,winforms,C#,Winforms,所以我只是想弄清楚事件处理程序是如何工作的 我有一个WinForms应用程序,它在主窗体上有一个面板控件。我用一个登录页面填充面板。登录页面将在数据库中搜索用户,并在用户单击登录按钮时检查密码是否正确。如果登录详细信息正确,则会触发事件处理程序,告知主窗体登录成功。然后,它应该将用户详细信息存储在主窗体中,以备面板填充下一个控件时使用。当用户登录时,它会创建一个名为user的类的实例。如何将该用户传递回主窗体,以便它知道当前登录的用户 我希望这是有道理的 这是在ctrl中: public par

所以我只是想弄清楚事件处理程序是如何工作的

我有一个WinForms应用程序,它在主窗体上有一个面板控件。我用一个登录页面填充面板。登录页面将在数据库中搜索用户,并在用户单击登录按钮时检查密码是否正确。如果登录详细信息正确,则会触发事件处理程序,告知主窗体登录成功。然后,它应该将用户详细信息存储在主窗体中,以备面板填充下一个控件时使用。当用户登录时,它会创建一个名为user的类的实例。如何将该用户传递回主窗体,以便它知道当前登录的用户

我希望这是有道理的

这是在ctrl中:

public partial class ctrlLoginPage : UserControl
{
    public event EventHandler RegisterButtonClicked;
    public event EventHandler LoginButtonClicked;
    public User activeUser = new User();
    public ctrlLoginPage()
    {
        InitializeComponent();
    }

    private void btnRegister_Click(object sender, EventArgs e)
    {
        RegisterButtonClicked(this, e);
    }

    public void btnLogon_Click(object sender, EventArgs e)
    {
        SqlConnection con = new SqlConnection();
        con.ConnectionString = "server=DESKTOP-05NVBR2\\SQLEXPRESS;database=GymAppPrototype;UID=sa;password=Mabg123";
        con.Open();

        SqlDataReader dataReader = null;
        SqlCommand myCommand = new SqlCommand("select * from Customer where Email ='" + txtEmail.Text + "';", con);
        dataReader = myCommand.ExecuteReader();
        while (dataReader.Read())
        {
            activeUser.forename = dataReader["Forename"].ToString();
            activeUser.surname = dataReader["Surname"].ToString();
            activeUser.email = dataReader["Email"].ToString();
            activeUser.password = dataReader["Password"].ToString();
            activeUser.mobile = dataReader["MobileNumber"].ToString();
        }
        con.Close();
        if (txtPassword.Text == activeUser.password)
        {
            MessageBox.Show("Login Successful");
            LoginButtonClicked(this, e);
        }
        else
        {
            MessageBox.Show("Login Failed");
        }
        
    }
   
}

这完全取决于您设计类及其集成的方式,但鉴于上面的示例,您可以使用自定义EventArgs或更好的自定义EventHandler

不要将“e”传递给“LoginButtonClicked”事件。而是使用包含登录用户数据的自定义事件args类。为此,您需要为事件处理程序定义一个有点不同的选项卡:

event EventHandler<MyEventArgs> LoginButtonClicked;
现在可以传递新类的新实例,而不是“e”:

LoginButtonClicked(this, new MyEventArgs(activeUser));
然后,事件的订阅者可以使用e.ActiveUser访问登录的用户信息,例如:

myLoginPanel.LoginButtonClicked += (s, e) => { /* do something with e.ActiveUser */ };

虽然在应用程序中完全可以使用标准的基于事件的消息传递,但我怀疑在这里是否有必要。根据您的工作流,在用户登录/注册或取消之前,最简单的方法可能是显示不同的表单和块:

//MainForm
public void GetUser()
{
    using var userWindow = new UserForm();
    if (userWindow.ShowDialog(this) == DialogResult.OK)
    {
        return userWindow.SelectedUser;
    }

    return null;
}

“事件处理程序”是什么样子的?不要讲你的代码,展示你的代码。好的,我刚刚添加了代码。通常,你有一个用于在实体(包括表单)之间传递消息的。您可以找到一个实现。但是,您的设计有一个严重的缺陷-数据库凭据存储在应用程序中。这意味着用户可以反编译您的应用程序,提取连接字符串,然后直接连接到您的数据库并检索用户和密码。谢谢Wiktor,是的,我知道这一点。这只是一个原型应用程序,数据库中添加了虚拟用户。什么构建了正确的数据安全性和应用程序的总体设计将被更彻底地考虑。你永远不应该调用
LoginButtonClicked(这是新的MyEventArgs(activeUser))直接,因为这容易出现多线程问题!使用一个助手方法,首先复制,然后调用委托,如右图所示,而且LoginButtonClicked也可能为null,因此在调用它之前必须检查它是否为null。也就是说,Joe说它是一个原型,所以可能足以完成任务。您应该像这样调用事件:
LoginButtonClicked?.invoke(这个,新的MyEventArgs(activeUser))
//MainForm
public void GetUser()
{
    using var userWindow = new UserForm();
    if (userWindow.ShowDialog(this) == DialogResult.OK)
    {
        return userWindow.SelectedUser;
    }

    return null;
}
//UserForm
public class UserForm : Form
{
    public User SelectedUser { get; private set; }

    private void btnRegister_Click(object sender, EventArgs e)
    {
        SelectedUser = // registration logic

        DialogResult = DialogResult.OK;

        Close();
    }

    private void btnLogon_Click(object sender, EventArgs e)
    {
        SelectedUser = // logon logic

        DialogResult = DialogResult.OK;

        Close();
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        DialogResult = DialogResult.Cancel;

        Close();
    }
}