Aplikacja dla freelancerów- wstępny schemat modelu

Aplikacja dla freelancerów- wstępny schemat modelu
S-cat
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Postów:83
0

Hey ;)

Zabrałem się za projektowanie apki dla freelancerów. Planuję wykorzystać WPF oraz język C#, stosując wzorzez MVVM. Problem w tym, że nie do końca rozumiem, jak ten wzorzec działa, więc zacząłem od modelu. Nie do końca jestem pewien, co jeszcze będzie potrzebne, więc zamieściłem chwilowo podstawowe obiekty. Mam kilka pytań:

  1. Jeśli chodzi o dokumenty, to czy encja dokumentu powinna posiadać metodę Print() czy powinien zajmować się tym jakiś manager? Jeśli tak, jak go skonstruować? Chciałbym to zrobić tak, żeby móc w przyszłości dodawać inne dokumenty i potem taki obiekt tylko przesłać do tej samej funkcji drukującej.

  2. Chciałbym zrobić tą apkę tak, by była wielojęzyczna. Czy takie pomocnicze klasy, które wypełniają treść okienek i dokumentów należą do modelu? Zasoby językowe znajdowałyby się poza bazą danych.

  3. ContentFiller należy do warsty VM? W zasadzie ma on za zadanie zaciągnięcie plików językowych i odpowiednie wypełnianie okienek i dokumentów (prawdopodobnie będzie to podzielone na więcej klas).

Czegoś tutaj jeszcze w tym modelu wg was brakuje? Projekt wydaje się być sporym wyzwaniem, a powiedzmy, że jestem raczej średniozaawansowany, a chciałbym to wykonać naprawdę dobrze.

Zapraszam do dyskusji. :)

PS
Jeszcze jedno pytanie, aby się upewnić, czy dobrze rozumuję:

Każdy widok powinien mieć odpowiadającą mu klasę VM, a ta klasa zawiera właściwości, które są prezentowane na widoku (i zbindowane z nimi). Prawda czy fałsz? :)

edytowany 1x, ostatnio: S-cat
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1
S-cat napisał(a):
  1. Jeśli chodzi o dokumenty, to czy encja dokumentu powinna posiadać metodę Print() czy powinien zajmować się tym jakiś manager? Jeśli tak, jak go skonstruować? Chciałbym to zrobić tak, żeby móc w przyszłości dodawać inne dokumenty i potem taki obiekt tylko przesłać do tej samej funkcji drukującej.

Utwórz klasę serwisową obsługującą dokumenty i wstrzyknij ją do VM za pomocą mechanizmu IoC (Unity Container albo Ninject). Będzie posiadać funkcję drukowania dokumentów różnych typów przekazanych za pomocą interfejsu np: public void Print(IDocument document);

S-cat napisał(a):
  1. Chciałbym zrobić tą apkę tak, by była wielojęzyczna. Czy takie pomocnicze klasy, które wypełniają treść okienek i dokumentów należą do modelu? Zasoby językowe znajdowałyby się poza bazą danych.

Nie. Model nie widzi widoku. Język GUI to część widoku więc zmiana języków nie powinna być częścią modelu, a osobnym mechanizmem. Widok jest wypełniany przez własności VM, które uzupełniasz za pomocą modelu. Model to logika biznesowa.

S-cat napisał(a):
  1. ContentFiller należy do warsty VM? W zasadzie ma on za zadanie zaciągnięcie plików językowych i odpowiednie wypełnianie okienek i dokumentów (prawdopodobnie będzie to podzielone na więcej klas).

ContentFilter może należeć do klasy serwisowej obsługującej dokumenty. Możesz tam zrobić metodę filtrującą, np. IList<IDocument> GetDocuments(string name, strine header);. Same parametry filtrowania przekażesz przez VM. Co do ustawień językowych to napisałem już wyżej.

S-cat napisał(a):

Każdy widok powinien mieć odpowiadającą mu klasę VM, a ta klasa zawiera właściwości, które są prezentowane na widoku (i zbindowane z nimi). Prawda czy fałsz? :)

Poniekąd tak. Widok powinien mieć własny VM. Nie jest to jednak reguła, ponieważ pojedyncza kontrolka również może mieć swój VM jako DataContext. Jeżeli mówimy o widoku jako o całym oknie to można powiedzieć, że nie zawsze. Jeżeli o wszystkim co ma cokolwiek wspólnego GUI to tak. Ciekawostka: Nie jest regułą trzymanie pustego code-behind. Korzystając z MVVM c-b możesz spokojnie wykorzystać do obsługi zdarzeń, które wydelegujesz z VM np. wyświetlania messageboksów.

edytowany 8x, ostatnio: grzesiek51114
SO
Unity Container albo Ninject, albo AutoFac albo StructureMap :P
grzesiek51114
grzesiek51114
@some_ONE fajne te nazwy wymyślają w ogóle. Weź taki Ninject: wiadomo z nazwy, że chodzi o dependency injection, a nazwa zawiera nindzię i fajnie wygląda :D
S-cat
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Postów:83
0
grzesiek51114 napisał(a):

Utwórz klasę serwisową obsługującą dokumenty i wstrzyknij ją do VM za pomocą mechanizmu IoC (Unity Container albo Ninject). Będzie posiadać funkcję drukowania dokumentów różnych typów przekazanych za pomocą interfejsu np: public void Print(IDocument document);

Ten interfejs, o którym mówisz to u mnie w zasadzie klasa abstrakcyjna Document. Powinienem ją nim zastąpić?

grzesiek51114 napisał(a):

Nie. Model nie widzi widoku. Język GUI to część widoku więc zmiana języków nie powinna być częścią modelu, a osobnym mechanizmem. Widok jest wypełniany przez własności VM, które uzupełniasz za pomocą modelu. Model to logika biznesowa.

Skoro tak, to każdy VM powinien mieć właściwości odpowiadające za treść na kontrolkach, którą przy otwarciu okna, pobiera z zewnętrznych plików i binduje? Czy takie coś może wrzucić do c-b?

grzesiek51114 napisał(a):

ContentFilter może należeć do klasy serwisowej obsługującej dokumenty. Możesz tam zrobić metodę filtrującą, np. IList<IDocument> GetDocuments(string name, strine header);. Same parametry filtrowania przekażesz przez VM. Co do ustawień językowych to napisałem już wyżej.

Tutaj miałem na myśli ContentFiller, nie Filter. Taki content filler miałbym wstrzyknąć do VM? Czyli miałoby to postać np. interfejsu IFiller, z którego dziedziczą poszczególne wypełniacze, dla poszczególnego okna, a każdy VM miałby w sobie referencję do obiektu typu IFiller? Czy to zbędne udziwnienie?

PS
Czy gotowy dokument też jest widokiem? Faktury i umowy będą tak naprawdę templatką, wypełnianą szczególnymi już danymi z poziomu programu.

edytowany 1x, ostatnio: S-cat
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1
grzesiek51114 napisał(a):

Ten interfejs, o którym mówisz to u mnie w zasadzie klasa abstrakcyjna Document. Powinienem ją nim zastąpić?

Tak. Nic nie stoi na przeszkodzie, żeby zrobić z tego interfejs z dostępnymi własnościami;

grzesiek51114 napisał(a):

Skoro tak, to każdy VM powinien mieć właściwości odpowiadające za treść na kontrolkach, którą przy otwarciu okna, pobiera z zewnętrznych plików i binduje?

Takie coś możesz spokojnie wrzucić do VM przy czym najlepiej utworzyć metody pobierające dane w ramach jakiegoś serwisu, który będzie obsługiwał większą część reszty. Tak żeby logicznie to się trzymało kupy. Taki serwis możesz np. wstrzyknąć do VM. Można też zrobić do tego osobną klasę etc... Cokolwiek byleby VM pozostał VM czyli klasą udostępniającą własności widokowi, a nie czymś co zawiera w sobie tonę logiki, którą można przecież przenieść do klas serwisowych (service classes).

grzesiek51114 napisał(a):

Tutaj miałem na myśli ContentFiller, nie Filter. Taki content filler miałbym wstrzyknąć do VM? Czyli miałoby to postać np. interfejsu IFiller, z którego dziedziczą poszczególne wypełniacze, dla poszczególnego okna, a każdy VM miałby w sobie referencję do obiektu typu IFiller? Czy to zbędne udziwnienie?

Aha. No to coś takiego nie musi być częścią VM, ponieważ steruje to bezpośrednio widokiem aplikacji. Można to wrzucić do eventu odpowiedzialnego za odczytywanie danej wersji językowej Twojego programu. Nie wiem czy mnie dobrze zrozumiesz po tym co napisałem więc posłużę się przykładem: Mam proszę ja Ciebie w swoim programie taki panel, który pokazuje mi aktualnie używane przez użytkownika filtry wyszukiwania. Po prostu gość wdzydza filtr, a informacja o tym jaki to filtr zostaje dodana w GUI w formie nieaktywnego guzika na pasku i w ten sposób user wie, że np. używa kaskadowo ileś tam filtrów (tak... wiem, że chodzi o filler - to tylko przykład hehe).

Teraz jak obsłużyć taką informację? Bardzo prosto. Mam wewnątrz VM takiego delegata: public delegate void ActivateFilterEventHandler(string filterName);. Na jego podstawie tworzę sobie event, który będzie się odpalał kiedy user użyje jakiegoś filtru: public event ActivateFilterEventHandler ActivateFilter;.

Super, teraz np. w komendzie należy zrobić jego wywołanie w momencie kiedy user użyje filtru:

Kopiuj
public ICommand UseFilter
{
	get
	{
		return new RelayCommand(
		()=>
		{
			// Some logic...
			if(this.ActivateFilter != null) this.ActivateFilter(this.SurnameFilter);
		},null);
	}
}

Tak odpalony event można obsłużyć w miejscu gdzie sterujemy widokiem czyli... w code-behind:)

Kopiuj
this.viewModel.ActivateFilter += (filterName) =>
{
	// Pseudo-code:
	var button = new Button();
	button.Content = filterName;
	button.IsEnabled = false;
	this.StackPanel.Children.Add(button);
}

Viola! GUI samo się układa. Projektant GUI decyduje w code-behind jakiego użyje sposobu na to, żeby pokazać userowi jakich użył filtrów. Ty jako projektant logiki pod spodem dostarczasz jedynie eventa, który transportuje dla GUI nazwę filtru :) Dlatego taki projektant użyje c-b zamiast XAML? Odpowiedź jest prosta: ilość nieaktywnych guzików, czy jakichkolwiek kontrolek z nazwą filtru nie jest z góry określona i nie da się tego zrobić przez XAML. Można do tego napisać sobie fabrykę kontrolek ustawiających filtry w GUI, do wyboru do koloru.

grzesiek51114 napisał(a):

Czy gotowy dokument też jest widokiem? Faktury i umowy będą tak naprawdę templatką, wypełnianą szczególnymi już danymi z poziomu programu.

Dokument też jest widokiem, owszem no, bo jakoś musi zostać wyświetlony ale pod spodem siedzi logika, którą zapewne trzeba będzie wrzucić do modelu.

edytowany 6x, ostatnio: grzesiek51114
S-cat
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Postów:83
0

Dzięki serdeczne, biorę się zatem za dalsze projektowanie. Pewnie się tu jeszcze odezwę. :)

S-cat
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Postów:83
0

Hey ;) Poszedłem za twoimi radami (w pewnym stopniu, nie przetrawiłem jeszcze wszystkiego, szczególnie ten fragment z eventami), ale doszedłem mniej więcej do takiego etapu (załącznik).
Co sądzicie?

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1

Bardziej chodzi o taką architekturę: http://imgur.com/a/uRGMk

Po pierwsze, do wszelkiej maści purystów UML'a: diagram jest mocno uproszczony, ponieważ chodziło o pokazanie wszystkiego najbardziej przejrzyście.

  • GUI Speciffic Layer jest warstwą zależną od interfejsu graficznego, czyli co sobie projektanci powymyślają to tam właśnie wrzucą. Chcesz tworzyć dynamicznie tonę przycisków w menu? Masz od tego fabryczkę i ona pozwoli Ci to zrobić w zależności od parametrów jakie jej zapodasz. Coś jak to co pokazywałem Ci w swoim poprzednim poście;

  • Model jak widzisz składa się nie tylko z prostych klas, opisujących tabelę w bazie danych ale także z usług, które wykonują całą logikę biznesową aplikacji. W tym wypadku tworzą dokument, drukują go odpowiednio najpierw formatując czy zwracają z bazy danych listę wszystkich dokumentów. Model jest dodatkowo dość abstrakcyjny czyli bogaty w interfejsy co pozwala dokładnie określić jakich cech i zachowań będzie potrzebowała klasa, która będzie dziedziczyła od tych interfejsów. Zyskasz dzięki temu możliwość np. zmiany silnika bazy danych, którego inne warstwy nawet nie zauważą. Będziesz sobie chciał z MySQL'a przejść na Postgresa? Proszę bardzo: interfejs determinuje co musi zostać zaimplementowane i kropka - musisz się dostosować.

  • GUI Independent Layer jest warstwą niezależną od widoku (Poniekąd, bo nie zawsze jest to prawda hehe. Trywialnym przykładem może być kontrolka PasswordBox, której nie da się zbindować bezpośrednio z powodu bezpieczeństwa i trzeba przesłać ją do VM jako np. parametr komendy.) czyli generalnie mówimy tutaj o ViewModelu, który dostarcza widokowi własności, może propagować eventy, które obsłużysz gdzie chcesz (np. w code behind) oraz oczywiście o Modelu. Widać dokładnie, że VM jest to warstwą pośrednia pomiędzy modelem, a widokiem. Widać również, że model nie wie nic o widoku.

  • CRUD Communication komunikacja z silnikiem bazy danych. Operacje typu Create, Read, Update, Delete, również za pomocą ORM'a rzecz jasna.

edytowany 4x, ostatnio: grzesiek51114
S-cat
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 2 lata
  • Postów:83
0

Dzięki wielkie- biorę się za jakiś kod, muszę w praktyce to przetestować, wtedy będę mieć pewnie więcej pytań. ;)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)