Dodawanie elementów do `ListView` odpala event `ItemChecked`, nie można nim sterować

0

Problem jest następujący:

W Visual Studio dodałem sobie listę - element ListView w której, przy elementach, wyświetlam checkboxy. Kod działa w taki sposób, że po kliknięciu na checkbox odpala się event ItemChecked dzięki czemu dane o zaznaczeniu o liście zapisują się do pliku. Wszystko ładnie pięknie działa, event jest podczepiony, ale.. odpala się również po dodaniu elementu do listy - nie chcę by się w takiej sytuacji odpalał, ponieważ lista zapisuje się kilkaset razy przy wczytywaniu (tyle ile jest elementów) :/

Szukam rozwiązania problemu od wielu godzin, i jedyne co znalazłem, to by stosować prostą flagę, odczytując ją w evencie i tym samym sterując jego zachowaniem. Dodałem więc flagę private bool _loading widoczną w poniższym kodzie. Teoretycznie powinno działać. Jednak nie działa jak powinno.

class GridView {

	private bool _loading;

	public void Add(ListViewItem item) {
		// TODO: walidacja danych
		gridListView.Items.Add(item);
	}

	public void LoadData(List<ListViewItem> gridItems) {
		this._loading = true;
		Debug.Write("_loading = true\n");
		foreach (ListViewItem gridItem in gridItems) {
			this.Add(gridItem);
		}
		this._loading = false;
		Debug.Write("_loading = false\n");
	}

	private void gridListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
		if (!this._loading) {
			Debug.Write("ItemChecked! _loading == false\n");
			// TODO: Zapisywanie danych do pliku
		} else {
			Debug.Write("ItemNOTChecked! _loading == true\n");
		}
	}
	
}

Efekt wykonania powyższego kodu jest następujący:

_loading = true
_loading = false
ItemChecked! _loading == False
ItemChecked! _loading == False
ItemChecked! _loading == False
ItemChecked! _loading == False
ItemChecked! _loading == False
ItemChecked! _loading == False
(...)

a powinno być:

_loading = true
ItemNOTChecked! _loading == True
ItemNOTChecked! _loading == True
(...)
_loading = false

Czyli, wygląda na to, że flaga _loading zostaje natychmiast ustawiona na false, mimo, że jeszcze nie dodało elementów do ListView.

**Czy jest więc sposób, by event ItemChecked nie odpalał się podczas dodawania elementów do ListView, lub czy może istnieje jakiś argument do tego dla warunku If wewnątrz metody gridListView_ItemChecked **

0

Może coś w tym stylu:

public void LoadData(List<ListViewItem> gridItems) {
        this.gridListView.ItemChecked -= gridListView_ItemChecked;
        Debug.Write("_loading = true\n");
        foreach (ListViewItem gridItem in gridItems) {
            this.Add(gridItem);
        }
        this.gridListView.ItemChecked += gridListView_ItemChecked;
        Debug.Write("_loading = false\n");
    }
0

@mr_okeke dziwna sprawa bo u mnie działa zgodnie z Twoimi oczekiwaniami:

        private void button1_Click(object sender, EventArgs e)
        {
            List<ListViewItem> itemlist = new List<ListViewItem>();
            for (int i = 0; i < 5; i++)
            {
                ListViewItem item = new ListViewItem("item " + i.ToString(), 0);
                item.Checked = true;
                itemlist.Add(item);
            }
            LoadData(itemlist);
        }
_loading = true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
ItemNOTChecked! _loading == true
_loading = false

Gdy w kodzie nie ustawię item na Chcecked to jest to samo ale wykonuje się tylko 5 x

Poza tym dlaczego nie używasz ItemCheck? To zdarzenie wykonuje się tylko gdy zmieniasz stan checkboxa.

0

Znalazłem szybki hack na ten problem pod tym adresem: http://stackoverflow.com/questions/7506588/why-does-listview-fire-event-indicating-that-checked-item-is-unchecked-after-add . Może przyda się komuś z podobnym problemem.

Czyli:

void gridListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
    if (gridListView.FocusedItem != null) { 
        // Kod do zapisywania pliku danych
    } // jeśli nie ma focusa na żadnym elemencie, to oznacza, ze ładujemy dane
}

Hack jak hack, teraz działa, ale może zepsuć moją aplikacje w przyszłości. Postaram się jednak rozwiązać problem flagą, albo usuwaniem eventu - co zaproponował @dam1an

0

Znalazłem kod który sprawia problem. Mianowicie, w pierwszych linijkach kodu, w pliku Program.cs:

       static class Program {
        [STAThread]
            _gridModel = new GridModel();
            _gridModel.LoadData();

            _gridView = new GridView();
            _gridView.SetColumns(_modelGrid.Columns);

            _gridView.SetController(this);
            _gridView.LoadData(_modelGrid.GetData()); // Tutaj eventy nie są odpalane
            _gridView.ShowDialog(); // dopiero tutaj wykonują się eventy, dlatego zmienna _loading jest ustawiona na false
        }

Co przedstawia się tak:

  • ładujemy dane za pomocą _gridView.LoadData(); i próbujemy blokować eventy przed uruchomieniem
  • następnie wyświetlamy formę GridView, co aktywuje eventy - przez co blokada jest nieskuteczna -- zawsze będzie: GridView._loading == false

Rozwiązałem to w ten sposób, że:

  • usunąłem event ItemCheck z ListView
  • dodałem event Shown do GridView : Form - który odpala się po tym, jak Form stanie się widoczny
  • i dopiero w evencie Shown dodaje event ItemCheck
  • flaga _loading jest nie potrzebna

Pełny - poprawny już - kod:

class GridView {

	public GridView() {
		this.Shown += ViewGrid_Shown;
		InitializeComponent();
	}

	public void Add(ListViewItem item) {
		// TODO: walidacja danych
		gridListView.Items.Add(item);
	}

	public void LoadData(List<ListViewItem> gridItems) {
		foreach (ListViewItem gridItem in gridItems) {
			this.Add(gridItem);
		}
	}

	private void gridListView_ItemChecked(object sender, ItemCheckedEventArgs e) {
		Debug.Write("ItemChecked!\n");
	}

	private void ViewGrid_Shown(object sender, System.EventArgs e) {
		gridListView.ItemChecked += gridListView_ItemChecked;
	}
	
}

Jak widać, kod zrobił się dużo prostszy i działa :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1