Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

C# - aplikacja drag&drop, kafelki, database itp.

kafus6 26 Wrz 2014 20:17 5754 79
  • Pomocny post
    #31
    Defice
    Poziom 25  
    Widzę, że kolega Marcin mnie uprzedził z odpowiedzią. Ale muszę z przykrością stwierdzić, że trochę tu zbyt wiele błędów.

    Całość na moje do kosza i do napisania ponownie. Kod zbudowany jest nielogicznie, więc i poprawiać nie ma sensu. Zważywszy jeszcze na cel, czyli to co przedstawiłeś w pierwszym poście. Na początek to ja proponuję zastanowić się dokładnie jak ma wyglądać aplikacja (to z grubsza przedstawiłeś), następnie trzeba określić kroki do realizacji. Z tego co widzę ma się to przedstawiać w następujący sposób.

    1. Stworzenie bazy danych.
    2. Wczytanie jej do formy.
    3. Stworzenie na jej podstawie "kafelków".
    4. Obsługa Drag&Drop.
    5. Zapis zmian w bazie danych.

    Z tego co widzę, wrzuciłeś teraz DataGridView. Oczywiście w finalnej wersji go nie będzie? Rozumiem, że pojawił się tu tylko do sprawdzenia/wyświetlenia zawartości tabeli. Inna sprawa, że twój aktualny kod miesza 2 podejścia do problemu, raz korzystasz z dataseta, a raz z DataGridView. To niestety jest oznaka, że niezbyt rozróżniasz zastosowania obu komponentów.
  • #32
    kafus6
    Poziom 14  
    Dzięki za podpowiedzi :)
    Zmienne dałem do zdarzenia button1_Click i działa prawidłowo. Aby sprawdzić jak działa odwołanie się do zaznaczonych kolumn, dodałem:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    i wywołanie:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Przy okazji tego wiem jak łączyć wartości z dwóch kolumn do jednego Label'a.
    Jeszcze raz dzięki za podpowiedzi.

    Edit:
    Pytanko w sprawie 'czyszczenia' kodu.
    Chciałbym użyć kilku plików .cs aby rozdzielić kod- w jednym pliku napisałbym funkcje, a w drugim np. wygląd wszystkich kontrolek, w trzecim jakieś coś innego lub tak, aby wszystkie większe funkcje do jednej kontrolki były w osobnym pliku itp. na przykładzie zdarzenia button1_Click ( pobiera kod z innego pliku .cs o nazwie np. Show_workers.cs)

    Edit 2: Do Defice

    Tak DataGrid był tylko jako pomoc dla mnie :) Kod teraz troche inaczej wygląda- popracowałem nad nim i mam nadzieje, że chociaż troszkę jest w ramach poprawnie wyglądającego kodu...


    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Cytat:

    1. Stworzenie bazy danych.
    2. Wczytanie jej do formy.
    3. Stworzenie na jej podstawie "kafelków".
    4. Obsługa Drag&Drop.
    5. Zapis zmian w bazie danych.


    ad1. Baza danych już istnieje wraz z relacjami
    ad2. Mówisz o tym, że mam ją wczytać globalnie? np. w Form1?
    ad3. Jestem na tym etapie.
    ad4. Narazie mam materiały do tego 'howDoIt' :)
    ad5. daleko jeszcze przede mną :)[/quote]
  • #33
    marcinj12
    Poziom 40  
    Kilka rzeczy do przemyślenia / poprawienia:
    - niepotrzebnie ponownie otwierasz i zamykasz połączenie po tym, jak już wykonałeś zapytanie...

    - do obiektu SqlCommand niepotrzebnie dwa razy przypisujesz połączenie (najpierw w konstruktorze, a potem wprost)

    - pobierasz dane sqlem do tabeli, a potem wykorzystujesz ją tylko do stworzenia labeli... OK, można i tak, ale bardziej logicznie byłoby wykorzystać zamiast SqlDataAdapter'a odczyt za pomocą SqlDataReaer. Było o nim w kursach które proponowałem. Wtedy nie tworzysz żadnej tabeli pomocniczej, w kolejnych iteracjach pętli tworzysz kolejne labele.

    - zmienną conn wypada po użyciu zwolnić poleceniem conn.Dispose() albo wrzucając ją w sekcję using().

    - proponuję zacząć stosować jakieś logiczne nazewnictwo zmiennych i kontrolek - może na razie to nie problem,ale w miarę jak się program rozrośnie - sam się pogubisz... Standardowe Form1, button1 czy panel1 można zastąpić czymś więcej mówiącym o kontrolce. Warto stosować skrótowce, np. btnWykonaj czy pnlKontener1

    - kod lepiej wygląda, kiedy stosuje się pewne konwencje nazewnictwa - u Ciebie każda nazwa jest z innej parafii: Worker_Name, cmd_Worker_name, getValue, DataTable_Worker_name... Oprócz nazw publicznych pól, zmienne lokalne powinno zaczynać się z małej litery stosując camel-notation i unikając podkreśleń w kodzie - czyli z tej serii tylko getValue jest ładnie nazwane.

    - nie nazywasz zmiennych logicznie - np. getValue, ta nazwa nic nie mówi. "Get" sugeruje akcję i stosuje się go raczej w nazwach zdarzeń, nie zmiennych. Skoro pobierasz imię i nazwisko, to może zamiast getValue i getValue2 po prostu: workerName, workerSurname? Zmienna Worker_Name dla zapytania SQL wprowadza w błąd - to jest zapytanie SQL, nie imię, w dodatku zwraca ono imię i nazwisko. Krótka nazwa sql lub query będzie lepsza.
    Dla odmiany - zmienne cmd_Worker_name, sdadapter_Worker_name, DataTable_Worker_name niosą zbyt dużo informacji - wystarczy cmd, adapter, dt - z kontekstu wynika, że dotyczą one pracownika. Cały kod obsługi zapytać sqlowych w ogóle warto przerzucić do innego pliku, możesz spróbować, ale na tym etapie na razie sobie tym głowy nie zaprzątaj.
    O znaku podkreślnika przy nazewnictwie lepiej zapomnij (dot. również nazw plików).

    - przestrzeń System.Drawing możesz zadeklarować w using... na samej górze, nie będziesz musiał później tego powtarzać w kodzie.

    kafus6 napisał:
    Pytanko w sprawie 'czyszczenia' kodu.
    Chciałbym użyć kilku plików .cs aby rozdzielić kod- w jednym pliku napisałbym funkcje, a w drugim np. wygląd wszystkich kontrolek, w trzecim jakieś coś innego lub tak, aby wszystkie większe funkcje do jednej kontrolki były w osobnym pliku itp. na przykładzie zdarzenia button1_Click ( pobiera kod z innego pliku .cs o nazwie np. Show_workers.cs)
    Ja w tym zdaniu nie widzę pytania... pomysł generalnie dobry, ale też nie ma co przesadzać z ilością plików na którą dzielisz logikę. Możesz zastosować oddzielenie interfejsu użytkownika (GUI - obsługa kontrolek) od logiki binesowej (wszystko, co się da a nie jest powiązane z GUI) oraz dostępu do danych (zapytania SQL) - to tzw. trójwarstwowy model aplikacji. Dla często powtarzanych operacji, np. formatowania kontrolek możesz stworzyć odpowiednie klasy pomocnicze.
  • #34
    kafus6
    Poziom 14  
    A ja myślałem, że w miarę dobry kod napisałem, a Ty mi tutaj taką litanie piszesz :)- dziekuje :)
    Nazwy szystkich zmiennych, kotrolek itp są robocze- wiem, powinienem od razu dobrze nazywać i zazwyczaj staram się tak robić, a tu mi to jakoś spadło na niższy plan.

    Co do trójwarstwowego modelu- chciałem się zapytać jak wywoływać klasy z innych plików?
    np.
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • Pomocny post
    #35
    marcinj12
    Poziom 40  
    Po raz kolejny odsyłam do przykładów na Internecie - ten w miarę dobrze przedstawia zagadnienie architektury trójwarstwowej. Chociaż prawdę powiedziawszy można spotkać na nacie wiele różnych jej wariacji - więc na początku polecam przeczytać kilka różnych tutoriali opisujących temat i na ich podstawie opracować sobie jakiś własny sposób, którego będziesz się trzymać.
  • #36
    kafus6
    Poziom 14  
    Po małej przerwie...

    Zrobiłem dynamicznie tworzenie się buttonów z bazy danych buttonManager[i] gdzie wyświetlani są menagerowie.
    Zrobiłem również buttonSection[i] sekcje gdzie pokazywane są sekcje zalogowanego menagera. Wszystko wyświetlane jest w osobnych panelach (panelNazwaPanelu).

    Tak stworzyłem buttonSection[i]:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    1. Jak mogę wywołać tworzenie się Pracowników po kliknięciu na stworzonym przed chwilą buttonSection[i] ? Szukałem czegoś podobnego, ale nie umiem znaleźć.

    2. Czy ta linia:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Jest dobra? wyświetla prawidłowe dane, ale czytając dokumentację włąściwości SqlDataReader.FieldCount trochę mi tutaj nie pasuje(albo czegoś nie rozumiem).
  • #37
    marcinj12
    Poziom 40  
    kafus6 napisał:
    1. Jak mogę wywołać tworzenie się Pracowników po kliknięciu na stworzonym przed chwilą buttonSection[i] ? Szukałem czegoś podobnego, ale nie umiem znaleźć.
    Wpisz
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    i dwa razy tab. Utworzy automatycznie zdarzenie obsługi przycisku, które możesz sobie oprogramować.

    kafus6 napisał:
    2. Czy ta linia:

    Kod C# - [rozwiń]

    Button[] buttonSection = new Button[sdrSection.FieldCount];

    Jest dobra? wyświetla prawidłowe dane, ale czytając dokumentację włąściwości SqlDataReader.FieldCount trochę mi tutaj nie pasuje(albo czegoś nie rozumiem).
    Nie jest.
    Po pierwsze: FieldCount to ilość pól (kolumn) w sql readerze. Jeśli zadziałało to tylko dlatego, że masz mniej niż 3 wiersze z wynikami...
    Po drugie: umieszcznie linii:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    wewnątrz pętli while jest bez sensu, bo każdorazowo tworzysz trzyelementową tablicę, a potem wypełniasz tylko jedno jej pole... Jeśli chcesz później gdzieś użyć tej tablicy, powinieneś zadeklarować ją wcześniej tak, żeby była globalnie dostępna. W przeciwnym wypadku zniknie po zakończeniu funkcji.

    W ogóle pracując z datareaderem lepiej użyć dynamicznej listy - zamiast
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    użyj
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    - oczywiście zadeklarowane poza funkcją. Potem użyj buttonSection.Add(...) aby dodać nowego buttona do listy.

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    ...w życiu Romana... Jeśli to nie wywala wyjątku, to tylko przypadkiem... Dispose niszczy zmienną i nie można już na niej wykonywać żadnych operacji. Akurat w tym wypadku, kiedy korzystasz z using() na obiekcie Connecion, nie musisz robić ani Dispose, ani Close - using() robi to za Ciebie...
  • #38
    kafus6
    Poziom 14  
    Dzięki za szybką odpowiedź i za kolejne wskazówki :)

    Od początku

    Zrobiłem:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Potem dla sprawdzenia:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    Wyrzuca błąd NullReference (nawet jeśli zastąpię Button clickedbutton podobnym kodem do tworzenia dynamicznych labeli, który już mam stworzony). Co ja robię nie tak ?

    Nie umiałem poradzić sobie również z:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Więc dodałem DataTable i dataTable.Rows.Count. Nie wiem czy jest to poprawne.

    Bardzo mnie to rozśmieszyło:
    Cytat:
    ...w życiu Romana...

    Hah. You made my day :)
  • #39
    anonymousexd
    Poziom 24  
    Gdzie dokładnie pojawia się wyjątek?
    Sprawdź czy
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    nie jest NULL'em.
  • #40
    marcinj12
    Poziom 40  
    Ale Ty korzystasz gdzieś potem z tej tablicy buttonów czy nie??
  • #41
    kafus6
    Poziom 14  
    błąd nulla wywala w linii
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Edit:

    Dałem tą linie po funkcji (foreach) i teraz wywala Out of range.





    mam tak:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    Oczywiście to już jest po 1000 zmianach i już sam nie wiem co jest dobrze a co nie.
  • #42
    marcinj12
    Poziom 40  
    Wrzuć więcej kodu i odpowiedz na pytanie...
  • #43
    anonymousexd
    Poziom 24  
    Dodaj tam linie:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod


    I napisz czy pojawia się komunikat "BUTTON JEST NULLEM".
  • #44
    kafus6
    Poziom 14  
    Ostatnio rano coś próbowałem więc nie wiem czy już czegoś nie przekombinowałem. Cały kod:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #45
    witoldwitoldowicz
    Poziom 28  
    Dlaczego masz "+=new"?
  • Pomocny post
    #46
    anonymousexd
    Poziom 24  
    witoldwitoldowicz napisał:
    Dlaczego masz "+=new"?


    Ta linijka jest poprawna, ale chyba jest w złym miejscu. Spójrz sobie chociażby na autogenerated code. To dodaje kolejny handler zdarzenia.

    Tak powinno zadziałać:


    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #47
    marcinj12
    Poziom 40  
    Oj, przekombinowałeś i to mocno... :-/

    Naprawdę, uważam, że dopóki nie poznasz podstaw programowania, daleko nie zajdziesz - rozwiążesz jeden problem, pojawią się dwa kolejne... Chodzi o takie podstawy jak co to jest tablica, jaki jest zakres widoczności zmiennych etc.

    Poprawię ten kod raz jeszcze, ale jeśli kolejne pytanie będzie dotyczyło równych podstaw, nie udzielam się więcej w tym temacie, bo nie widzę sensu... :-/ Wątek i tak zrobił się za długi.

    Mimo, że dwa razy o to prosiłem, nie napisałeś, czy korzystasz po utworzeniu z tablicy buttonów buttonSection[] poza funkcją. Z fragmentu kodu wynika że nie, chyba, że zadeklarowałeś tablice buttonSection[] dwa razy - w zdarzeniu buttonclick i poza nim... Zakładam, że jednak nie, więc tablica nie jest potrzebna.

    Poprawny kod, na tyle, na ile potrafię się domyślić z tego fragmentu, powinien wyglądać tak:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #48
    kafus6
    Poziom 14  
    Byłem sceptycznie do tego nastawiony, ale zadziałało o dziwo :) Z tego co pamiętam próbowałem wstawić tą linijkę za panelSections... ale tam nie działało. Dzięki wielkie.

    marcinj12:
    Napisałem wcześniej, że nie korzystałem, ale zniknął ten post, w którym to napisałem :( Nigdzie indziej nie korzystałem z buttonSection[] oprócz tego jednego razu.
    Nie zrozumiałeś mojego pytania wcześniejszego, nie pytałem co to jest tablica, ale nie potrafiłem przekształcić tego co mam na tablice( zapewne dlatego, że nie poświęciłem temu wystarczającej uwagi).

    Mam jeszcze jedną prośbę/pytanie.
    Chciałbym, żeby ten pierwszy void( czyli void buttonSection_Click(object sender, EventArgs e) był uruchamiany na starcie Form, a nie przy kliknięciu na buttonSection. Co należy wpisać w public Form() ?
  • #49
    marcinj12
    Poziom 40  
    kafus6 napisał:
    Chciałbym, żeby ten pierwszy void( czyli void buttonSection_Click(object sender, EventArgs e) był uruchamiany na starcie Form, a nie przy kliknięciu na buttonSection. Co należy wpisać w public Form() ?
    Wykorzystać zdarzenie Form_Load().
    Wszystko, co masz w zdarzeniu buttonSection_Click, przenieś do osobnej metody, np.
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    a w buttonSection_Click i Form_Load zrób wtedy:
    Kod: csharp
    Zaloguj się, aby zobaczyć kod
    Chyba, że w ogóle nie chcesz tego przycisku mieć - wtedy cały kod możesz przenieść od razu do Form_Load
  • Pomocny post
    #50
    anonymousexd
    Poziom 24  
    Kliknij dwukrotnie w edytorze GUI na ramce formy tak by powstało zdarzenie "Form1_Load" a potem wklej tam swój kod.
  • #51
    kafus6
    Poziom 14  
    Dzięki za podpowiedzi. Wszystko działa teraz jak należy.
    Temat faktycznie zrobił się przydługi, ale założyłem go właśnie po to, aby ktoś jeszcze mógł z tego skorzystać.

    Pozostało teraz chyba najważniejsze, drag&drop :) W miarę pisania, będę wklejał kod. Mam nadzieje, że nie będzie za dużo kłopotów, ale...nadzieja matką głupich :)

    Dodano po 1 [godziny]:

    No i oczywiście pojawiło się pytanie jeszcze odnośnie tworzenia labeli.
    Mam stworzonych Liderów, z których tworzą się przyporządkowane do nich sekcje (sections - ten ostatni kod, który przesłałem, a który marcinj12 poprawił (tutaj pokłony;P)). Teraz chciałbym dodatkowo z tych sekcji, stworzyć pracowników(Workers), którzy są dopasowani do powyższych sekcji..... To może ja pokaże :)
    C# - aplikacja drag&drop, kafelki, database itp.

    Prosiłbym o podpowiedź ('słownie') co bym musiał zrobić.
    Zapewne będzie to connectString z sqlcommandem i adapterem.
    Potem jakaś pętelka foreach? Znając moje 'doświadczenie' zapewne to jest złe. :) np.
    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    (te foreach'e mnie wykończą.)
    Nie byłoby problemem jeśli Buttony w Sekcjach byłyby dodane ręcznie, ale są tworzone dynamiczne.
  • #52
    marcinj12
    Poziom 40  
    1. Kopiujesz kod, który masz w buttonSection_Click
    2. Wklejasz go do buttonWorkers_Click
    3. Na początku dodajesz panelWorkers.Controls.Clear();
    4. Sql modyfikujesz tak, aby wybrać imię i nazwisko z tabeli pracowników, w warunku WHERE wykorzystując btn.Tag.ToString() żeby odfiltrować tylko pracowników o ID danej sekcji.
    5. Modyfikujesz tak, aby zamiast buttonów tworzyć labele i działać na panelWorkers zamiast panelSections.

    Pętle foreach - i proszę to sobie wbić do głowy ;) - służy do nawigowania po każdym elemencie kolekcji: tablicy, listy etc. W każdym kroku pętli "wybiera" ona z listy kolejny element, który przypisuje do zmiennej o takiej nazwie, jak w pętli podajesz. Na tym elemencie możesz wykonywać operacje tak, jakbyś odwoływał się właśnie do tego konkretnego elementu. W podanym przykładzie wybierasz kolejne kontrolki znajdujące się w panelu. Ifem w środku sprawdzasz, czy jest to button. Ta informacja jest zupełnie nieprzydatna w tym, co teraz chcesz zrobić.
  • #53
    kafus6
    Poziom 14  
    No piękne dzięki raz jeszcze. Mam jedno ale... :)
    ...ale btn.Tag does not exist in the current context. A jakakolwiek próba zapisania tej zmiennej jako globalnej kończy się oczywiście złym wynikiem. Jak się domyślasz, program dodaje wynik z pętelki do wartości zapisanej w zmiennej globalnej. Czy ja znowu o czymś nie wiem/zapomniałem ?

    A z tą pętlą foreach (zresztą jak sama nazwa wskazuje- dla każdego/każdej (...) zrób(w domyśle) {...}. Nie wiem czemu ale chciałem dla wszystkich buttonów sekcji na raz podać funkcje, a trzeba je przecież traktować osobno- inny tok myślenia. Zapamiętam :)
  • #54
    anonymousexd
    Poziom 24  
    kafus6 napisał:
    btn.Tag does not exist in the current context.


    Jeśli "btn" to obiekt klasy Button to pole "Tag" musi istnieć. A jeśli to nie jest obiekt klasy Button to wykonaj rzutowanie na Button.
  • #55
    kafus6
    Poziom 14  
    Jakieś bliższe podpowiedzi ? :)
  • #56
    anonymousexd
    Poziom 24  
    Jakiej klasy jest to "btn" które nie ma pola "Tag"?
    Najlepiej wrzuć kod albo daj projekt w załączniku.
    Znów podałeś tak mało informacji że trudno jest cokolwiek stwierdzić.

    Chyba że pytasz o rzutowanie?
    Jeśli tak to:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #57
    kafus6
    Poziom 14  
    Nie pisałem kodu bo to ten sam co marcinj napisał.
    Czyli mam tak: (Zaznaczyłem w kodzie)

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #58
    anonymousexd
    Poziom 24  
    W tamtym miejscu w kodzie nie ma żadnej zmiennej o nazwie buttonSection.
    Spróbuj tak:

    Kod: csharp
    Zaloguj się, aby zobaczyć kod
  • #59
    kafus6
    Poziom 14  
    Dziękuje, działa :)
    Mógłbyś wytłumaczyć o co chodzi z tym:
    Button buttonSection = (Button)sender; ??
  • #60
    anonymousexd
    Poziom 24  
    To jest rzutowanie. Tzn. jeśli jedna klasa dziedziczy po drugiej i mamy wskaźnik do klasy która jest starsza w hierarchii (tzn. jest "rodzicem", w tym przypadku object) to możemy z pomocą rzutowania otrzymać wskaźnik klasy która jest młodsza w hierarchii (tzn. jest "dzieckiem", w tym przypadku Button).