C# 如何从按钮单击事件中获取返回值?
我刚开始学C。我看到一个老问题,有人试图制造一台可口可乐机,这似乎是一个很好的练习 但我被钱扣卡住了。我不知道如何将一个按钮代表的金额存储在一个变量中,该变量可以通过ColaMachine方法访问 我有以下代码:C# 如何从按钮单击事件中获取返回值?,c#,winforms,C#,Winforms,我刚开始学C。我看到一个老问题,有人试图制造一台可口可乐机,这似乎是一个很好的练习 但我被钱扣卡住了。我不知道如何将一个按钮代表的金额存储在一个变量中,该变量可以通过ColaMachine方法访问 我有以下代码: using System; using System.Windows.Forms; using System.Drawing; namespace QuickSharp { public class ColaMachine : Form { publi
using System;
using System.Windows.Forms;
using System.Drawing;
namespace QuickSharp
{
public class ColaMachine : Form
{
public ColaMachine()
{
this.Text = "Cola Machine";
this.Size = new Size(450 , 500);
//Money & Money Buttons
Label Money;
Money = new Label();
Money.Text = "Insert Coins Here:";
Money.Location = new Point(20, 100);
this.Controls.Add(Money);
Button MoneyButton1;
MoneyButton1 = new Button();
MoneyButton1.Text = "€0,05";
MoneyButton1.Location = new Point(28,125);
MoneyButton1.Click += new System.EventHandler(this.MoneyButton1_Click);
this.Controls.Add(MoneyButton1);
Button MoneyButton2;
MoneyButton2 = new Button();
MoneyButton2.Text = "€0,10";
MoneyButton2.Location = new Point(28,165);
MoneyButton2.Click += new System.EventHandler(this.MoneyButton2_Click);
this.Controls.Add(MoneyButton2);
Button MoneyButton3;
MoneyButton3 = new Button();
MoneyButton3.Text = "€0,20";
MoneyButton3.Location = new Point(28,205);
MoneyButton3.Click += new System.EventHandler(this.MoneyButton3_Click);
this.Controls.Add(MoneyButton3);
Button MoneyButton4;
MoneyButton4 = new Button();
MoneyButton4.Text = "€0,50";
MoneyButton4.Location = new Point(28,245);
MoneyButton4.Click += new System.EventHandler(this.MoneyButton4_Click);
this.Controls.Add(MoneyButton4);
Button MoneyButton5;
MoneyButton5 = new Button();
MoneyButton5.Text = "€1,00";
MoneyButton5.Location = new Point(28,285);
MoneyButton5.Click += new System.EventHandler(this.MoneyButton5_Click);
this.Controls.Add(MoneyButton5);
Button MoneyButton6;
MoneyButton6 = new Button();
MoneyButton6.Text = "€2,00";
MoneyButton6.Location = new Point(28,325);
MoneyButton6.Click += new System.EventHandler(this.MoneyButton6_Click);
this.Controls.Add(MoneyButton6);
// Drinks & Drink Buttons
Label Drinks;
Drinks = new Label();
Drinks.Text = "Choose Your Drink:";
Drinks.Location = new Point(315 , 100);
Drinks.AutoSize = true;
this.Controls.Add(Drinks);
Button DrinkButton1;
DrinkButton1 = new Button();
DrinkButton1.Text = "Coca-Cola";
DrinkButton1.Location = new Point(328,125);
this.Controls.Add(DrinkButton1);
Button DrinkButton2;
DrinkButton2 = new Button();
DrinkButton2.Text = "Coca-Cola Light";
DrinkButton2.Location = new Point(328,165);
this.Controls.Add(DrinkButton2);
Button DrinkButton3;
DrinkButton3 = new Button();
DrinkButton3.Text = "Fanta";
DrinkButton3.Location = new Point(328,205);
this.Controls.Add(DrinkButton3);
Button DrinkButton4;
DrinkButton4 = new Button();
DrinkButton4.Text = "Sprite";
DrinkButton4.Location = new Point(328,245);
this.Controls.Add(DrinkButton4);
Button DrinkButton5;
DrinkButton5 = new Button();
DrinkButton5.Text = "Spa Blauw";
DrinkButton5.Location = new Point(328,285);
this.Controls.Add(DrinkButton5);
Button DrinkButton6;
DrinkButton6 = new Button();
DrinkButton6.Text = "Red Bull";
DrinkButton6.Location = new Point(328,325);
this.Controls.Add(DrinkButton6);
//Header & Machine Display
Label Header;
Header = new Label();
Header.Text = "Coca-Cola Machine";
Header.Font = new Font("Arial" , Header.Font.Size +5);
Header.ForeColor = Color.DarkRed;
Header.Location = new Point(132, 20);
Header.AutoSize = true;
this.Controls.Add(Header);
TextBox TextBox1 ;
TextBox1 = new TextBox();
if(InsertedCoins == 0.00)
TextBox1.Text = "Buy Your Ice Cold Drinks Here!";
else
TextBox1.Text = "Inserted Coins: €" + InsertedCoins;
TextBox1.BackColor = Color.Black;
TextBox1.ForeColor = Color.Red;
TextBox1.Font = new Font("Arial" , TextBox1.Font.Size +3);
TextBox1.ReadOnly = true;
TextBox1.Size = new Size(210,300);
TextBox1.Location = new Point(112,50);
// I tried to get the text scrolling here... :)
TextBox1.SelectionStart = TextBox1.Text.Length;
TextBox1.ScrollToCaret();
TextBox1.Refresh();
this.Controls.Add(TextBox1);
}
public double InsertedCoins;
// Money Button Click Events
private void MoneyButton1_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 0.05;
}
private void MoneyButton2_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 0.10;
}
private void MoneyButton3_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 0.20;
}
private void MoneyButton4_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 0.50;
}
private void MoneyButton5_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 1.00;
}
private void MoneyButton6_Click(object sender, EventArgs e)
{
InsertedCoins = InsertedCoins + 2.00;
}
private static void Main()
{
ColaMachine Scherm;
Scherm = new ColaMachine();
Application.Run(Scherm);
}
}
}
此外,如果您对我的常规编程有任何建议(例如,让其他试图阅读我的代码的人更容易理解),请告诉我 您可以存储每个按钮i按钮标记属性的金额,并在eventhandler中使用以下代码读取金额:
void ValueButton_Click(object sender, EventArgs e)
{
Button button = sender as Button;
if (button == null) return;
if (button.Tag == null) return;
double amount = (double)button.Tag;
// Process the amount here....
InsertedCoins += amount;
}
先想想: 你应该把问题分为两类(类测试和类ColaMachine) 看起来像是:
public class ColaMachine : Form
{
public ColaMachine()
{
...
}
}
public class Test
{
private static void Main()
{
ColaMachine Scherm;
Scherm = new ColaMachine();
Application.Run(Scherm);
}
}
下一个:如果要返回私有的变量,请使用属性。IC将是一个公共方法(属性)。InsertedCoins将是一个私有变量
public double IC
{
get
{
return InsertedCoins;
}
set
{
InsertedCoins = value;
}
}
别忘了,机器有很多状态。你应该使用设计模式,确切地说是状态模式。当我想到一台可乐机时,我看到机器中每种饮料都有一个按钮,但不同金额的饮料没有按钮。也许你的意思是一瓶可乐要50美分,所以按可乐按钮我要收50美分 按钮和事件处理程序 当您按下屏幕上的按钮时,会生成一个单击事件。您需要编写一个方法来响应该单击。我们用来响应事件的任何方法(一般来说)都称为事件处理程序。您必须告诉您的程序哪些按钮与哪些事件处理程序一起使用。我们称之为注册事件处理程序 按照惯例,如果您的按钮名为“CokeButton”,那么与该特定按钮关联的事件处理程序将命名为“CokeButton\u ClickHandler”。或者类似的 一般建议 思考您正在建模的东西,并在代码中定义东西以反映真实世界。模型中的内容通常以类、类属性和类字段结束。这些事情通常会在适当的类中作为方法结束。然后想想这些东西是如何相互作用的 在开始编写代码之前,您不需要了解可乐机的所有信息。你应该一次写一点点,测试它们,然后在你测试过的基础上构建。不要编写大量复杂的代码,然后进行测试。你会在追逐你的尾巴时绕圈子。写一点,测试一点,重复一遍<现在听我说,以后相信我;写一点,测试一点,然后重复。现在和永远都要听从这个建议 下面是我对可乐机的看法。首先是可乐机本身
public class CokeMachine {}
可乐机有一个钱槽、一个回程槽和饮料按钮。我真的不能把钱放进投币口,所以我会说我会在文本框中输入。然后我点击一个按钮,可乐就会自动分配。我觉得我已经定义了足够多的模型,可以开始了。关于可乐机还有很多其他的事情,但我现在不想担心它们
但我需要知道每种饮料的价格。
嗯,好的。然后必须有“CokeCost”、“7UpCost”等字段。所以定义它们吧!我们将在前进的过程中找出如何以及在何处使用它们
public class CokeMachine {
Button Coke;
Button 7Up;
Button RootBeer;
TextBox MoneySlot;
double CokeCost = .75;
double 7UpCost = .65;
}
我说过按钮需要处理程序,所以我们至少可以编写一些代码外壳。我希望他们都会以同样的方式工作,所以我现在将重点放在一个方面。请注意,在编写代码时,我意识到必须处理的其他事情。我会添加注释,调用还不存在的方法,等等
public class CokeMachine {
Button Coke;
Button 7Up;
Button RootBeer;
TextBox MoneySlot;
double CokeCost = .75;
double 7UpCost = .65;
// "wiring up" the coke button click event to it's handler.
// We do this in C# by declaring an new EventHandler object (a .NET framework supplied class)
// and we pass in the name of our method as a parameter.
// This new EventHandler is *added* to the button's click event.
// An event can have multiple handlers, that's why we do "+="
// instead of just "=". Otherwise we would have accidentally "unhooked" any
// previously registered handlers.
Coke.Click += new EventHandler(Coke_ClickHandler);
// this is the .NET event handler method signature.
Public void Coke_ClickHandler (object sender, EventArgs args){
if (MoneySlot.Value >= CokeCost) {
DispenseDrink();
// How do I handle returning change? Maybe DispenseDrink() can do that.
}else {
// tell customer to put in more money
}
}
private void DispenseDrink() {
// An empty method is enough to get it to compile so for now that's fine.
// I need to test the Coke_EventHandler logic that I've written so far.
}
}
现在我需要测试到目前为止我写的东西。之后,我需要决定下一步的重点。但是要意识到,当您在编写依赖于已经编写的代码的新代码时,如果现有代码还没有经过测试——而现在您看到了错误,那么您只会让自己更加困难。您可以在代码更简单的时候进行测试。现在有更多,更复杂,更难调试和修复
建议,第二部分
冒着把事情搞砸的风险,我给出以下我最初的答案:
您可以看到每个饮料按钮都做相同的事情,根据上面的代码,我们将为每个按钮反复编写相同的逻辑。如果有什么需要改变,我们必须在任何地方都改变它
更一般的建议
一种面向对象的编程启发式方法是封装保持不变的程序。您应该始终注意一些地方,这些地方可能是通用代码的候选者
我想强调的是,这种常见的按钮行为对我来说并不是很明显。只有在我写了上面的代码之后,我才开始认为我所有的饮料按钮处理程序看起来都是一样的,我意识到在一台真正的饮料机上,它们的行为确实是一样的。我的编码蜘蛛侠意识告诉我,当代码反映真实事物的可识别行为时,这绝对是一件好事(双关语!)
重构
实际上,这是一个技术术语,意思是对现有代码进行修改,使其更灵活、可重用、可读性更强,总之是可维护的
重构应该一直在你的思维过程中。但要确保你有做出任何改变的正当理由。重塑代码是软件开发中一个正常的、不可分割的部分
让我们通过提取方法进行重构
枚举数
我讨厌像上面用“可乐”那样用字符串。打字错误和大小写(即上/下)可能会导致Visual Studio无法捕捉到的问题。当我有一个有限的物品清单-各种饮料-我真的喜欢使用enumerati
Public void Coke_ClickHandler (object sender, EventArgs args){
PurchaseDrink("Coke", CokeCost);
}
// now we have a method that stands out and says THIS is how it works
// and a single point of change, rather than ump-teen button handlers.
private PurchaseDrink (string whatKind, double cost) {
// all I did so far is move the code and change "Cokecost" to "cost"
// Now I'm beginning to think I may need to pass "whatKind" to
// DispenseDrink() - but first I need to test the changes I've
// made at this level.
// ***** and since I already tested the code when I 1st wrote it,
// this refactoring will be easier & quicker to test.. GET IT??!! ******
if (MoneySlot.Value >= cost) {
DispenseDrink();
// How do I handle returning change? Maybe DispenseDrink() can do that.
}else {
// tell customer to put in more money
}
}
private void DispenseDrink() {
// An empty method is enough to get it to compile so for now that's fine.
// I need to test the Coke_EventHandler logic that I've written so far.
}