Jak patrzę ile tekstu wyszło, to jest to więcej roboty, niż chop siup dzień dwa :P, ale ciągle jest to w kategorii realne do wyklepania.
Większość aplikacji rozwiązuje podobne problemy pisząc singletona reprezentującego stan całej aplikacji. Ribbon, okna, status bark, commendy, toole itp. itd.
Ty masz chyba tylko okna ale i tak zaczął bym właśnie od takiej wydmuszki na wejściu. Nic to nie kosztuje i się nie zakopiesz.
Publiczny interfejs w tych warstwach pisał bym na interfejsach, bo istnieje smutna tendencja do tego ze kod jest użyty 2000 razy i nie da się już poprawić, np. implementacji z listy na hash set.
Klasa od okienek powinna posiadać kolekcje okien. Aktywne okno, eventy na przed po na zmianę: aktywnego okna, zamilkniecie, otwarcie. Itp. oraz metody, otwórz zamknij okno/ dialog.
Bardzo przydatne będzie jeśli każde okno będzie miało własny unikalny indetyfikator.
Metoda do otwierania okienek wyglądała by przykładowo tak ITwójInterfejsOkna OpenToolWIndow(string title, string id, IFrameworkElement element , ITwójInterfejsOkna parent = null). Zamiast IFrameworkElement możesz dać dowolny inny interfejs WPF lub własny który da się wyświetlić w kontrolce.
Nie głupim pomysłem było by na dzień dobry wydzielić logikę, od ustawiania pozycji okien do osobnej klasy. Wiec gdy pojawi się pomysł zapisywania pozycji itp, miałbyś już dobry punkt wyjścia.
Warto zauważyć ze większość okienek ma 2 lub 3 hierarchie okienek. Główne, pomocnicze i normalne. Np. visual ma files, tools, i czasem normalne dialogi.
Ty będziesz musiał utrzymywać 2 stany, ostatnio używany tool lub okno główne, oraz ostatnio używane okno główne. Wszystko z eventami, przed po w trakcie. Zgranie tego ładnie z focusem WPF, jest nie trywialne, ale nie ma tragedii.
Wysoko poziomowo nie potrzebujesz dużo więcej, ew. jakiś interfejs na okno żeby dało rade nimi sterować wysokość szerokość styl.
Implantacje formy zrobiłbym tak:
0 czytasz jak działają eventy drag-drop i jak przekazywać dane, do wygooglowania
0.1 Przeczytaj jak działają viewModele, i jak bindować dane. Wystarczy Ci najprostsza wersja.
0.2 Znajdz najprostsza możliwą wersje InotifyProertyChanged i napisz 'code snippset' na tworzenie propsów, wywołujących ten event.
1 - Piszesz kontrolkę która przypomina tab-control, ze scrolami, z możliwością ustawiania listy tabów lewo-prawo-góra,-dół, przesuwania ich lewo prawo i co Ci sie tam podoba, oraz z możliwością dodawania kontrolek. które wyświetlana się w środku. Przydatny pewnie będzie event tabDrabbed albo cos takiego. To ma być taki koń roboczy dla Twojej appki.
2 - piszesz kontrolkę która ma 5(czasem wiecej) pojawiających się kwadracików gdy dragujesz nad nia właściwe dane*. Na drop : jeśli nie ma tam nic jeszcze dodajesz kontrolkę 1), i sterujesz jej wyglądem, jeśli jest dodajesz kolejnego taba do niej. Implementacja to proscizna, kilka kwadracików(tez możesz jako kontrolki napisać) oraz grid ze spliterami(to do rozciągania). Jeśli nic nie ma w danym celu dajesz romiar na 0 i widok na collapsed. To koń roboczy numer 2.
- Prościej może być ustawić stan, `przerzucam okno ABC'
3 - Piszesz kontrolkę reprezentującą okienko dokowane, z pinem, eventami na odpinanie, zamykanie, ciagniecie za tytuł, zawiara w sobie i steruje kontrolką nr 2
4 - piszesz kontrolkę i logike do reprezentacji okienka(NIE OKIENKO), minimalizacją, przesuwaniem itp. rozmiarem itp. itd. zawiera w sobie i steruje kontrolką nr 2
5 - Piszesz kontrolkę która będzie siedzieć w twoim main-window, miedzy ribbonem, a status barem. Zawierać będzie w sobie kontrolkę nr.1 jako taki punkt startowy. to jest miejsce gdzie możesz dodać wsparcie dla alt+tab, szukajek itp.
Komunikacje miedzy kontrolkami, mozna napisać na kilka sposobów, ale zanim to bardzo ważna uwaga, 1,2,3,4, i pewnie 5, to nie jest publiczne API. Nie bawisz się wzorce, projektowe, rzeźbienie w XAML'u. nie trywialne bindingi danych, wyrafinowane struktury danych. Nie mówię ze masz robic lipe. To że zamiast pisać jednego wielkiego bloba masz 5 kontroleczek jednego przeznaczenia, daje Ci fajne możliwości. W code behind piszesz kod, odpowiedzialny za pozycjonowanie elementów, dodawnie odejmowanie kontrolek, ale tylko tego aspektu wizualnego lub frameworkowego. Jak musisz coś przesunąć o 5px, przesuwasz, podpinasz event handlary i delegujesz je dalej, ale nie robisz zadnej logiki stricte.
Przy takim podejściu uzyskamy wszystkie cegiełki które są potrzebne, żeby poskładać nasz system okienkowy. Zostaje problem skomunikowania tego wszystkiego razem.
Ogólnie widzę dwie opcje:
A) eventami przerzucasz informacje na najwyższy poziom, tj. nr 6. tam wszystko ogarniasz, a kontrolkami niżej sterujesz korzystając z referecji do nich. Zaletą jest to zę to najprostsze podejście które pozwoli uniknąć rozrzucenia, logiki i haków wszędzie i byle jak. Wadą jest to zę możesz skończyć z 1000 liniami sterującymi wszystkim naraz, ale nie musisz.
B) Możesz napisać view modele. Głowna kontrolka miała by swój viewModel, a każde dziecko, dostawało by dedykowany dla siebie przy tworzeniu. Kontrolki do view modelu przekazywały by informacje, zaczęto przesuwać, kliknięto na tab. A view model, przekazywał by te informacje, do modelu czyli tego singletna od którego zaczynaliśmy, oraz sterował kontrolkami, np. wysmażając nie aktywne okna lub przenosząc controlki z zadokowanego okna do okna pływającego.
I w drugą stronę, gdy w modelu, ktoś wywoła aktywuj mi okno, view model przestawi widok jak trzeba.
Jako model przekazujesz faktyczną implementacje, singletona od okienek lub wewnętrzy interfejs który pozwala na więcej.
Jak wszystko pójdzie sprawnie dostaniesz, UI w którym możesz wysterować absolutnie wszystkim, co do pixela, ViewModele z grupują logikę w jednym miejscu, pozwolą troche reuzyć kod i ochronią Cię przed tygodniami debugowania scenariuszy typu: jak ustawiam to w UI to leci taki event, na co reaguje tak i tak, co wywołuje kolejny event.. (wystarczy dać flagę, ze to rozróżniającą input od usera i ten wywołany z kodu). A publiczny interface będzie ładnie z enkapsulowany interfejsem.