Konwersja WebForms do WinForms

0

Cześć wszystkim!
Planuje konwersję mojej aplikacji internetowej do wersji lokalnej "okenkowej" w związku z tym chciałbym się zapytać jak są realizowane odpowiednie funkcjonalności. Jakim odpowiednikiem dla "widoków"/funkcjonalnosci (strona.aspx), funkcji (strona.aspx.cs) są te, które znajdują się w WinApplication (lub podobnym)? Czy jest jakiś prosty sposób na konwersję jednej formy programu w drugi?

2

Odpowiednikiem strony jest formularz (ang. form), zazwyczaj składa się z dwóch partial class, jedna generowana automatycznie przez designer (zmiany w niej są aktualizowane przez designer, więc jej nie ruszamy raczej samemu) i drugi partial do dopisywania handlerów akcji.

Neosphoros napisał(a):

Czy jest jakiś prosty sposób na konwersję jednej formy programu w drugi?

Pisanie w sposób niezależny od warstwy prezentacji na pewno ułatwia. Jeśli chodzi o same kontrolki to nie sądzę.

0
Saalin napisał(a):

Odpowiednikiem strony jest formularz (ang. form), zazwyczaj składa się z dwóch partial class, jedna generowana automatycznie przez designer (zmiany w niej są aktualizowane przez designer, więc jej nie ruszamy raczej samemu) i drugi partial do dopisywania handlerów akcji.

Czyli przekierowanie do określonego formularza odbywa się tak jak przekierowanie do strony za pomocą odnośnika lub handlera akcji tak jak odnośnik w html lub funkcja w strona.aspx.cs?

Pisanie w sposób niezależny od warstwy prezentacji na pewno ułatwia. Jeśli chodzi o same kontrolki to nie sądzę.

Co oznacza "pisanie w sposób niezależny od warstwy prezentacji"?

3
Neosphoros napisał(a):

Czyli przekierowanie do określonego formularza odbywa się tak jak przekierowanie do strony za pomocą odnośnika lub handlera akcji tak jak odnośnik w html lub funkcja w strona.aspx.cs?

Nie. Okno główne zazwyczaj tworzy okna potomne, a okna potomne coś robią i zwracają wyniki. Popatrz na dowolną aplikację okienkową i zastanów się jak działa. Masz jakiś button, klikasz, otwiera się okienko, tam coś robisz, klikasz OK, okno się zamyka.

Neosphoros napisał(a):

Co oznacza "pisanie w sposób niezależny od warstwy prezentacji"?

Zazwyczaj większość kodu, szczególnie tego interesującego, jest niezależna od tego czy to będzie aplikacja konsolowa, okienkowa czy webowa. Jeśli masz logikę aplikacji poukrywaną w handlerach eventów kontrolek to robisz to źle. Jeśli logikę masz zupełnie gdzie indziej to kolejne platformy ma się niskim kosztem.
Najprostszy sposób wymuszenia separacji to wydzielenie logiki domenowej do oddzielnego projektu i nie dodawanie tam referencji do projektów infrastrukturalnych/prezentacyjnych, jak WebForms czy WinForms. Drugi sposób to pisanie testów, bo bez separacji nie da się ich praktycznie pisać.

0

Zazwyczaj większość kodu, szczególnie tego interesującego, jest niezależna od tego czy to będzie aplikacja konsolowa, okienkowa czy webowa. Jeśli masz logikę aplikacji poukrywaną w handlerach eventów kontrolek to robisz to źle. Jeśli logikę masz zupełnie gdzie indziej to kolejne platformy ma się niskim kosztem.
Najprostszy sposób wymuszenia separacji to wydzielenie logiki domenowej do oddzielnego projektu i nie dodawanie tam referencji do projektów infrastrukturalnych/prezentacyjnych, jak WebForms czy WinForms. Drugi sposób to pisanie testów, bo bez separacji nie da się ich praktycznie pisać.

Czyli to tak jak próba zagnieżdżania logiki w kodzie html/aspx (hipotetycznie, jeśli taka opcja by istniała) lub zawarcie w odrebnym piku cs, z czego druga opcja jest tą właściwą. Czy tak?

1
Neosphoros napisał(a):

Czyli to tak jak próba zagnieżdżania logiki w kodzie html/aspx (hipotetycznie, jeśli taka opcja by istniała) lub zawarcie w odrebnym piku cs, z czego druga opcja jest tą właściwą. Czy tak?

Robienie tam więcej niż absolutnie minimum w takim strona.aspx.cs czy formularzu jest błędem. Kod faktycznie wykonujący logikę powinien być w innym miejscu, tak, żeby dało się go użyć bezpośrednio w testach czy aplikacji konsolowej.

0
Saalin napisał(a):
Neosphoros napisał(a):

Czyli to tak jak próba zagnieżdżania logiki w kodzie html/aspx (hipotetycznie, jeśli taka opcja by istniała) lub zawarcie w odrebnym piku cs, z czego druga opcja jest tą właściwą. Czy tak?

Robienie tam więcej niż absolutnie minimum w takim strona.aspx.cs czy formularzu jest błędem. Kod faktycznie wykonujący logikę powinien być w innym miejscu, tak, żeby dało się go użyć bezpośrednio w testach czy aplikacji konsolowej.

To gdzie indziej niż w strona.aspx.cs można umieszczać kod?

2

Wszędzie? W osobnych klasach, w osobnych projektach, w osobnych paczkach. Nie mowa, żeby kodu w takim aspx.cs nie było w ogóle - dla każdej akcji powinna być z reguły jedna linijka, która wywołuje akcje zdefiniowane gdzieś indziej.

0
Saalin napisał(a):

Wszędzie? W osobnych klasach, w osobnych projektach, w osobnych paczkach. Nie mowa, żeby kodu w takim aspx.cs nie było w ogóle - dla każdej akcji powinna być z reguły jedna linijka, która wywołuje akcje zdefiniowane gdzieś indziej.

Czy więc oznacza to, że strona.aspx.cs może zawierać odnośnik do innego pliku z zdefiniowanymi akcjami? W jaki sposób? Jak to wygląda?

3

Tak - kod sobie dzielisz na klasy, które robią odpowiadające rzeczy. Twoje pliki .cs "widzą" inne klasy z twojego projektu, a nawet z innych projektów (np. wspólnych dla kilku systemów), o ile masz poprawnie dodane referencje.

Przykładowo, musisz w WebForms wyświetlić użytkownikowi wartość zapisaną gdzieś w bazie danych. Robisz sobie klasę połączenia do bazy, ew. klasy które mapują bazę danych na obiekty C# (ORM) i dzięki temu po stronie twojej obsługi przycisku masz tylko coś takiego:

private void Button_Click(object sender, EventArgs e)
{
    var dbconn = DatabaseConnection.Connect();
    var lastClientId = dbconn.Clients.GetLastClientId();
    
    textBoxLastClientId.Text = lastClientId;
}

I teraz zmień to na Console.WriteLine(lastClientId) i już masz aplikację, która coś prezentuje w konsoli.

Chodzi o to, aby "widok" robił jak najmniej - może wybierać dane z bazy i je prezentować w kontrolkach, ale już samym połączeniem, przetwarzaniem danych, zapisywaniem i tak dalej niech zajmują się inne klasy.

2

Szczerze... to bym chyba wolał zrobić konwersję do Blazora z całkowitym oddzieleniem logiki od widoku - bardziej przyszłościowe i chyba szybsze!

2
Neosphoros napisał(a):

Czy więc oznacza to, że strona.aspx.cs może zawierać odnośnik do innego pliku z zdefiniowanymi akcjami? W jaki sposób? Jak to wygląda?

Programowanie to nie jest pisanie plików lecz funkcji, struktur danych i klas. Kod odpowiedzialny za logikę biznesową (czyli to, co Twoja aplikacja ma robić dla jej użytkowników) powinien znajdować się w klasach, które nie są związane z konkretną technologią GUI. Po pierwsze dlatego, że tak jest łatwiej go przetestować automatycznie, po drugie dlatego, że łatwiej go użyć ponownie - np. tworząc inne GUI, jak Ty chcesz to zrobić teraz.

Kristof napisał(a):

Szczerze... to bym chyba wolał zrobić konwersję do Blazora z całkowitym oddzieleniem logiki od widoku - bardziej przyszłościowe i chyba szybsze!

Być może. Ale w ogólności to, co autor chce osiągnąć nie jest problemem. Wystarczyłoby od początku zastosować wzorzec MVP, aby nawet logika prezentacji została taka sama, jedyne co trzeba by było zaimplementować to nowe formularze implementujące interfejsy widoków.

0
somekind napisał(a):
Neosphoros napisał(a):

Czy więc oznacza to, że strona.aspx.cs może zawierać odnośnik do innego pliku z zdefiniowanymi akcjami? W jaki sposób? Jak to wygląda?

Programowanie to nie jest pisanie plików lecz funkcji, struktur danych i klas. Kod odpowiedzialny za logikę biznesową (czyli to, co Twoja aplikacja ma robić dla jej użytkowników) powinien znajdować się w klasach, które nie są związane z konkretną technologią GUI. Po pierwsze dlatego, że tak jest łatwiej go przetestować automatycznie, po drugie dlatego, że łatwiej go użyć ponownie - np. tworząc inne GUI, jak Ty chcesz to zrobić teraz.

Kristof napisał(a):

Szczerze... to bym chyba wolał zrobić konwersję do Blazora z całkowitym oddzieleniem logiki od widoku - bardziej przyszłościowe i chyba szybsze!

Być może. Ale w ogólności to, co autor chce osiągnąć nie jest problemem. Wystarczyłoby od początku zastosować wzorzec MVP, aby nawet logika prezentacji została taka sama, jedyne co trzeba by było zaimplementować to nowe formularze implementujące interfejsy widoków.

To czy oznacza to, że jest możliwość wskazania z ścieżki zewnętrznej - plik (lub pliki) w których zawierała by się logika funkcjonowania zbudowana już wcześniej podczas np tworzenia wcześniejszych projektów?

0

Nie ze ścieżki (bo programy w C# to nie są połączone ze sobą pliki) lecz z projektu bądź skompilowanego assembly (np. dll).
Ale tak, jest to możliwe. Co więcej, cały świat programistyczny tak działa.

0
somekind napisał(a):

Nie ze ścieżki (bo programy w C# to nie są połączone ze sobą pliki) lecz z projektu bądź skompilowanego assembly (np. dll).

Ale tak, jest to możliwe. Co więcej, cały świat programistyczny tak działa.

No to już nie wiem czy się da czy nie :D
Można wskazać w WebApp/WebForms (lub WinApp/WinForms) ścieżkę z której ma pobierać plik (lub pliki) z logiką programu czy każdorazowo to logikę trzeba kopiować do folderu z nowym projektem i zmieniać mu nazwę na taki by był zbieżny z plikiem .aspx (lub odpowiednikiem dla WinApp/WinForms)?

Czy pliki z logiką można dzielić na części/kilka plików?

1

To ja powtórzę i uściślę.

Przede wszystkim programowanie w C# nie polega na pisaniu plików tylko na pisaniu klas, które zawierają metody (funkcje). Fizycznie te klasy i metody umieszcza się w plikach, ale do elementów kodu nie odwołuje się po nazwach plików lecz po nazwach klas i metod. Po prostu przestań myśleć plikami, zacznij kodem, to znacznie ułatwi zrozumienie interakcji między elementami kodu.

I teraz - w ramach jednej solucji w Visual Studio możesz mieć wiele projektów. Nic nie stoi na przeszkodzie, aby klasy związane z logiką domenową umieścić w jednym projekcie, GUI WebForms w drugim, GUI WinForms w trzecim. Jeśli do projektów GUI doda się referencje do projektu logiki domenowej, to będzie można wykorzystywać dokładnie ten sam kod biznesowy w obu aplikacjach.

0
somekind napisał(a):

To ja powtórzę i uściślę.

Przede wszystkim programowanie w C# nie polega na pisaniu plików tylko na pisaniu klas, które zawierają metody (funkcje). Fizycznie te klasy i metody umieszcza się w plikach, ale do elementów kodu nie odwołuje się po nazwach plików lecz po nazwach klas i metod. Po prostu przestań myśleć plikami, zacznij kodem, to znacznie ułatwi zrozumienie interakcji między elementami kodu.

Ale, żeby wskazać nazwę klasy lub metody to trzeba wskazać nazwę pliku w którym one się znajdują, czyż nie? "Plik" dla mnie ma znaczenie ogólne.

I teraz - w ramach jednej solucji w Visual Studio możesz mieć wiele projektów. Nic nie stoi na przeszkodzie, aby klasy związane z logiką domenową umieścić w jednym projekcie, GUI WebForms w drugim, GUI WinForms w trzecim. Jeśli do projektów GUI doda się referencje do projektu logiki domenowej, to będzie można wykorzystywać dokładnie ten sam kod biznesowy w obu aplikacjach.

Ale załóżmy, że nie ma się jeszcze gotowych projektów z gotową logiką lub interfejsami GUI, ale ma się pojedyncze pliki z gotową (przykładową) logiki programów, to czy konieczne jest utworzenie projektów dla tych plików tylko po to by wskazać referencją - ten "niby projekt"? Nie można wskazać po prostu zewnętrznego folderu z "pomocnymi" plikami logiki (lub klasami jak wolisz)?

0

W normalny sposób nie.

0
somekind napisał(a):

W normalny sposób nie.

To aż dziwne, bo wydawać by się mogło, że byłoby to niesamowicie przydatne. Bo po co niby miałbym wskazywać cały projekt, który zawierać będzie np tylko jeden potrzebny plik/klasę skoro inny i tak korzystałby tylko z pewnych (kilku) plików/klas?

A czy jest przynajmniej możliwość deklaracji większej ilości plików (przepraszam za używanie prawdopodobnie błędnej nomenklatury) logiki w plikach .aspx? Na zasadzie:

CodeBehind="Default01.aspx.cs; kopiowanie_plikow.aspx.cs; obsluga_bd.aspx.cs"
1

Nie można - jeden formularz - jeden "Code Behind". Nie za bardzo w ogóle rozumiem jakby to miało działać w ogóle.

Ogólnie - przestań myśleć o plikach. To nie C. Kompletnie nie ma znaczenia czy klasa jest w takim pliku czy innym, każda klasa w jednym projekcie ma dostęp do każdej innej klasy w tym samym projekcie, nieważne w jakim pliku, nie trzeba podawać nazw tych plików, w zasadzie wszystko mogło by być w jednym i też by działało, a dzielimy na kilka, aby nam było wygodniej.

0
Ktos napisał(a):

Nie można - jeden formularz - jeden "Code Behind". Nie za bardzo w ogóle rozumiem jakby to miało działać w ogóle.

Ogólnie - przestań myśleć o plikach. To nie C. Kompletnie nie ma znaczenia czy klasa jest w takim pliku czy innym, każda klasa w jednym projekcie ma dostęp do każdej innej klasy w tym samym projekcie, nieważne w jakim pliku, nie trzeba podawać nazw tych plików, w zasadzie wszystko mogło by być w jednym i też by działało, a dzielimy na kilka, aby nam było wygodniej.

Ale w tym wypadku mi chodzi o wygodę w dostępie do informacji i przejrzystość kodu. Przecież łatwiej byłoby podzielić kod na kilka części by nie musieć przeszukiwać tych kilku tysięcy linijek kodu w jednym pliku.

Bo niby dlaczego (czysto teoretycznie) klasa partial nie mogłaby być podzielona na kilka plików cs jeśli tylko przyjmowała by tę samą nazwę?

1

Bo niby dlaczego (czysto teoretycznie) klasa partial nie mogłaby być podzielona na kilka plików cs jeśli tylko przyjmowała by tę samą nazwę?

Może być w kilku plikach. I chyba nawet da się zrobić takie coś, co jak rozumiem chcesz osiągnąć - aby jednemu plikowi .aspx odpowiadało kilka plików .cs. Nie mam teraz ochoty testować, ale na oko powinno działać. Z tym, że nie musisz w ogóle mówić, że to jest w tym pliku i tym pliku i tym pliku - kompilator sam to ogarnie, bo kompiluje wszystkie pliki od razu w jedno.

Ale!

SRP - Single Responsibility Principle. Jedna jednostka kodu (np. funkcja lub klasa) powinna odpowiadać za jedną rzecz. Nie za obsługę zdarzeń formularza, i jeszcze komunikację z bazą danych, i jeszcze zapisywanie do plików i jeszcze logowanie błędów i jeszcze generowanie PDF-ów i jeszcze robienie herbaty. Klasa formularza powinna obsługiwać zdarzenia formularza, klasa bazy danych komunikuje się z bazą danych, a klasa herbaty robi herbatę. One wzajemnie mogą się uruchamiać i komunikować - ale nie muszą wiedzieć w jakich są plikach, bo C# w zasadzie to nie obchodzi, bo wszystko się kompiluje w jednym projekcie do jednego wielkiego pliku DLL.

Ale w tym wypadku mi chodzi o wygodę w dostępie do informacji i przejrzystość kodu. Przecież łatwiej byłoby podzielić kod na kilka części by nie musieć przeszukiwać tych kilku tysięcy linijek kodu w jednym pliku.

No to właśnie wracamy do poprzedniego punktu - dzielimy na mniejsze klasy, odpowiadające za pojedynczą odpowiedzialność, aby nasze klasy nie były zbyt długie i nie miały tysięcy linii kodu w jednym pliku ;)

1
Neosphoros napisał(a):

To aż dziwne, bo wydawać by się mogło, że byłoby to niesamowicie przydatne. Bo po co niby miałbym wskazywać cały projekt, który zawierać będzie np tylko jeden potrzebny plik/klasę skoro inny i tak korzystałby tylko z pewnych (kilku) plików/klas?

To jest niesamowite, że już rozwiązujesz nieistniejące zupełnie w języku problemy, kiedy Twoim podstawowym problemem jest niezrozumienie idei podziału kodu na klasy, tworzeniu obiektów i odwoływaniu się do nich. Może warto na chwile odpuścić Formsy jedne i drugie, a nadrobić braki w podstawach?

Neosphoros napisał(a):

Bo niby dlaczego (czysto teoretycznie) klasa partial nie mogłaby być podzielona na kilka plików cs jeśli tylko przyjmowała by tę samą nazwę?

Albo nie zrozumiałem o co Ci chodzi albo partial tak faktycznie działa.

0
Saalin napisał(a):
Neosphoros napisał(a):

To aż dziwne, bo wydawać by się mogło, że byłoby to niesamowicie przydatne. Bo po co niby miałbym wskazywać cały projekt, który zawierać będzie np tylko jeden potrzebny plik/klasę skoro inny i tak korzystałby tylko z pewnych (kilku) plików/klas?

To jest niesamowite, że już rozwiązujesz nieistniejące zupełnie w języku problemy, kiedy Twoim podstawowym problemem jest niezrozumienie idei podziału kodu na klasy, tworzeniu obiektów i odwoływaniu się do nich. Może warto na chwile odpuścić Formsy jedne i drugie, a nadrobić braki w podstawach?

Nie umiem w inny sposób. Nie jestem typem "czytacza" i nie czułbym ognia jeśli musiałbym przedzierać się przez strony książki po to by dopiero na ostatniej stronie znaleźć rozwiązanie problemu. Bardziej wolę analizować kod i na jego podstawie starać się zrozumieć to czego konkretnie szukam. Wielość informacji w Internecie na szczęście mi w tym pomaga.

Neosphoros napisał(a):

Bo niby dlaczego (czysto teoretycznie) klasa partial nie mogłaby być podzielona na kilka plików cs jeśli tylko przyjmowała by tę samą nazwę?

Albo nie zrozumiałem o co Ci chodzi albo partial tak faktycznie działa.

Może działa, ale chyba nie w sposób o jaki mi chodzi... a przynajmniej nie znalazłem rozwiązania:

https://stackoverflow.com/questions/23996069/how-to-create-multiple-code-behind-file-for-aspx-page

Edit:

To https://social.msdn.microsoft.com/Forums/en-US/7fd970d2-05da-4b6d-8dfc-7634ee45566f/splitting-the-code-behind-file-into-multiple-files?forum=aspgettingstarted chyba jednak rozwiązuje problem?

Nie rozumiem jednak w jaki sposób aplikacja wie, że ma czytać plik MyPartialClass.cs . Gdzieś go trzeba zadeklarować?

1

Nie rozumiem jednak w jaki sposób aplikacja wie, że ma czytać plik MyPartialClass.cs . Gdzieś go trzeba zadeklarować?

W momencie kiedy kompilujesz swój projekt wszystkie pliki, które wchodzą w skład projektu są łączone "w jedno". Więc dopóki dodajesz plik do projektu w Visual Studio nic nie musisz deklarować, "samo" się zrobi. Skompilowany projekt nie ma odniesień do plików źródłowych.

(więc tak naprawdę "deklarujesz" dodając plik do projektu VS)

1

nie wiem czy o to ci chodzi ale w WinForms oddzielasz widok od logiki używając wzorca MVP https://www.google.com/search?q=mvp+winforms ; w WPF - MVVM.
Piszesz presenter / viewmodel który skala logikę z widokiem a logikę możesz trzymać całkiem osobno. W ten sposób z widokiem trzymasz tylko minimum niezbędnego kodu powiązanego z samym widokiem (nie ma sensu go oddzielać) a osobno masz dll-kę z logiką którą teoretycznie przy dobrej separacji możesz współdzielić w aplikacji webforms i winforms

0
Ktos napisał(a):

Nie rozumiem jednak w jaki sposób aplikacja wie, że ma czytać plik MyPartialClass.cs . Gdzieś go trzeba zadeklarować?

W momencie kiedy kompilujesz swój projekt wszystkie pliki, które wchodzą w skład projektu są łączone "w jedno". Więc dopóki dodajesz plik do projektu w Visual Studio nic nie musisz deklarować, "samo" się zrobi. Skompilowany projekt nie ma odniesień do plików źródłowych.

(więc tak naprawdę "deklarujesz" dodając plik do projektu VS)

Hmmm. Ok. Mądry ten VS.
Czyli jeśli w default.aspx.cs wypisze warunek powiązujący wybór z DDL, a później dodam do projektu nowy plik klasy .cs o tej samej nazwie klasy, to po dodaniu funkcji button_click bedzie ona mogła wiązać akcję DDL z default.aspx.cs?

To samo będzie się działo z innymi plikami aspx.cs o ile tylko klasa ich będzie mieć taką samą nazwę co nowododany plik cs?

0
Neosphoros napisał(a):

To aż dziwne, bo wydawać by się mogło, że byłoby to niesamowicie przydatne. Bo po co niby miałbym wskazywać cały projekt, który zawierać będzie np tylko jeden potrzebny plik/klasę skoro inny i tak korzystałby tylko z pewnych (kilku) plików/klas?

Z tego, co udostępnia .NET też używasz mniejszości, pewnie nawet nie 1% klas. Jaki w tym widzisz problem?

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