Komponent Form (zmiana kształtu) C#

Hej,

mam kilka pytań dotyczących programowania w Visual Studio C#.

  1. W jaki sposób mogę zmienić wygląd standardowego kształtu komponentu Form ? Chciałbym aby był on nieregularny np. w kształcie jabłka, albo czegoś innego.

Czy podobnie można zrobić z przyciskami - czy jak wstawię Buttona, to dla niego inaczej zmienia się kształt ?

  1. W jaki sposób przekazywać wartości zmiennych z jednej formy do innej np. Form1 do Form2 i na odwrót ?

  2. Zastanawiam się nad ideą połączenia z bazą danych MySql - wiem jak się połączyć.

Chodzi o to czy w przypadku zapytania np. Select - za każdym razem łączyć się z bazą i rozłączać, czy może połączyć się z bazą i w jakiś sposób utrzymywać połączenie do zakończenia działania programu ?

Zapytań do bazy danych będzie dużo - użytkownik aby wysłać zapytanie będzie przyciskał button np. wyślij.

Jak zrealizować w takim razie połączenie z bazą i jak przechwycić sytuację, w której będę próbował wysłać jakąś komendę (zapytanie np. select ) a okaże się, że jest brak połączenia z bazą ?

Czy za każdym razem będę musiał obejmować blok kodem try i catch - czy może zrobić to jakoś inaczej (np. funkcję, albo coś) ???

Z góry dziękuję za pomoc :wink:

AD 1.

Creating a Shaped Form (Visual C#),

C# Non-Rectangular Windows Form Region,

Irregular Shaped Form,

Give any shape to your form in vb.net,

Custom Arrow Button,

Elliptical/Circular Button.

AD 2. Tak jak do każdej innej klasy, tj. używając przeciążonego konstruktora lub publicznych właściwości.

AD 3. Za każdym razem łącz i rozłączaj się z bazą danych. Połączenie utrzymuj tylko na czas zakończenia danej operacji. Jeśli jednak ta operacja wymaga np. wykonania 100 x UPDATE i 20 x INSERT, to wszystkie te instrukcje SQL wykonaj w ramach jednego połączenia (a nawet w ramach jednej transakcji). Aby sprawdzić jaki jest stan połączenia możesz użyć właściwości State klasy MySqlConnection. Jeśli w trakcie wykonywania danej operacji (np. otwarcia połączenia, wykonywania instrukcji SQL, itd.) może wystąpić wyjątek, to zawsze musisz użyć bloku try catch, przy czym to czy będziesz łapać ogólne wyjątki za pomocą klasy Exception, czy też najpierw bardziej szczegółowe np. MySqlException, a dopiero potem ogólne, czyli Exception, zależy tylko i wyłącznie od Ciebie.

Dzięki za odpowiedzi :slight_smile:

Mam jednak jeszcze kilka pytań - na początku odnośnie zmiany kształtu Form. O właściwości Region, czytałem - jednak wydaje mi się trochę pozbawione sensu, aby za pomocą kodu dokładnie odwzorowywać kształt komponentu - czy istnieje do tego jakieś oprogramowanie (darmowe), które by ten proces zautomatyzowało ? I co z innymi komponentami np. Buttonem - czy tak samo mogę zmienić jego kształt (na tej zasadzie jak Form) ?

Kolejne pytanie dotyczy bazy danych mysql (połączenia) - czy faktycznie sensownym rozwiązaniem jest rozłączanie i połączanie ?

Wydaje mi się tutaj, że będzie to strata czasu - a czy jest jakaś właściwość klasy MySQL, która sprawdzałaby czas połączenia i rozłączała się gdy baza danych nie była wykorzystana przez określony przedział czasu np. po 1 godzinie nieużywania (brak zapytań itp…) ?

Ilość zapytań do bazy danych będzie duża i częsta - i raczej nie będzie się tego dało przesłać w jednym zapytaniu (ze względu na specyfikę programu).

I ostatnie pytanie, w przypadku jak mam główną formę Form1 i zrobię sobie kolejną formę Form2 i ustawię połączenie z bazą danych mysql na formie1 to mam rozumieć, że na formie 2 nie będę mógł wykonać zapytania do bazy danych ?

Czy można objąć połączenie z bazą danych w całym programie - niezależnie od tego w jakiej formie się znajduję - czy też jedyną możliwością (albo lepszą) jest przesyłanie zapytań z form2 do form1 i dopiero stamtąd wysłanie ich do bazy danych ?

Jeszcze raz dziękuję za odpowiedzi :slight_smile:

AD 1. Nie wiem, czy istnieje oprogramowanie, które na podstawie jakiegoś wzoru, automatycznie wygeneruje Ci niezbędny kod. Do swojego poprzedniego posta dodałem jeszcze trzy linki.

AD 2. Tak, jest to sensowne rozwiązanie, a dlaczego tak jest:

Connection Pooling (ADO.NET),

Using Connector/Net with Connection Pooling,

ADO.NET Connection Pooling at a Glance,

Tuning Up ADO.NET Connection Pooling in ASP.NET Applications.

AD 3. Na formie 1 i 2 możesz mieć otwarte dwa niezależne połączenia lub korzystać z tego samego połączenia. Dodam tutaj tylko, że connection string powinieneś przechowywać w jednym miejscu, a mianowicie w pliku konfiguracyjnym aplikacji (takich connection string-ów możesz mieć kilka).

To nie jest “lepsza możliwość”, to jest najgorszy możliwy sposób. Zrób sobie jedną klasę do obsługi bazy danych i używaj jej z obu (a nawet tysiąca, jeśli aplikacja się rozwinie) Form.

W klasach Form nie powinieneś w ogóle korzystać z bazy danych, plików, wykonywać żadnych obliczeń, itd. One są tylko od obsługi GUI.

Tylko mi chodzi o takie coś, że ktoś kliknie przycisk wyślij i wtedy połączy się z bazą danych - czyli i tak zajdzie to w klasie form.

Można prosić ewentualnie o krótki przykład ? Dzięki za poprzednie linki.

Masz mieć drugą klasę poza form, w której wszystko będziesz robić. W form masz się do niej odwoływać :slight_smile:

I jest tak jak pisałem, czyli w obrębie każdej form-y możesz korzystać z niezależnego połączenia z bazą danych. Domyślnie ilość połączeń, które możesz mieć jednocześnie otwarte wynosi 100 i jest definiowana przez parametr Max Pool Size.

Chodzi o to, aby w obrębie procedury reagującej na zdarzenie Click wywołać inną metodę, która będzie zdefiniowana albo bezpośrednio w jednej z klas odpowiedzialnych za realizację instrukcji SQL, albo w jednej z klas realizujących logikę aplikacji, w której najpierw wykonane zostaną jakieś operacje na danych, a dopiero potem zostanie wywołana metoda z jednej z klas odpowiedzialnych za realizację instrukcji SQL.

Klasy realizujące instrukcje SQL to tzw. data access layer (DAL). Możesz sobie te klasy wygenerować (wbudowane generatory istnieją dla ADO .NET Entity i bezpołączeniowego ADO .NET) lub napisać ręcznie. Ty aktualnie tworzysz ręcznie, tzw. połączeniowy ADO .NET. Przy jego tworzeniu możesz skorzystać ze wzorca fabryki dostawców danych, dzięki czemu będziesz mógł łatwo w aplikacji przełączać się między różnymi silnikami baz danych (sęk w tym, że musisz sprawdzić, czy MySQL NET/Connector obsługuje ten wzorzec, bo tego nie wiem), ale utracisz wtedy możliwość korzystania ze specyficznych funkcji danej bazy danych (chodź zgaduję, że pewno z takich korzystać nie będziesz).

Już wszystko zrozumiałem - w klasie Form2 zrobię publiczne metody zwracające prywatne pola , które będę wywoływał w klasie Form1. Moim zdaniem to rozsądne wyjście - ponieważ nie mogę przekazać referencji do Form1 (pisze, że można z niej tylko odczytywać a nie bezpośrednio zapisywać).

Odnośnie bazy danych i pooling to rozumiem jak to ma działać (wizję tego), ale nie widzę tego w praktyce - może jednak znajdzie się jakiś przykład użycia ?

Zrób klasę “BazaDanych”, a w niej metody “Wczytaj”, “Zapisz”, “Usuń”, itd. (oczywiście lepiej użyć angielskich nazw) i tej klasy używaj z Form1 i Form2. Nie wiem jak prościej to wytłumaczyć.

Możesz, po prostu coś źle robisz.

Przecież przykład jest w pierwszym i ostatnim linku, który podałem. Poczytaj te wszystkie 4 linki, które podałem, bo na pewno dużo wyjaśnią :slight_smile: Connection pooling jest realizowane w tle (za Ciebie). Nie ma tutaj jakiejś wielkiej filozofii.

W skrócie chodzi o to, żeby w obrębie całej aplikacji nie używać tego samego obiektu Connection. Załóżmy, że masz dwie klasy realizujące instrukcje SQL dla dwóch różnych tabel. W każdej z tych klas musisz zdefiniować osobny obiekt Connection (obiekty te tworzysz w oparciu o pojedynczy łańcuch połączenia zdefiniowany w pliku konfiguracyjnym aplikacji). I teraz załóżmy, że masz dwie formy (1 i 2), z których każda korzysta z przeznaczonej dla niej klasy realizującej instrukcje SQL. Dzięki temu, że każda z tych klas realizujących instrukcje SQL korzysta ze swojego obiektu Connection, możliwe jest korzystanie w tym samym czasie z dwóch otwartych połączeń z tą samą bazą danych.

[quote]Możesz, po prostu coś źle robisz.[/quote]


W takim razie przedstawiam ci jak to zrobiłem, załóżmy że mam form1 tylko z etykietą label i przyciskiem otwierającym form2, natomiast form2 z edittextem (do wpisania) i buttonem i chce, żeby ktoś wpisał coś do form2, nacisnął przycisk i label w form1 uległ zmianie.


W form 1 mam : 


[code]  


 Form2 okno;

        public Form1()

        {

            InitializeComponent();

            okno = new Form2(ref this);

        }


        private void button1_Click(object sender, EventArgs e)

        {

            okno.ShowDialog();

        }

Natomiast w form2 mam :

private Form1 formatka;


        public Form2(ref Form1 okno)

        {

            InitializeComponent();

            formatka = okno;

        }

Jest jeszcze zdarzenie dla buttona form2, ale teraz to raczej niepotrzebne - wyskakuje mi blad w form1 w wierszu : okno = new Form2(ref this); - podkreslone jest this i jest komunikat :

Error 1 Cannot pass ‘’ as a ref or out argument because it is read-only

Odnośnie baz danych = matzu, teraz mi to bardziej rozjaśniłeś - dzięki :slight_smile:

Czyli jak sobie zdefiniuje np. 2 obiekty Connection, to będą to dwa równoległe połączenia.

A czy za każdym razem jak wykonam jakieś polecenie np. select albo insert to mam zrobić open i potem close - aby zamknąć połączenie ? A jeżeli takich zapytań będzie np. 20 - zakładamy, że nie można tego wysłać w 1 zapytaniu bo będą w odstępach czasowych np. co 2 minuty - to też mam zamykać połączenie closem ?

PS: Rozumiem, że w tym kodzie nie miało być słówka ref - już to zmieniłem i faktycznie działa :slight_smile:

Ale mam jeszcze jedną wątpliwość, jeżeli ustawię modyfikator metody form1 np. na private (taki jest standardowo) to pomimo błędu w oknie Error list - program wykonuje się poprawnie i z form2 zmienia komponent form1 - dlaczego ?

Jak najlepiej i najbezpieczniej ustawić metody ma to być public czy internal ?

Czym tak właściwie jest modyfikator Internal - wcześniej się z nimi nie spotkałem (kojarzę tylko public, private i protected).

Nie wiem, czy rozumiem pytanie, bo wydaje mi się, że już to wyjaśniłem. Połączenie z bazą danych za pomocą Open i Close otwierasz na czas trwania danej operacji. Ta operacja może obejmować 100 x UPDATE i 20 x INSERT (i jeszcze 20 x SELECT, bo musisz wyciągnąć ID wygenerowane przez silnik bazy danych). Jeśli jednak masz do wykonania 20 INSERT-ów, ale będziesz je wykonywać co 2 minuty, to dla każdego INSERT-a otwieraj i zamykaj połączenie za pomocą Open i Close. Pierwszy INSERT będzie wolniejszy, ale kolejne dzięki użyciu connection pooling będą przeprowadzane szybciej. Reasumując jeśli coś ma być wykonane od razu po sobie to przeprowadzaj to w obrębie tego samego połączenia, a jeśli w pewnych większych odstępach czasu, to za każdym razem otwieraj i zamykaj połączenie.

Ok, już wiem co i jak - dzięki :smiley: