Temat: Co ze stylami kontrolek generycznych?

Od jakiegoś czasu walczę z mocno typowanymi kontrolkami. Generalnie kontrolki piszemy w ten sposób, że dziedziczą z Control, a style są aplikowane w pliku generic.xaml i matchowane po typie.
Ale co zrobić w przypadku gdy mam coś takiego :


public class ListaObiektow<T> : Control
{
public static readonly DependencyProperty KolekcjaObiektowProperty =
DependencyProperty.Register("KolekcjaObiektow", typeof(ICollection<T>), typeof(ListaObiektow<T>), new UIPropertyMetadata(null, OnKolekcjaObiektowPropertyChanged));

public ICollection<T> KolekcjaObiektow
{
get { return (ICollection<T>)GetValue(KolekcjaObiektowProperty); }
set { SetValue(KolekcjaObiektowProperty, value); }
}


static void OnKolekcjaObiektowPropertyChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{

}
}


Można oczywiście tak:

static ListaObiektow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListaObiektow<T>), new FrameworkPropertyMetadata(typeof(ListaObiektow<T>)));
}

ale nie ma jak powiedzieć, w xamlu, że TargetType jest ListaObiektow<T>. Jak sobie z tym poradzić?Jacek Tomaka edytował(a) ten post dnia 20.04.10 o godzinie 20:50

konto usunięte

Temat: Co ze stylami kontrolek generycznych?

W .Net 4.0 już można używać w xaml'u typów generycznych. Natomiast we wcześniejszych wersjach proponuję tak:

public class ListaObiektow :ListaObiektow<T>
{
}
W takiej postaci klasa nie traci swojej funkcjonalności a można śmiało zaimportować ListaObiektow do xaml.

Alternatywnie można to zrobić po stronie kodu proceduralnego.

Temat: Co ze stylami kontrolek generycznych?

Anna Bauza:
W .Net 4.0 już można używać w xaml'u typów generycznych. Natomiast we wcześniejszych wersjach proponuję tak:

public class ListaObiektow :ListaObiektow<T>
{
}
W takiej postaci klasa nie traci swojej funkcjonalności a można śmiało zaimportować ListaObiektow do xaml.

Alternatywnie można to zrobić po stronie kodu proceduralnego.

Tak właśnie się skończyło. Klasy ViewModel mieliśmy generyczne tak długo jak sie dało, na koniec musiały być jednak zamknięte, czyli to co proponujesz.

W ogóle zrezygnowaliśmy ze styli generycznych - style były tylko dla kontrolek niegenerycznych, pewien poziom "dziedziczenia" template'ów uzyskaliśmy dzięki następującej sztuczce:


<DataTemplate x:Key="KluczDlaKlasyBazowej">
<!-- tutaj bardzo duzy template dla klasy bazowej-->
</DataTemplate>
<DataTemplate DataType="{x:Type vm:KlasaDziedziczacaZBazowej1}">
<ContentControl Content="{Binding }" ContentTemplate="{StaticResource KluczDlaKlasyBazowej}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:KlasaDziedziczacaZBazowej2}">
<ContentControl Content="{Binding }" ContentTemplate="{StaticResource KluczDlaKlasyBazowej}"/>
</DataTemplate>


Jeśli chodzi o typy generyczne w xamlu w 4.0, to nadal są do niczego - typ musi być zamknięty.
Nie można powiedziec w xamlu:
JakasKlasaGeneryczna<T>: where T: KlasaBazowa
Mozna jedynie powiedziec JakasKlasaGeneryczna<Klasa>, co jest słabe.

konto usunięte

Temat: Co ze stylami kontrolek generycznych?

No tak.. Xaml posiada swoje ograniczenia często nie do przeskoczenia.
Borysław B.

Borysław B. Mgr inżynier
informatyki,
właściciel Matrix
Reliability

Temat: Co ze stylami kontrolek generycznych?

Pisze pracę magisterską używając WPF i ostatnio zastanawiałem się jak obejść problem braku dziedziczenia XAML-a po XAML-u. Miałem fajne okno podstawowe z funkcjonalnością i chciałem po nim dziedziczyć jak w WinForms.
Obszedłem ograniczenia w dość prosty sposób. Całą moją funkcjonalność bazową umieszczam w pliku jakisTemplateConstructor.cs

Otwieram plik i klasę jakisTemplateConstructor. Wygląd okien zapisuje w polu typu string. Dokładnie mówiąc zapisuję wygląd w XAML-u, który konwertuje ręcznie na string, dodając znaczek \ przed każdym " . Root-tag tego XAML-u to <DockPanel>, więc idealny kontener do osadzenia w nim absolutnie wszystkiego, co potrzeba.

Następnie string w czasie działania programu zamieniam na realny obiekt za pomocą obiektów klasy StringReader i XmlReader i podpinam funkcje pod odpowiednie zdarzenia już w czasie działania programu.Borysław Bobulski edytował(a) ten post dnia 05.03.11 o godzinie 23:54

Temat: Co ze stylami kontrolek generycznych?

Tylko że nie tędy droga.

WPF został zaprojektowany po to, żeby oddzielić role projektanta GUI od programisty. A co za tym idzie prezentację od logiki (inna sprawa to logika prezentacji ;D). Jak w Twoim rozwiązaniu chciałbyś przekazać designerowi xamla?

Lekarstwo, które proponujesz jest gorsze od choroby. Niestety w WPF nie da się osadzić okna w oknie, dlatego funkcjonalności trzeba zamykać w kontrolki.

Generalnie jeśli korzystasz z wzorca MVVM, nie piszesz prawie w ogóle kodu stojącego za XAML'em.
Jest "głupi" widok napisany w XAMLU, zdarzenia są podpinane poprzez komendy bindowane w Widoku z ModelWidoku. Implementacje tychże komend znajdują się bezpośrednio w ModeluWidoku - jeśli dotyczą stanu widoku, jeśli nie, to sa przekierowywane na metody logiki biznesowej w modelu.

A jak jest potrzebna bardziej złożona interakcja Widok, ModelWidok to zamyka się całość w kontrolkę i taki gotowy do użycia klocek używa się jak TextBlock.

I jeszcze jedno: używanie canvasa to jakaś zaszłość z widnows forms. Są zastosowania w których canvas ma sens. Np. jeśli kontrolka prezentuje mapę. Ale generalnie nie potrafię sobie wyobrazić sensownego użycia Canvasa mając DockPanel, StackPanel i Grid'a.
Borysław B.

Borysław B. Mgr inżynier
informatyki,
właściciel Matrix
Reliability

Temat: Co ze stylami kontrolek generycznych?

Już wyjaśniam. Dużo animacji robiłem w swoim życiu i Canvas jest rewelacyjny, bo jest "lekki" a dziecko osadzone na nim można łatwo przemieszczać zmieniając Canvas.Left, Canvas.Top dziecka. Dlatego zdziwiło mnie niepomiernie Twoje zdziwienie :)

Zwróć uwagę, że każdy Canvas wprowadza mi nowy, lokalny układ współrzędnych. Pozycja na Canvas jest liczona w double, nie tak jak w WinForms w integer. Zwróć uwagę, jak można łatwo napisać grę komputerową używając Canvas, czy bardziej złożoną kontrolkę z wieloma animacjami dzięki właściwościom Canvas. Czy teraz sobie potrafisz wyobrazić potężne zastosowanie Canvas?

Nie zgadzam się również z Twoją opinią o mojej metodzie. Uważam, że Twoja krytyka jest zbyt pospieszna i niesprawiedliwa. Uzasadniam:

1. Rolą projektanta GUI jest zrobienie w XAML-u podstawowego wyglądu okna. On to robi. Nie mieszam się w to. Nie odbieram mu pracy. Zamieniam później tylko XAML na string. Rola projektanta GUI od programisty jest oddzielona.

2. Nie biorę na siebie również pracy designera jeśli chodzi o wnętrze okna. Projektant robi UserControl, które jest wnętrzem okna. Ponieważ w oknie WPF bez problemu można osadzić UserControl. Dalej rola projektanta GUI od programisty jest oddzielona.

3. Co więcej. Mój sposób to na razie jedyny znany mi sposób by nie złamać zasady DRY i nie musieć za każdym razem kopiować XAML-a z podstawowym wyglądem okna w każdym nowo powstającym oknie. Bo co, jeśli postanowisz zmienić podstawowy wygląd okna? Wtedy musisz zmodyfikować XAML nawet dwudziestu okienek - i nigdy nie masz pewności, że czegoś po drodze nie zepsujesz. Zastanów się dobrze, czy moja metoda jest wciąż taka bez sensu?

Zdanie "Lekarstwo, które proponujesz jest gorsze od choroby" mnie wręcz uraziło, bo jestem wrażliwym, młodym człowiekiem.

Mógłbyś mi napisać coś więcej o MVVM, bo chcę wiedzieć, czy dobrze ten wzorzec rozumiem? Będę Ci wdzięczny :)Borysław Bobulski edytował(a) ten post dnia 31.01.11 o godzinie 03:36

Temat: Co ze stylami kontrolek generycznych?

Wrażliwy młody człowieku ;) Nie bierz do siebie moich uwag. Napisałem to, bo mam wrażenie, że masz mocny Formsowy background i próbujesz go przenieść do WPF. WPF to zupełnie inna bajka. Nie wykluczam, że kompletnie nie rozumiem problemu, który usiłujesz rozwiązać, ale mam wrażenie, że wyważasz otware drzwi.

W Forms wszystko jest Canvas'em + kotwice. WPF wspiera layout managery, które są wyjęte żywcem z Javy, a nie Formsów.
Zauważyłem,że developerzy mający doświadczenie w kodowaniu w Formsach wpadają w panikę zaczynając przygodę z WPF: gdzie mogę ustawić rozmiar mojej kontrolki?! Jak ustawić im pozycję?

Oczywiście. Canvasy mają swoje zastosowania. Ale pisząc normalne aplikacje użytkowe się ich nie wykorzystuje. Jeśli chciałbyś zrobić formularz do rozliczania podatku i używasz Canvasów do pozycjonowania texblockow i texboxów to mówię: nie tędy droga!!!

BTW: uważałbym z tym doublem do określania pozycji. Co prawda WPF używa doubli do określania pozycji, ale wątek renderujący już leci w single, co powoduje, że Twój "nowy układ współrzędnych" ma poważne ograniczenia i rozjeżdża się przy dużych wartościach współrzędnych gdy chcesz miec jednocześnie dużą precyzję. Tzn. gdy np na Canvasie chcialbys miec całą Polskę, ale chciałbyś się przybliżyć i dojrzeć Pałac Kultury.

To co proponujesz załatwia się tzw. lookless controls. Kontrolka nie definiuje wyglądu całkowicie, jej wygląd jest w domyślnym stylu (kontrolka tylko definiuje DefaultStyleKey, np. w Themes(albo gdzieś w rodzicu) definiuje się domyślny dla niej wygląd - styl). Pozwala to dziedziczyć klaski okien, co pozwala zmieniac zachowanie (a także w klasie pochodnej zmieniając wygląd jeśli trzeba - np. poprzez wspomniany DefaultStyleKey), jednocześnie pozwalając dowolnie definiować zawartość (poprzez ContentPresenter). Można w ten sposób zmienić wygląd wszystkich okien. Nie dotykając kodu.

Nie wyobrażam sobie edytowania wyglądu (widok zawiera nie tylko wygląd, ale też bindowania) poprzez zmianę stringa.

Ad1. Praca z designerem nie polega na tym, że on przygotuje Ci coś i wyjeżdża do ciepłych krajów. Klient zobaczy co zrobiłeś i powie, że chce zmian. Wtedy jesteś ugotowany bo musisz stringa wyciągnąć z powrotem żeby designer mógł pracować.
Ad2. To można załatwić tak, że wkładasz w content obiekt nie dziedziczący z Control/UiElement/FrameworkElement tylko dowolny obiekt modelWidok + DataTemplate gdzie masz widok.
Ad3. a) DataTemplate, b) Style, c) zaprojektowanie GUI w taki sposób, aby pozwolić podmienić elementy, które się mogą zmienić. W jednym miejscu, bez zmiany kodu.

Polecam książkę :
WPF Control Development Unleashed - fajnie koleś pokazuje jak zrobić z listview - widok sonaru łodzi podwodnej - zdaje się że przy użyciu akurat Canvas'a, ale nie o to chodzi.
MVVM: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

Tak na marginesie MVVM to słowo wytrych i dotyczy tylko warstwy prezentacji. Nie mówi nic o modelu. Ale tam obowiązują już "stare" wzorce.Jacek Tomaka edytował(a) ten post dnia 01.02.11 o godzinie 00:27
Borysław B.

Borysław B. Mgr inżynier
informatyki,
właściciel Matrix
Reliability

Temat: Co ze stylami kontrolek generycznych?

Jacek Tomaka:
Ad2. To można załatwić tak, że wkładasz w content obiekt nie dziedziczący z Control/UiElement/FrameworkElement tylko dowolny obiekt modelWidok + DataTemplate gdzie masz widok.

Byłbyś miły podarować mi jakiś prościutki sampel?
Ad3. a) DataTemplate, b) Style, c) zaprojektowanie GUI w taki sposób, aby pozwolić podmienić elementy, które się mogą zmienić. W jednym miejscu, bez zmiany kodu.

Chcę mieć półprzezroczyste, okrągłe okno z własną belką i z własnymi przyciskami do zamykania go, oraz możliwość chwytania okna w rogu i skalowania go. Chcę by tak wyglądało każde moje okno. Czy taką rzecz osiągnę w opisany przez Ciebie sposób? Mógłbyś mi pokazać prościutki sampel?

Będę wdzięczny. Chciałbym lepiej sobie radzić z tworzeniem GUI w WPF, bo nie stać mnie na projektanta :P

Przy okazji - jak najlepiej pozycjonować elementy GUI? Skoro nie określając ich pozycji na Canvas? Jest też Margin, ale jest bardzo niewygodny. Właśnie z WinForms jestem przyzwyczajony określać położenie obiektów poprzez Left, Top i nie wydaje mi się, żeby było coś łatwiejszego i prostszego.

Temat: Co ze stylami kontrolek generycznych?

Jacek Tomaka:
Ad2. To można załatwić tak, że wkładasz w content obiekt nie dziedziczący z Control/UiElement/FrameworkElement tylko dowolny obiekt modelWidok + DataTemplate gdzie masz widok.

Byłbyś miły podarować mi jakiś prościutki sampel?

W wolnej chwili podaruje.
Ad3. a) DataTemplate, b) Style, c) zaprojektowanie GUI w taki sposób, aby pozwolić podmienić elementy, które się mogą zmienić. W jednym miejscu, bez zmiany kodu.

Chcę mieć półprzezroczyste, okrągłe okno z własną belką i z własnymi przyciskami do zamykania go, oraz możliwość chwytania okna w rogu i skalowania go. Chcę by tak wyglądało każde moje okno. Czy taką rzecz osiągnę w opisany przez Ciebie sposób? Mógłbyś mi pokazać prościutki sampel?

To nie jest chyba na prosciutki sampel.
Przy okazji - jak najlepiej pozycjonować elementy GUI? Skoro nie określając ich pozycji na Canvas? Jest też Margin, ale jest bardzo niewygodny. Właśnie z WinForms jestem przyzwyczajony określać położenie obiektów poprzez Left, Top i nie wydaje mi się, żeby było coś łatwiejszego i prostszego.

Masz przestrzeń do poukładania w niej obiektów.

1. Chcesz mieć np. siatkę obiektów. Wtedy używasz Grid, definiujesz kolumny i wiersze, następnie używając Grid.Row i Grid.Column umieszczasz elementy w siatce grida.

2. Chcesz mieć okno z przyciskami ok i anuluj na dole. Pozostałą przestrzeń okna ma wypełniać jakaś kontrolka, powiedzmy Zegar. Używasz DockPanelu z LastChildFill=true i w nim umieszczasz StackPanel z przyciskami, ustawiasz mu DockPanel.Dock="Bottom", a następnie kontrolkę Zegar'a.

3. Panel przycisków. Wkładasz StackPanel i do niego kolejno Buttony. Każdy kolejny button będzie leżał na/obok (w zależności od Orientation = Horizontal|Vertical) następnego.

etc, etc, etc.
Można też pisac własne layout managery - w zasadzie kazda kontrolka jest layout managerem - kluczowe są metody Arrange (Override) i Measure(Override)

Temat layoutu jest dość szeroki, praktycznie kazda ksiazka do WPF'a poświęca mu przynajmniej rozdział.

Następna dyskusja:

dyskoteka z kontrolek




Wyślij zaproszenie do