Jeg har en form med to usercontrols på. Den ene usercontrol indeholder en listview med en række items som den læser fra en database, og vha en eventhandler på SelectedIndexChanged (samt tilhørende public event for at kunne flytte fra en userform til en anden) bliver detaljer for dette item vist i den anden userform bestående af en række textboxes og selectboxes hvor detaljerne for det enkelte item kan redigeres og gemmes i databasen. Den del fungerer perfekt!
Så snart man begynder at ændre i en af detaljerne sættes en variabel for at fortælle at detaljerne er ændret men ikke gemt.
Hvis denne variabel er sat og man vælger et nyt item på listen bliver man via en messagebox spurgt om man vil skifte til det nye item uden først at gemme detaljerne for det gamle.
Udfordringen består i at omgå eventhandleren midlertidig således at den bibeholder detaljerne for det tidligere valgte item, og ikke mindst at ændre markeringen i listviewet fra det nyvalgte til det forrige valgte item, vel at mærke uden at eventhandleren reagerer på at man manuelt ændrer det valgte item.
Jeg har forsøgt alverdens ting, og brugt adskillige timer på at forsøge at løse det selv, men nu er jeg løbet tør for idéer.
Hej, tak for forslaget. Min egen løsning ligner den meget, men den skaber alligevel problemer da eventhandleren bliver trigget igen når man manuelt ændrer selectedIndex, og man således bliver præsenteret for det samme spørgsmål 4 gange inden det oprindeligt valgte item igen er valgt.
Den oprindelige kode er meget komplex da den kører over flere userforms, men jeg har simplificeret den til én form i nedenstående kode. Da den oprindelige kode kører med en public eventhandler som også trigger en eventhandler i hovedformen skaber det også andre problemer, men jeg tror at hvis først dette problem bliver løst så vil resten også løse sig. Jeg synes blot det blev alt for indviklet at kopiere kode fra flere forskellige forms og userforms ind her.
Det skulle være lige til at oprette et nyt projekt og copy/paste hele koden ind i Form1.cs -----------------------------
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms;
namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
#region Windows Form Designer generated code
/// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("Item1"); System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("Item2"); System.Windows.Forms.ListViewItem listViewItem3 = new System.Windows.Forms.ListViewItem("Item3"); System.Windows.Forms.ListViewItem listViewItem4 = new System.Windows.Forms.ListViewItem("Item4"); System.Windows.Forms.ListViewItem listViewItem5 = new System.Windows.Forms.ListViewItem("Item5"); System.Windows.Forms.ListViewItem listViewItem6 = new System.Windows.Forms.ListViewItem("Item6"); this.listView1 = new System.Windows.Forms.ListView(); this.textBox1 = new System.Windows.Forms.TextBox(); this.textBox2 = new System.Windows.Forms.TextBox(); this.button1 = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // listView1 // this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] { listViewItem1, listViewItem2, listViewItem3, listViewItem4, listViewItem5, listViewItem6}); this.listView1.Location = new System.Drawing.Point(12, 12); this.listView1.MultiSelect = false; this.listView1.Name = "listView1"; this.listView1.Size = new System.Drawing.Size(404, 170); this.listView1.TabIndex = 0; this.listView1.UseCompatibleStateImageBehavior = false; this.listView1.View = System.Windows.Forms.View.List; this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); // // textBox1 // this.textBox1.Location = new System.Drawing.Point(184, 217); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(232, 20); this.textBox1.TabIndex = 1; this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); // // textBox2 // this.textBox2.Location = new System.Drawing.Point(184, 243); this.textBox2.Name = "textBox2"; this.textBox2.Size = new System.Drawing.Size(232, 20); this.textBox2.TabIndex = 2; this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); // // button1 // this.button1.Location = new System.Drawing.Point(341, 269); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 3; this.button1.Text = "Gem"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.buttonSave_Click); // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(181, 201); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(60, 13); this.label1.TabIndex = 4; this.label1.Text = "(Intet valgt)"; // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(9, 282); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(35, 13); this.label2.TabIndex = 5; this.label2.Text = "-1"; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(428, 304); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Controls.Add(this.button1); this.Controls.Add(this.textBox2); this.Controls.Add(this.textBox1); this.Controls.Add(this.listView1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout();
private bool ChangedButNotSaved = false; private int SelectedItem = -1;
private void textBox_TextChanged(object sender, EventArgs e) { //Rød tekst på gem knappen indikerer at der er foretaget ændringer i en af TextBoxene. button1.ForeColor = Color.Red; ChangedButNotSaved = true; }
private void buttonSave_Click(object sender, EventArgs e) { //I dette eksempel gemmes ingenting, men tekstfarven på Gem knappen bringes tilbage til den oprindelige sorte. button1.ForeColor = Color.Black; ChangedButNotSaved = false; }
private void listView1_SelectedIndexChanged(object sender, EventArgs e) { if (listView1.SelectedIndices.Count > 0) { if (ChangedButNotSaved == false) { // Her skifter vi indhold som normalt, ingen problemer her: label1.Text = listView1.Items[listView1.SelectedIndices[0]].Text; textBox1.Enabled = true; textBox1.Text = ""; textBox2.Enabled = true; textBox2.Text = ""; SelectedItem = listView1.SelectedIndices[0]; label2.Text = SelectedItem.ToString(); } else { //Hvis teksten er ændret men ikke gemt bliver vi spurgt om vi vil skifte til det nye valg og dermed miste alle ændringer: DialogResult answer = MessageBox.Show("Denne handling vil nulstille alle ændringer til det åbne item.\n\nØnsker du at lukke det åbne item uden at gemme ændringerne?", "Advarsel!", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (answer == DialogResult.Yes) { //Ja det vil vi gerne, så vi skifter indhold som normalt samt nulstiller ChangedButNotSaved label1.Text = listView1.Items[listView1.SelectedIndices[0]].Text; SelectedItem = listView1.SelectedIndices[0]; label2.Text = SelectedItem.ToString(); textBox1.Enabled = true; textBox1.Text = ""; textBox2.Enabled = true; textBox2.Text = ""; button1.ForeColor = Color.Black; ChangedButNotSaved = false; } else { //Hvis vi vælger ikke at skifte item på listen vælger vi her det item som var valgt inden brugeren valgte et nyt, og vi bibeholder således dataene i TextBoxene. //Problemet består i at når vi ændrer det valgte item tilbage, vil denne eventhandler blive trigget igen. listView1.Items[SelectedItem].Selected = true; } } } else { // SelectedItem = -1; label2.Text = SelectedItem.ToString(); } } }
Den eneste åbenlyse metode jeg kan komme på, uden at vi skal til at lave en custom event der kigger på det tidligere valgte index, er simplethen at "skippe" alt contant i eventet, såfremt tidligere valgte index er lig med det index som bliver valgt.
(jeg viser eksemplet i min kode da denne er nemmere at overskue her på siden )
private int indexValue = -1; //-1 intet valgt.
private void listBox_SelectedIndexChanged(object sender, EventArgs e) { //Denne if sætning checker om det nye index er lig det tidligere valgte. if(indexvalue != listBox.SelectedIndex()) { if(indexValue != -1) { indexValue = listBox.SelectedIndex(); //do stuff normalt. } else { //request user input - keepInfo (boolean) if(keepInfo) { listBox.SelectedIndex(indexValue); //gem ændringer, eller hvad der skal ske } else { indexValue = listBox.SelectedIndex(); //ignore ændringer } //do stuff normalt } } }
Ja du har helt afgjort fanget den rigtige problemstilling, og jeg har selv i den oprindelige kode leget med mange varianter af at tjekke om tidligere index = valgte index, men det er aldrig lykkedes at få det til at fungere 100%. Jeg ved ikke om forskellen ligger i at jeg i min kode anvender et listview og du i din kode en listbox, men hvis jeg har redigeret indholdet i en af textboxene, og vælger et nyt item bliver jeg præsenteret for dialogboxen to gange hvor jeg begge gange skal svare nej for at blive på det valgte item.
Prøv den kode jeg gav herinde i går, og erstat eventhandleren med følgende kode som netop tjekker om valgte index = forrige index. Jeg har lagt lidt messageboxes på som udskriver værdien af relevante variable, men kan stadig ikke gennemskue hvorfor spørgsmålet kommer to gange.
--------------------------------------
private void listView1_SelectedIndexChanged(object sender, EventArgs e) { MessageBox.Show("listView1.SelectedIndices.Count = " + listView1.SelectedIndices.Count.ToString()); if (listView1.SelectedIndices.Count > 0) { MessageBox.Show("listView1.SelectedIndices[0] = " + listView1.SelectedIndices[0].ToString() + "\n" + "SelectedItem = " + SelectedItem.ToString()); if (listView1.SelectedIndices[0] != SelectedItem) { MessageBox.Show("ChangedButNotSaved = " + ChangedButNotSaved.ToString()); if (ChangedButNotSaved == false) { // Her skifter vi indhold som normalt, ingen problemer her: label1.Text = listView1.Items[listView1.SelectedIndices[0]].Text; textBox1.Enabled = true; textBox1.Text = ""; textBox2.Enabled = true; textBox2.Text = ""; SelectedItem = listView1.SelectedIndices[0]; label2.Text = SelectedItem.ToString(); } else { //Hvis teksten er ændret men ikke gemt bliver vi spurgt om vi vil skifte til det nye valg og dermed miste alle ændringer: DialogResult answer = MessageBox.Show("Denne handling vil nulstille alle ændringer til det åbne item.\n\nØnsker du at lukke det åbne item uden at gemme ændringerne?", "Advarsel!", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); if (answer == DialogResult.Yes) { //Ja det vil vi gerne, så vi skifter indhold som normalt samt nulstiller ChangedButNotSaved label1.Text = listView1.Items[listView1.SelectedIndices[0]].Text; SelectedItem = listView1.SelectedIndices[0]; label2.Text = SelectedItem.ToString(); textBox1.Enabled = true; textBox1.Text = ""; textBox2.Enabled = true; textBox2.Text = ""; button1.ForeColor = Color.Black; ChangedButNotSaved = false; } else { //Hvis vi vælger ikke at skifte item på listen vælger vi her det item som var valgt inden brugeren valgte et nyt, og vi bibeholder således dataene i TextBoxene. //Problemet består i at når vi ændrer det valgte item tilbage, vil denne eventhandler blive trigget igen. listView1.Items[SelectedItem].Selected = true; } } } } else { label2.Text = SelectedItem.ToString(); } }
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.