XO game using c# and ASP.NET - c#

i'm new to C# (and programming at all) and i'm trying to write an 'XO' game along with ASP.NET
i'm getting a problem after the first player clicks a button.
turns doesn't switch and any click after the 1st does nothing. what is wrong with my code ?
public partial class GamePage : System.Web.UI.Page
{
Player player1 = new Player();
Player player2 = new Player();
int turn;
protected void Page_Load(object sender, EventArgs e)
{
this.turn = 0;
if (!IsPostBack)
{
Label1.Visible = true;
}
if (turn == 0)
{
Label1.Text = (Session["player1"] as Player).getname();
}
else
{
Label1.Text = (Session["player2"] as Player).getname();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Session["p1"] = player1;
Session["p2"] = player2;
player1.setsymbol("X");
player2.setsymbol("O");
if (Button1.Text == "")
{
if (turn == 0)
{
Button1.Text = player1.getsymbol();
Label1.Text = (Session["player2"] as Player).getname();
turn = 1;
}
else
{
Button1.Text = player2.getsymbol();
Label1.Text = (Session["player1"] as Player).getname();
turn = 0;
}
}
}
protected void Button2_Click(object sender, EventArgs e)
{
if (Button2.Text == "")
{
if (turn == 0)
{
Button2.Text = player1.getsymbol();
Label1.Text = (Session["player2"] as Player).getname();
turn = 1;
}
else
{
Button2.Text = player2.getsymbol();
Label1.Text = (Session["player1"] as Player).getname();
turn = 0;
}
}
}
protected void Button3_Click(object sender, EventArgs e)
{
if (Button3.Text == "")
{
if (turn == 0)
{
Button3.Text = player1.getsymbol();
Label1.Text = (Session["player2"] as Player).getname();
turn = 1;
}
else
{
Button3.Text = player2.getsymbol();
Label1.Text = (Session["player1"] as Player).getname();
turn = 0;
}
}
}
// this is an example - i have the same lines from button1 to 9

Everytime page renders, you set turn to 0 in Page_Load. Because Page_Load is executed upon every page load, you won't get any other value and this is probably the major issue here.
To properly support the lifetime of such variables that should keep value upon consecutive requests, wrap them in simple property:
public int turn
{
get
{
if ( Session["turn"] != null )
return (int)Session["turn"];
return 0; // default value if not set before
}
set
{
Session["turn"] = value;
}
}
This way everytime you refer to turn in your code, setting it to 0 or 1 or comparing the value to 0 or 1, you will refer to the same value, possibly stored during previous request(s).

this.turn=0; should be executed only when IsPostBack is false. Move this line inside if in your Page_Load.

Related

return to main after paying

i have POS system to fastfood, created by c# and sql server.
after the payment process show me window "Order Successfully Paid" after clicking to ok return to form ProductsReceiptPreview again,
i want after payment process go to the form main.
this is my code.......
private void lblPayments_Click(object sender, EventArgs e)
{
if (pnlPayments.Height != lbl.Height)
{
pnlPayments.Height = lbl.Height;
btnDone.Text = "DONE";
lbl.Text = "RECEIPT";
btnDone.Image = Resources.done;
Data.Show();
}
else
{
pnlPayments.Height = 394;
btnDone.Text = "RECEIPT";
lbl.Text = "AMOUNT";
btnDone.Image = Resources.receipt;
Data.Hide();
}
}
private void Touch_Click(object sender, EventArgs e)
{
var btn = (Button)sender;
txtCashReceived.Text += btn.Text;
}
private void btnClear_Click(object sender, EventArgs e)
{
if(txtCashReceived.Text.Length >0) txtCashReceived.Text =
txtCashReceived.Text.Remove(txtCashReceived.Text.Length - 1);
}
double totalBill = 0;
private void btnPay_Click(object sender, EventArgs e)
{
if (txtCashReceived.Text.Length > 0 && totalBill <=
Convert.ToInt32(txtCashReceived.Text) && Data.RowCount > 0)
{
int i = 0;
foreach (var rep in ListReports)
{
i++;
var report = new ModelReports();
report.Productname = rep.Productname;
report.TotalSales = rep.TotalSales;
report.TotalTransactions = rep.TotalTransactions;
report.Save();
}
var rpd = new ProductsReceiptPreview(dataReceiptBindingSource,
txtTotal.Text, txtCashReceived.Text, txtChange.Text);
rpd.ShowDialog();
if (i == ListReports.Count)
{
MessageBox.Show("Order Successfully Paid");
}
pnlProducts.Controls.Clear();
pnlCategoryPanel.Visible = false;
dataReceiptBindingSource.Clear();
LoadTables();
btnDone.PerformClick();
}
else
{
MessageBox.Show("Please pay your order.");
txtCashReceived.Text = "0";
}
}
private void btnPay_Click_1(object sender, EventArgs e)
{
if (txtCashReceived.Text.Length > 0 && totalBill <=
Convert.ToInt32(txtCashReceived.Text) && Data.RowCount > 0)
{
int i = 0;
foreach (var rep in ListReports)
{
i++;
var report = new ModelReports();
report.Productname = rep.Productname;
report.TotalSales = rep.TotalSales;
report.TotalTransactions = rep.TotalTransactions;
report.Save();
}
if (i == ListReports.Count)
{
MessageBox.Show("Order Successfully Paid");
txtCashReceived.Text = "0";
}
pnlProducts.Controls.Clear();
pnlCategoryPanel.Visible = false;
dataReceiptBindingSource.Clear();
LoadTables();
btnDone.PerformClick();
}
else
{
MessageBox.Show("Please pay your order.");
}
}
If you call some code from main then it will return to main when the call is finished. In the case of a Form, it's handled on a different thread started from main. The thread will never return back to main in this context. If you are using a click event to do some action and want to call some other code when that happens, then you need to re-design your infrastructure. Look into SOLID development principles and dependency injection.
https://www.codeproject.com/Tips/1033646/SOLID-Principle-with-Csharp-Example
https://simpleinjector.readthedocs.io/en/latest/windowsformsintegration.html

I have a glitch in my program which keeps opening a specific form over and over again after the form is hidden

I am an AS Software Development student and I have made an Electronics Quiz for my CA. I have come across a glitch which I cannot seem to fix. It has started to bug me and I can't think of what is wrong. My teacher also cannot see what is wrong. Everything else is working. Here is the code:
namespace MyQuiz2
{
public partial class DragDropYear8_Question1 : Form
{
public DragDropYear8_Question1(string name, int quizSelection)
{
InitializeComponent();
CenterToScreen();
setupQuestion();
}
private void setupQuestion()
{
AllowDropping();
ScoreLbl.Text = "Score: " + StartScreen.Player.Score;
LEDImg.Visible = true;
ResistorImg.Visible = true;
VairiableResistorImg.Visible = true;
timer1.Interval = 1000;
timer1.Start();
if (_time1 == 0)
{
ShowNextQuestion();
}
}
//variable decleration
private int _time1 = 15;
private int _correctAnswers = 0;
//Set up timer
private void timer1_Tick(object sender, EventArgs e)
{
_time1--;
TimerLbl.Text = "Time: " + _time1;
}
//Question setup
private void ShowNextQuestion()
{
_time1 = 0;
Hide();
new DragDropYear8_Question2(StartScreen.Player.Username, 10).Show();
}
private void AllowDropping()//allows the label to be dropped onto a picture box.
{
VairiableResistorImg.AllowDrop = true;
ResistorImg.AllowDrop = true;
LEDImg.AllowDrop = true;
}
//Tells the program that a label has been grabbed
private void LabelGrabbed(object sender, MouseEventArgs e)
{
Label selectedLabel = (Label)sender;
selectedLabel.DoDragDrop(selectedLabel.Text, DragDropEffects.Copy);
}
//allows the label to be droped onto the PictureBox
private void AllowDragDropCopy(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
private void UpdateScoreAndLabelWhenCorrect()//updates all labels on the current form if the answers are correct
{
_correctAnswers++;
StartScreen.Player.IncreaseScore();
ScoreLbl.Text = "Score: " + StartScreen.Player.Score;
if (_correctAnswers == 3)
{
ShowNextQuestion();
}
}
private void UpdateScoreAndLabelWhenWrong()//updates all labels on the current form if the answers are incorrect
{
_correctAnswers++;
ScoreLbl.Text = "Score: " + StartScreen.Player.Score;
if (_correctAnswers == 3)
{
ShowNextQuestion();
}
}
//checks if the right label has been dropped onto the correct picture box
private void VairiableResistorDragDrop(object sender, DragEventArgs e)
{
string result = (string)e.Data.GetData(DataFormats.Text);
/*if the correct label is droped then the score and labels
will be updated and that label and picture box will hide*/
if (result == "Vairiable Resistor")//checks for right answer
{
UpdateScoreAndLabelWhenCorrect();
VairiableResistorImg.Visible = false;
VairiableResistorLbl.Visible = false;
}
//if the anser is wrong then it will hide the picture box and the dragged label
else if (result == "Resistor")
{
UpdateScoreAndLabelWhenWrong();
ResistorLbl.Visible = false;
VairiableResistorImg.Visible = false;
}
else if (result == "Light Emmiting Diode")
{
UpdateScoreAndLabelWhenWrong();
LEDLbl.Visible = false;
VairiableResistorImg.Visible = false;
}
}
private void LEDDragDrop(object sender, DragEventArgs e)
{
string result = (string)e.Data.GetData(DataFormats.Text);
/*if the correct label is droped then the score and labels
will be updated and that label and picture box will hide*/
if (result == "Light Emmiting Diode")//checks for right answer
{
UpdateScoreAndLabelWhenCorrect();
LEDImg.Visible = false;
LEDLbl.Visible = false;
}
//if the anser is wrong then it will hide the picture box and the dragged label
else if (result == "Resistor")
{
UpdateScoreAndLabelWhenWrong();
ResistorLbl.Visible = false;
LEDImg.Visible = false;
}
else if (result == "Vairiable Resistor")
{
UpdateScoreAndLabelWhenWrong();
LEDImg.Visible = false;
VairiableResistorLbl.Visible = false;
}
}
private void ResistorDragDrop(object sender, DragEventArgs e)
{
string result = (string)e.Data.GetData(DataFormats.Text);
/*if the correct label is droped then the score and labels
will be updated and that label and picture box will hide*/
if (result == "Resistor")//checks for right answer
{
UpdateScoreAndLabelWhenCorrect();
ResistorImg.Visible = false;
ResistorLbl.Visible = false;
}
//if the anser is wrong then it will hide the picture box and the dragged label
else if (result == "Light Emmiting Diode")
{
UpdateScoreAndLabelWhenWrong();
ResistorImg.Visible = false;
LEDLbl.Visible = false;
}
else if (result == "Vairiable Resistor")
{
UpdateScoreAndLabelWhenWrong();
ResistorImg.Visible = false;
VairiableResistorLbl.Visible = false;
}
}
}`
The problem is that when I change from the first dragdrop question to the second dragdrop question. Randomly during the second form, the first dragdrop question form will open. It does this the hole way through the quiz. Latter on in the quiz the game loadscreen also does this. The code is as follows:
namespace MyQuiz2
{
public partial class GameLoading : Form
{
public GameLoading()
{
InitializeComponent();
CenterToScreen();
timer1.Start();
}
//Timer and Progressbar setup
private void timer1_Tick(object sender, EventArgs e)
{
//randome number generator for ProgressBar increments
Random random = new Random();
int Increment = random.Next(10, 20);
Random random2 = new Random();
int _Increment = random2.Next(1, 5);
timer1.Interval = 1000;
if (progressBar1.Value <= 80)
{
progressBar1.Increment(Increment);
/*picks a random number between 5 and 10 to increment the ProgressBar by if
the value of the Progress bar is less than or equal to 80*/
}
else
{
progressBar1.Increment(_Increment);
// picks a randome number between 1 and 5 to incremnt by when the ProgressBar is more then 80
}
LoadingLbl.Text = "Loading Game..." + progressBar1.Value + "%";
//When progress bar is at its maximum value the next form will show
if (progressBar1.Value == progressBar1.Maximum)
{
timer1.Stop();
LoadingLbl.Text = "Loading Game... 100%";
CheckScore();
}
}
private void CheckScore()
{
if (StartScreen.Player.Score >= 20)
{
MessageBox.Show("Congratulations, you got more than 80% of the quiz correct. You can proceed to the Game", "Well done!!");
timer1.Stop();
new GameMenu().Show();
Hide();
}
else
{
MessageBox.Show("You got under 80% in the quiz but you can't play the game. Try again.", "Unlucky, Try again");
timer1.Stop();
new EndScreen(false).Show();
Hide();
}
}
}
}
I have
I will link if you would like to have a look for yourself(the source code and a video is included). Thanks
This screen shot shows the problem at the drag drop questions. As you an see from this image, it keeps on multiplying. The same thing happens with the game loading screen
I think the problem is that the timer does not stop which will keep on opening the forms but I'm not sure. I hope this lets you understand my problem better. Thanks
You an still call each question as a form. I would have a function that shows the requested question. This can be called by a second function that can keep track of the question you are on. Also, I would probably call and destroy each form, so that you don't have unnecessary forms hanging around. Something like this (writing this on my phone so take it as an outline more than direct code) :
public void CallQuestions()
{
int QuestionNumber = 1;
do {
if Question(QuestionNumber)
QuestionNumber++;
} while (Exit == false) ;
}
public boolean Question(int number)
{
Form QuestionForm = null;
switch (number)
{
case 1:
QuestionForm = new DragDropYear8_Question1;
break;
//...
}
if (QuestionForm.ShowDialog() == DialogResult.Ok)
return true;
return false;
}

Button is not getting the ViewState Value and no error message shown

i have been trying to use the ViewState object to store the counter for clicking the ImageButton.For instance if ImageButton1 is click it will store the counter == 1(or increment) in it if another button is clicked the counter will become null.I tried clicking the imagebutton , the counter becomes 1 however when i try to retrieve from the submit button via the if else statement it retrieves nothing and the button cannot work.In addition no error message has been shown.I am developing something like a seat selector for my project.Any help will be greatly appreciated!.Below are the codes
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
if (ImageButton1.ImageUrl != "~/Images/bed-occupied.png")
{
ImageButton1.ImageUrl = "~/Images/bed-occupied.png";
if (ViewState["Counter"] == null)
{
counterBed1 = 1;
TextBoxClass.Text = counterBed1.ToString();
}
else
{
counterBed1 = (int)ViewState["Counter"] + 1;
}
}
else
{
ImageButton1.ImageUrl = "~/Images/bed-unoccupied.png";
ViewState["Counter"] = null;
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
ViewState["Counter"] = counterBed1;
// if(ViewState["Counter"] != null)
if(counterBed1 ==1)
{
Panel_ErrorMsg.Visible = true;
lb_ErrorMsg.Text = "Patient Successfully admitted to hospital";
}
}
You are incrementing the value as well as setting a local variable but please note you are never storing the value back in ViewState object.
int counterBed1 = 0;
if (ImageButton1.ImageUrl != "~/Images/bed-occupied.png")
{
ImageButton1.ImageUrl = "~/Images/bed-occupied.png";
if (ViewState["Counter"] == null)
{
counterBed1 = 1;
TextBoxClass.Text = counterBed1.ToString();
ViewState["Counter"] = counterBed1; // Add This
}
else
{
counterBed1 = (int)ViewState["Counter"] + 1;
ViewState["Counter"] = counterBed1; //Add This
}
}
else
{
ImageButton1.ImageUrl = "~/Images/bed-unoccupied.png";
ViewState["Counter"] = null;
}
Also, don't use class variable as it will be re-initialized after every new request, use local variable instead like this in Submit Button handler:-
protected void btnSubmit_Click(object sender, EventArgs e)
{
int counterBed1 = Convert.ToInt32(ViewState["Counter"]);
// if(ViewState["Counter"] != null)
if(counterBed1 ==1)
{

Make previous two buttons disappear when third is clicked in C#

That's my code below and it works perfectly fine, except there is one thing that doesn't work correctly. When I click two buttons to match, they should stay visible until the user clicks a third button. How can I do that? Thank you.
namespace Memorija_Seminarska
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
tableLayoutPanel1.Enabled = false;
label1.Visible = false;
label2.Visible = false;
label3.Visible = false;
progressBar1.Visible = false;
label2.Text = vreme.ToString();
}
public int vreme = 150;
Random random = new Random();
Button firstClicked = null;
Button secondClicked = null;
List<string> drzava = new List<string>()
{
"Македонија","Македонија", "Бугарија","Бугарија", "Србија","Србија",
"Германија","Германија", "Канада","Канада", "Шпанија","Шпанија",
"Португалија","Португалија", "Австрија","Австрија", "Данска","Данска",
"Индија","Индија", "Италија","Италија", "Англија","Англија",
"Турција","Турција", "Грција","Грција","Хрватска","Хрватска",
"Холандија","Холандија", "Русија", "Русија", "Швајцарија","Швајцарија"
};
private void startButton_Click(object sender, EventArgs e)
{
Add();
tableLayoutPanel1.Enabled = true;
label1.Visible = true;
label2.Visible = true;
progressBar1.Visible = true;
timer2.Start();
timer3.Start();
}
private void Add()
{
foreach (Control control in tableLayoutPanel1.Controls)
{
Button b = control as Button;
if (b != null)
{
int randNum = random.Next(drzava.Count);
b.Text = drzava[randNum];
b.ForeColor = b.BackColor;
drzava.RemoveAt(randNum);
}
}
}
private void button_Click(object sender, EventArgs e)
{
if (timer1.Enabled == true)
return;
Button clickedButton = sender as Button;
if (clickedButton != null)
{
if (clickedButton.ForeColor == Color.Black)
return;
if (firstClicked == null)
{
firstClicked = clickedButton;
firstClicked.ForeColor = Color.Black;
return;
}
secondClicked = clickedButton;
secondClicked.ForeColor = Color.Black;
Win();
if (firstClicked.Text == secondClicked.Text)
{
firstClicked.BackColor = Color.GreenYellow;
secondClicked.BackColor = Color.GreenYellow;
firstClicked = null;
secondClicked = null;
return;
}
timer1.Start();
}
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
firstClicked.ForeColor = firstClicked.BackColor;
secondClicked.ForeColor = secondClicked.BackColor;
firstClicked = null;
secondClicked = null;
}
private void timer2_Tick(object sender, EventArgs e)
{
vreme--;
label2.Text = vreme.ToString();
if (vreme == 0)
{
tableLayoutPanel1.Enabled = false;
label3.Text = "Game over!";
label3.Visible = true;
label2.Visible = false;
timer2.Stop();
timer3.Stop();
label1.Visible = false;
progressBar1.Visible = false;
}
}
private void timer3_Tick(object sender, EventArgs e)
{
progressBar1.Value -= 1;
if (progressBar1.Value == 0)
{
timer3.Stop();
}
}
private void Win()
{
foreach (Control control in tableLayoutPanel1.Controls)
{
Button button1 = control as Button;
if (button1 != null)
{
if (button1.ForeColor == button1.BackColor)
{
return;
}
}
}
label3.Text = "Браво!!!";
label3.Visible = true;
tableLayoutPanel1.Enabled = false;
timer2.Stop();
timer3.Stop();
label2.Visible = false;
progressBar1.Visible = false;
label1.Visible = false;
}
}
}
As far as I can see, your timer1_Tick handler performs the hiding automatically when it's time period expires. In case you want this hiding to happen manually when third card is clicked, you should not hide the buttons there, but should just perform a check in the beginning of button_Click:
private void button_Click(object sender, EventArgs e)
{
//two cards are open and not matching (if they matched, they would be already null)
if ( firstClicked != null && secondClicked != null )
{
//hide the buttons
firstClicked.ForeColor = firstClicked.BackColor;
secondClicked.ForeColor = secondClicked.BackColor;
firstClicked = null;
secondClicked = null;
}
}
And delete the timer1.Start() from the end of the event handler.
im not good at understanding other people code, but as far as i look through, you do this in here:
private void button_Click(object sender, EventArgs e)
Check for null
get reference of button 1 and return
get reference of button 2
do win() method
check for equality
here you should send step 5 to front line, check for null as MZetko said, and then check for equality, so it will be third click, else if you get reference as you did, after second button filled up, the checking will also launch
i hope i were helpful

BackgroundWorker for implementing "Search as you type" Combobox

I have created a code for my combobox, that can search addresses in a very large table on Sql Server with the help of stored procedure (i'm working with Entity framework). My stored procedure returns 10 hits and my code fills the combobox with search results. For doing this I'm using BackgroundWorker.
But here I'm now having big problems:
- although the combobox is filled with my search results, it always has the first item selected. Even if I type in only a letter, the whole text gets selected;
After that searching for the address doesn't work anymore. It searches only among these 10 results and I'm having no idea how to solve this. Here is my whole code, that causes me problems:
public String searchedItem = "";
public delegate void DelegateUpdateComboboxSelection(ComboBox myCombo,string value,int count);
BackgroundWorker m_bgworker = new BackgroundWorker();
static AutoResetEvent resetWorker = new AutoResetEvent(false);
m_bgworker.WorkerSupportsCancellation = true;
m_bgworker.DoWork += new DoWorkEventHandler(FillComboboxBindingList);
m_bgworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_bgworker_RunWorkerCompleted);
BindingList<spIskalnikNaslovi_Result1> m_addresses = new BindingList<SP_Result1>();
void m_bgworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
int count = (int)((object[])e.Result)[0];
string value = (string)((object[])e.Result)[1];
ComboBox myCombo = (ComboBox)((object[])e.Result)[2];
DelegateUpdateComboboxSelection ndelegate = new DelegateUpdateComboboxSelection(UpdateComboSelection);
if (this.InvokeRequired)
{
Invoke(ndelegate, new object[] {myCombo, value, count});
return;
}
else
{
UpdateComboSelection(myCombo, value, count);
return;
}
}
private void UpdateComboSelection(ComboBox myCombo, String value, int count)
{
myCombo = comboBox9;
myCombo.DataSource = m_addresses;
searchedItem = myCombo.Text;
if (count > 0)
{
myCombo.SelectionStart = value.Length;
myCombo.SelectionLength = searchedItem.Length - value.Length;
myCombo.DroppedDown = true;
}
else
{
myCombo.DroppedDown = false;
myCombo.SelectionStart = value.Length;
}
}
public void FillComboboxBindingList(object sender, DoWorkEventArgs e)
{
if (m_bgworker.CancellationPending)
{
resetWorker.Set();
e.Cancel = true;
return;
}
else
{
string value = (String)((Object[])e.Argument)[0];
List<SP_Result1> result;
result = _vsebina.SP_searcher(value).ToList<SP_Result1>();
m_addresses = new BindingList<SP_Result1>();
foreach (SP_Result1 rez in result)
{
if (m_addresses.Contains(rez))
{
continue;
}
else
{
m_addresses.Add(rez);
}
}
foreach (SP_Result1 r in m_addresses.ToArray())
{
if (!result.Contains(r))
{
m_addresses.Remove(r);
}
}
e.Result = new object[] { rezultat.Count, vrednost, null };
return;
}
}
private void comboBox9_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back)
{
int searchStart = comboBox9.SelectionStart;
if (searchStart > 0)
{
searchStart--;
if (searchStart == 0)
{
comboBox9.Text = "";
}
else
{
comboBox9.Text = comboBox9.Text.Substring(0, searchStart + 1);
}
}
else
{
searchStart = 0;
}
e.Handled = true;
}
}
private void comboBox9_Enter(object sender, EventArgs e)
{
comboBox9.SelectionStart = 0;
comboBox9.SelectionLength = 0;
}
private void comboBox9_Click(object sender, EventArgs e)
{
comboBox9.Text = "";
}
private void comboBox9_KeyPress(object sender, KeyPressEventArgs e)
{
Search();
}
public void Search()
{
if (comboBox9.Text.Length < 4)
{
return;
}
else
{
if (m_bgworker.IsBusy)
{
m_bgworker.CancelAsync();
m_bgworker = new BackgroundWorker();
m_bgworker.WorkerSupportsCancellation = true;
m_bgworker.DoWork += new DoWorkEventHandler(FillComboboxBindingList);
m_bgworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(m_bgworker_RunWorkerCompleted);
}
m_bgworker.RunWorkerAsync(new object[] { comboBox9.Text, comboBox9 });
}
}
Maybe can someone enlighten me, what I'm doing wrong. This is first time, that I'm using BackgroundWorker. I have no idea, how
to achieve "search as you type" with combobox in any other way, because my datatable with addresses is quite large (million records).
Thanks in advance for any kind of help or code example.
Vladimir
Edit 1:
Ok, here is my code, before I have used BackGroundWorker. It worked, but it searches very very slow (it can take up to 10 seconds):
private void comboBox9_TextChanged(object sender, EventArgs e)
{
if (comboBox9.Text.Length < 4)
{
return;
}
else
{
FillCombobox(comboBox9.Text, comboBox9);
}
}
public void FillCombobox(string value, ComboBox myCombo)
{
List<spIskalnikNaslovi_Result1> result;
result = _vsebina.spIskalnikNaslovi1(value).ToList();
if (result.Count() > 0)
{
myCombo.DataSource = result;
myCombo.ValueMember = "HS_MID";
myCombo.DisplayMember = "NASLOV1";
var searchedItem = myCombo.Items[0].ToString();
myCombo.SelectionStart = value.Length;
myCombo.SelectionLength = searchedItem.Length - value.Length;
myCombo.DroppedDown = true;
}
else
{
myCombo.DroppedDown = false;
myCombo.SelectionStart = value.Length;
}
return;
}
Is there a way to speed this up without having backgroundworker?
make a button you will call searchbutton
and in click_event of this button call your search() method that run your backgroundworker
that fill the combobox
clear you key_press event of your combobox and it will work
the mistake is you key_press event that call every key stroke happening your search method
so retrieve it
You should get your items in a list, use that list to populate your combobox.
then set AutoCompleteMode property value to Suggest or Append or SuggestAppend and set AutoCompleteSoucre property value to ListItems.
For "Search as you Type", which is actually "Filter as you Type" more than search, you need to implement the OnKeyDown or KeyPressed event.
What you would do is take the search string, which is the current text at the time of the event, then filter the master list using that string. Normally one would use "Starts With" for the filtering, but you could also simply use "Contains". Then you live update the contents of the box with the results from the filter. This is accomplished by changing and refreshing the Datasource.
Here is my final solution without BackGroundWorker. It works quick with my large table, and is upgraded for using a stored procedure on SQL Server (if you use Entity Framework). I use Timer to make sure the user can find a value, that he is searching.
Here you can see the original solution, that I found on this site (thanks to Max Lambertini and algreat for the idea and working concept):
C# winforms combobox dynamic autocomplete
My solution:
private bool _canUpdate = true;
private bool _needUpdate = false;
List<spIskalnikNaslovi_Result1> dataFound;
private void comboBox12_TextChanged(object sender, EventArgs e)
{
if (_needUpdate)
{
if (_canUpdate)
{
_canUpdate = false;
refreshData();
}
else
{
restartTimer();
}
}
}
private void comboBox12_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Back)
{
int searchStart = comboBox12.SelectionStart;
if (searchStart > 0)
{
searchStart--;
if (searchStart == 0)
{
comboBox12.Text = "";
}
else
{
comboBox12.Text = comboBox12.Text.Substring(0, searchStart + 1);
}
}
else
{
searchStart = 0;
}
e.Handled = true;
}
}
private void comboBox12_TextUpdate(object sender, EventArgs e)
{
_needUpdate = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
_canUpdate = true;
timer1.Stop();
refreshData();
}
private void refreshData()
{
if (comboBox12.Text.Length > 1)
{
FillCombobox(comboBox12.Text, comboBox12);
}
}
private void restartTimer()
{
timer1.Stop();
_canUpdate = false;
timer1.Start();
}
private void FillCombobox(string value, ComboBox myCombo)
{
dataFound = _vsebina.spIskalnikNaslovi1(value).ToList();
if (dataFound.Count() > 0)
{
myCombo.DataSource = dataFound;
myCombo.ValueMember = "HS_MID";
myCombo.DisplayMember = "NASLOV1";
var searchedItem = myCombo.Items[0].ToString();
myCombo.SelectionStart = value.Length;
myCombo.SelectionLength = searchedItem.Length - value.Length;
myCombo.DroppedDown = true;
return;
}
else
{
myCombo.DroppedDown = false;
myCombo.SelectionStart = value.Length;
return;
}
}

Categories