Posts Tagged ‘projektowanie’
Agile estimating and planning
Insight w programowanie msejf: .NET
Poniższym wpisem chcielibyśmy rozpocząć serię postów dedykowanych technologiom, w jakich tworzymy aplikację msejf. Projekt i jego poszczególne elementy wymagają połączenia różnych rozwiązań i dzięki temu jest wyjątkowo ciekawy z punktu widzenia programistów i web developerów.
Cykl chcielibyśmy zacząć od przyjrzenia się technologii .NET, w oparciu o którą zbudowaliśmy część desktopową aplikacji. Spośród typowych bibliotek tej platformy z których korzystaliśmy szczególnie dwie zasługują na szczególną uwagę: WPF i WCF.
WPF (Windows Presentation Foundation) to silnik graficzny bazujący na platformie .NET od wersji 3.0. Co takiego ciekawego jest w WPF, że postanowiliśmy użyć jej do naszej aplikacji? WPF daje nam ogromne możliwości co do kształtowania wyglądu aplikacji. msejf ma być niebanalny, a jeśli tak, to WPF jest naturalnym wyborem. Tworząc interfejs użytkownika praktycznie nie musimy się niczym ograniczać. Nie musimy martwić się o to, że nie będziemy w stanie przełożyć kreatywności naszych grafików na działającą aplikację.
Dla nas, programistów, WPF ma też inne zalety. Przede wszystkim, WPF zmienia całkowicie sposób implementacji aplikacji desktopowych, zbliżając się stylem do aplikacji webowych. Nasze aplikacje oparte są o wzorzec projektowy Model-View-ViewModel, co skutkuje przejrzystym i łatwiejszym w utrzymaniu kodem.
WCF to drugie w kolejności ciekawe rozwiązanie, w oparciu o które zbudowaliśmy klienta msejf. WCF (Windows Communication Foundation) to część .NET Framework’a, która dostarcza ujednolicony model programistyczny dla aplikacji opartych o usługi. Większości będzie się to zapewne kojarzyć z komunikacją z zewnętrznymi serwisami. My wykorzystujemy WCF do komunikacji międzyprocesowej. Technologia znakomicie sprawdza się w tej roli, upraszczając wymianę informacji między komponentami. Jej zastosowanie daje nam też duże możliwości łatwej zmiany konfiguracji oraz monitorowania pracy komponentów dzięki wbudowanym mechanizmom logowania.
Co jeszcze w msejf desktop zasługuje na szczególną uwagę? Zastosowaliśmy mnóstwo ciekawych rozwiązań. Długo zastanawialiśmy się nad wyborem optymalnej architektury, co zaowocowało sprawnie działającą, łatwą w utrzymaniu i stabilną aplikacją. Na każdym etapie prac staraliśmy się trzymać najlepszych praktyk wytwarzania i projektowania oprogramowania.
msejf desktop to nie tylko ciekawe technologie, ale przede wszystkim innowacyjna aplikacja, a efekt końcowy naszych prac będzie można już wkrótce podziwiać.
źródło: blog.msejf.pl
Najprostszy sposób na zalogowanie użytkownika
Obecnie, w niemal każdej aplikacji biznesowej wymagane jest zalogowanie się, by w pełni móc korzystać z możliwości, jakie taka aplikacja daje, lub by wogóle móc cokolwiek zrobić. Jakiś czas temu zrobiłem krótki research po sieci w poszukiwaniu jakiegoś sprytniejszego rozwiązania niż to, które używam w swoich aplikacjach. Cóż… Dziwni są ludzie, którzy zatrudniają do obrony swojego zamku legiony, a pozwalają do niej wejść zwykłym OR 1=1 (to tak na marginesie), nie rozumię też rozwiązania, które zostało pozytywnie ocenione na jednym z for programistycznych, a wygląda ono tak:
W aplikacji sprawdzamy, czy ustawiony jest w bazie znacznik informujący o zalogowaniu, jeśli nie, to po zalogowaniu generujemy go, a usuwamy, gdy użytkownik zamknie aplikację… A co, jeśli zwiesi się komp, zabraknie prądu albo wydarzy się coś innego? Przecież po wystąpieniu tak nieoczekiwanego zdarzenia wartość w bazie może się nie zmienić, a wtedy każdy, kto skorzysta z komputera będzie zalogowany. Naprawdę nie rozumię wielu tych wielkich idei, dlatego na razie nadal korzystam z bardzo prostego rozwiązania, które wygląda następująco:
W aplikacji w sekcji odpowiedzialnej za przechowanie predefiniowanych zmiennych globalnych (jak np. nazwa bazy, string wyświetlany w górnej belce aplikacji etc.) ustawiam sobie zmienną, określającą, czy użytkownik jest zalogowany (domyślnie ustawioną na false) oraz metodę pozwalającą zmienić wartość tej zmiennej:
public class GlobalAppVariables
{
/// Globalna zmienna, której wartość jest ustwaiona na 1, gdy użytkownik się zaloguje.
static int _logged = 0;
/// Dostęp/zmiana wartości globalnej zmiennej _logged
public static int Logged
{
get
{
return _logged;
}
set
{
_logged = value;
}
}
}
Samo logowanie polega na wywołaniu metody, która połączy się z bazą, sprawdzi, czy dla podanych parametrów istnieje wpis i na tej podstawie zwróci wynik pozytywny/negatywny, co z kolei pozwoli mi ustawić wartość zmiennej _logged w następujący sposób:
private void button1_Click(object sender, EventArgs e)
{
object result = Queries.StartSession(this.loginTxt.Text, this.PasswordTxt.Text);
//Queries to osobna klasa, w której przechowywane są metody odpowiedzialne za operacje na bazie
if (result != null)
{
this.Close(); //zamknięcie okna logowania
GlobalAppVariables.Logged = 1; // w tej chwili wiem, że już mam zalogowanego użytkownika
}
else
{
//info o nieudanym logowaniu
}
}
Jeśli już mam zalogowanego użytkownika, mogę odblokować domyślnie wyłączone opcje, lub zrobić coś innego.
Jeśli nie potrzebujesz wymyślnego systemu logowania skorzystaj z przedstawionego sposobu. Jest on wystarczający dla wielu nieskomplikowanych aplikacji. AVE!
Dynamiczne generowanie kontrolek
W czasie pracy nad swoim małym projektem w C#, stanąłem przed problemem dynamicznego generowania kontrolek na formie. Nie chciałem, aby cały kod za to odpowiedzialny znajdował się w zdarzeniu kliknięcia w button, wiec stworzyłem przykładową klasę, którą nazwałem ControlGenerator.
![]()
Generalnie, trzeba by ją jakoś połączyć z główną formą aplikacji (w projekcie Form1 – standardowe nazewnictwo, gdyż więcej form nie przewiduję). W klasie ControlGenerator utworzyłem zmienną typu Form1 służącą za łącznik klasa – forma:
public class ControlGenerator
{
/// Prywatna zmienna typu Form1
private Form1 pf;
//...
}
Następnie, konstruktor klasy musi posiadać takie przypisanie zmienej pf, aby wskazywała ona na referencję instancji mojej Form1 (trochę to może zamieszane, więc kawałek kodu wyjaśni, co miałem na myśli):
public ControlGenerator(Form1 f1)
{
pf = f1;
}
Tak właśnie wygląda konstruktor, o którym była mowa, a jak to wygląda ‘na żywo’ jest ukazane poniżej.
W formie głównej aplikacji (Form1) po kliknięciu w jeden z przycisków powinny wygenerować się kontrolki, inicjuję więc obiekt klasy ControlGenerator w następujący sposób:
private void button1_Click(object sender, EventArgs e)
{
ControlGenerator generate = new ControlGenerator(this);
// właśnie tu do konstruktora przekazuje referencję do Form1 za pomocą this
}
Skoro moje połączenie klasa – forma jest już aktywne, to pora napisać metodę generującą kontrolki. Do owej metody powinna być przekazana informacja jak wiele kontrolek utworzyć. W poniższym przykładzie ograniczę się do wygenerowania TextBoxów z Labelkami zawartymi w GroupBoxie (które mogą być oczywiście dodatkowo osadzone na jakimś panelu, czy czymkolwiek się chce).
Gotowa funkcja prezentuje się następująco:
public void GenerateRegisterControls(int number, string text)
{
int[] textboxes = new int[number];
string[] labels = { "Imię", "Nazwisko", "PESEL", "Ulica", "Numer budynku",
"Miasto", "Kod pocztowy", "Województwo", "Telefon" };
int i = 0, move = 0;
//tworzę GroupBoxa, do którego wrzucę tworzone kontrolki (opis metody w następnym listingu)
GroupBox box = GenerateGroupBoxControl(text);
foreach (int element in textboxes)
{
TextBox textbox = new TextBox(); //tworzę nowego TextBoxa
Label label = new Label(); //tworzę nowy Label
//lokalizacja TextBoxa
textbox.Location = new System.Drawing.Point(200, 70 + move);
textbox.Name = "textbox" + i.ToString();
textbox.Size = new System.Drawing.Size(360, 20 + move); //wymiary TextBoxa
//Rozmiar czcionki w TextBoxie - funkcja nie zostanie przedstawiona
//w tym wpisie
textbox.Font = SetFontForElement(40, textbox.Font);
textbox.TabIndex = i;
textbox.Visible = true;
//automatyczna zmiana rozmiarów TextBoxa przy zmianie rozmiaru okna
textbox.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;
textbox.BorderStyle = BorderStyle.FixedSingle; //styl ramki
//lokalizacja Labela
label.Location = new System.Drawing.Point(20, 80 + move);
label.Name = "label" + i.ToString();
//nazwa Labela wzięta z wcześniej utworzonej tablicy stringów
label.Text = labels[i];
label.Font = SetFontForElement(28, label.Font);
label.Size = new System.Drawing.Size(160, 28);
label.Visible = true;
box.Controls.Add(textbox); //dodaję do GroupBoxa utworzone TextBoxy
box.Controls.Add(label); //dodaję do GroupBoxa utworzone Labele
i++;
move += 50;
}
//dodaję GroupBoxa z kontrolkami do panelu w kontenerze Form1
pf.splitContainer1.Panel2.Controls.Add(box);
}
Jak widać funkcja nie jest specjalnie skomplikowana, a tablicę z nazwami labelek można by przekazać jako parametr – jednak nie ma potrzeby w tym wpisie rozmieniać się na drobne. Tworzenie TextBoxów i Labelek można by dodatkowo zostawić osobnym funkcjom wywołanym w GenerateRegisterControls, jak np. GenerateGroupBoxControl, która wygląda następująco:
private GroupBox GenerateGroupBoxControl(string text)
{
GroupBox box = new GroupBox();
box.Name = "GroupBoxRegister";
box.Text = text;
box.Location = new System.Drawing.Point(1, 9);
box.Size = new System.Drawing.Size(pf.splitContainer1.Panel2.Width - 20, pf.splitContainer1.Panel2.Height - 20);
box.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
return box;
}
Samo wygenerowanie kontrolek po kliknięciu w jeden z przycisków wygląda następująco:
private void button1_Click(object sender, EventArgs e)
{
ControlGenerator generate = new ControlGenerator(this);
//9 TextBoxów i 9 Labelek, GroupBox będzie opatrzony tekstem Rejestracja
generate.GenerateRegisterControls(9, "Rejestracja");
}
Jeśli ktoś dopiero zaczyna swoją przygodę z C#, to informacje, które przedstawiłem z pewnością się przydadzą, albo przynajmniej wskażą drogę poszukiwań w google. AVE!

0
komentarzy