• This is a usual time of the year for summaries so let’s keep the tradition alive and write one. Here’s my 2017 achievements split between months. January Blogging for 18 days straight – nothing near gutek’s achievement (whole year!) but still a nice streak Microsoft MVP title (thx Konrad Kokosa for pointing this one ;)) February […]

  • “Advent of Code is a series of small programming puzzles for a variety of skill levels.” Each day was a fun an interesting coding challenge. I’ve decided to practice and code this in python to learn the skill. Some of them might not be the best python scripting as I was short on time in […]

  • Some time ago I’ve attended a .net developer days 2017 conference. I was quite busy since (traveling, teaching .net, working) that only now I got some time to share some thoughts about it. As a bonus I’m including a short interview I did during the event. I need to state here, just to be clear, […]

  • We developers don’t like documentation. We don’t like to read it, and we even more we don’t like to write it. But sometimes it is worth to read it. Like when you find out that by using datetime in SQL DB you got a milliseconds precision but only if it ends on 0,3,7 (link). That […]

  • In the previous post we’ve removed some of the technical debt that could be found in our NetDeveloperPoland Website application. In this one we will remove it even more. We can even maybe reach a B? Let’s see where we’ll end up at the end of this part.

Dziś dokończenie o kilku właściwościach, które pomogą nam sterować wyglądem naszego okna w aplikacji WPF. Zaczynamy.

Justowanie

Dwie właściwości HorizontalAligment, VerticalAligment określają co kontrolka zrobi z dodatkowym miejsce jakie otrzyma od kontrolki rodzica. Przykład:

<StackPanel>                       

    <Button Content=”Przycisk 1″ HorizontalAlignment=”Center” Background=”Orange” />       

    <Button Content=”Przycisk 2″ HorizontalAlignment=”Left” Background=”Red”/>

    <Button Content=”Przycisk 3″ HorizontalAlignment=”Right” Background=”Green”/>

    <Button Content=”Przycisk 4″ HorizontalAlignment=”Stretch” Background=”Aquamarine”/>

StackPanel>

Należy jednak pamiętać, że właściwości te mają zastosowanie, gdy rodzic-panel przeznacza na swoją kontrolkę-dziecko więcej miejsca niż ona tego ona wymaga. Należy również pamiętać, że Width, Height, Min-, Max-opisane w poprzednim odcinku mają pierwszeństwo nad opcją Stretch.

Justowanie treści

Do tego służą właściwości o podobnie brzmiących nazwach. HorizontalContentAligment, VerticalContentAligment. Dzięki nim możemy modyfikować jak kontrolka będzie organizować położenie treści w niej się znajdującej. Przykład:

<StackPanel>                       

    <Button Content=”Przycisk 1″ HorizontalContentAlignment=”Center” Background=”Orange” />       

    <Button Content=”Przycisk 2″ HorizontalContentAlignment=”Left” Background=”Red”/>

    <Button Content=”Przycisk 3″ HorizontalContentAlignment=”Right” Background=”Green”/>       

StackPanel>

Istnieje jeszcze wartość Stretch, ale w przypadku przycisku nie ma ona zastosowania.

Flow direction

Pomocne przy językach, które w przeciwieństwie do naszego czytane są od strony prawej do lewej. Po ustawieniu tej właściwości zmienia się znaczenie wartości Left oraz Right dla justowania treści. Przykład:

<StackPanel>                       

    <Button Content=”Przycisk 1″ FlowDirection=”LeftToRight”

          HorizontalContentAlignment=”Left”

          Background=”Orange” />       

    <Button Content=”Przycisk 2″ FlowDirection=”RightToLeft”

          HorizontalContentAlignment=”Left”

          Background=”Red”/>       

StackPanel>

Zobaczmy, że w drugim przypadku, pomimo ustawionej wartości Left na właściwości HorizontalContentAligment tekst jest wyjustowany do prawej. Oczywiście samo ustawienie właściwości FlowDirection na RightToLeft nie zmienia kierunku w jakim są renderowane znaki.

Na ten odcinek tyle. W następnym będzie o transformacjach.

Zanim przystąpimy do omawiania poszczególnych rodzajów kontrolek używanych do planowania układu formy, musimy przyjrzeć się kilku właściwościom, które pozwolą to rozmieszczenie kontrolować. A zatem do dzieła:

Visibility

Ten atrybut to znany z innych technologii odpowiednik właściwości Visible. Nie byłoby w tej własności nic szczególnego, gdyby prócz standardowych wartości Visible i Hidden nie oferowała właściwości Collapsed. Czy zatem różni się ten stan od Hidden? Jeśli przygotujemy sobie taką prostą aplikację

<StackPanel>       

    <Button Visibility=”Collapsed” Content=”Collapsed” />

    <Button Content=”Widoczny” />

    <Button Visibility=”Hidden” Content=”Hidden” />

    <Button Content=”Widoczny” />

StackPanel>

i ją uruchomimy, to zaobserwujemy poniższy układ przycisków.

Podsumowując – Kontrolki z wartością Collapsed nie zajmują miejsca.

Margin & padding

Właściwości te określają ile miejsca dostanie kontrolka odpowiednio ‘na zewnątrz’ i ‘wewnątrz’. Najlepiej pokaże to kod i obrazek:

<StackPanel>               

    <Button Content=”Widoczny” Margin=”20″ Padding=”10″/>       

    <Button Content=”Widoczny” Margin=”5, 20″ Padding=”5,15″/>

    <Button Content=”Widoczny” Margin=”5,10,15,20″ Padding=”5,10,15,20″/>

StackPanel>

Jak widzimy, możemy użyć trybu 1,2 lub 4 wartości aby ustalić wielkość marginesów i wypełnienia. Dwie wartości odpowiednio definiują stronę: lewa i prawa, góra i dół. Cztery wartości definiują odpowiednio stronę: lewą, górną, prawą i dolną. Intuicyjnie. Jeśli ktoś chciałby te wartości ustawiać z kodu to musi posłużyć się typem Thickness.

Width & Height

Mamy też takie właściwości dostępna na kontrolkach. Ale to nie wszystko. Prócz tego mamy MinWidth, MinHeight, aby ograniczyć rozmiar kontrolki z dołu oraz odpowiednio MaxWidth, MaxHeight z góry. Do tego dochodzą także: DesiredSize, RenderSize, ActualWidth, ActualHeight. Sporo tego. Po kolei. Są one tylko (na szczęście) do odczytu. DesiredSize to wyliczony podczas renderowania kontrolki jej rozmiar. Uwzględniane są tu podane wcześniej ograniczenia jak i to ile rodzić przeznacza na daną kontrolkę miejsca. RenderSize to końcowy rozmiar jaki będzie dana kontrolka posiadać. Tę samą wartość odczytamy za pomocą ActualWidth, ActualHeight. Z tymi ostatnimi powinniśmy jednak uważać, gdyż rozmieszczanie kontrolek odbywa się asynchronicznie i możemy trafić w zły moment podczas ich odczytywania. Można jednak synchronicznie wymusić dokończenie operacji rozmieszczania poprzez zawołanie metody UpdateLayout. Warto również wspomnieć, iż ponieważ rodzic sam daje tyle miejsca ile jest to możliwe to ustawianie wartości Height, Width na sztywno trochę mija się z celem, ale oczywiście znajdą się sytuacje gdy będzie to konieczne.

Następnym razem będzie dokończenie o przydatnych właściwościach kontrolek.

Po krótkiej świątecznej przerwie, powracamy do cyklu “Co w WPF piszczy”. Dziś na warsztat pójdą ostatnie kontrolki z kategorii ItemsControls – TreeView, Toolbar oraz Statusbar.

TreeView

TreeView to drzewko :-). W XAML’u tworzy je się podobnie do kontrolki Menu.

<TreeView>

    <TreeViewItem Header=”C:\”>

        <TreeViewItem Header=”autoexec.bat” />

        <TreeViewItem Header=”config.sys” />

        <TreeViewItem Header=”Temp”>

            <TreeViewItem Header=”EA6111C2-5B8D-41f7-A2BA-A932D569DDD2″ />

        TreeViewItem>

    TreeViewItem>

TreeView>

Sterować elementami możemy poprzez cztery właściwości: Expanded, Collapsed, Selected, UnSelected.

Toolbar

Definicja Toolbar’a to również prosta sprawa.

<ToolBar>

    <Button>

        <Image Source=”warning.png” />

    Button>

    <Label>ZoomLabel>

    <ComboBox SelectedIndex=”0″>

        <ComboBoxItem>100%ComboBoxItem>

        <ComboBoxItem>50%ComboBoxItem>

        <ComboBoxItem>25%ComboBoxItem>

    ComboBox>

ToolBar>

Kontrolki umieszczone w elemencie Toolbar wyglądają troszkę inaczej niż standardowo. Kontrolkę tę można umieścić bezpośrednio w formie, ale lepiej się do tego nadaje obiekt ToolbarTray. Przechowuje on kolekcję elementów Toolbar i jeśli atrybut ToolbarTray.IsLocked nie jest ustawiony na true umożliwia ona reorganizację elementów. w przypadku, gdy lista elementów jest zbyt długa, możemy sprawić, aby elementy zostały umieszczone w tzn. OverflowArea. Robimy to poprzez ustawienia na elementach właściwości Toolbar.OverflowMode na Always, AsNeeded, Never.

StatusBar

StatusBar to belka (zwykle) umieszczona przy dolnej krawędzi naszej aplikacji. Definiujemy ją podobnie jak pozostałe omówione tu kontrolki.

<StatusBar>

    <Label>102 ElementyLabel>

    <Separator />

    <Button Content=”Paste” />

StatusBar>

Nie ma tu też żadnej magii. Prostota.

Na tym zakończymy omawianie kontrolek ItemsControls. Jest jeszcze kilka nieomówionych typów kontrolek (ProgressBar, Slider, TextBox, RichTextBox itp.), ale zostawię je na inny termin. W następnej lekcji przejdziemy do Select and configure Layout panels.

Pierwszy konkurs na http://dotnetomaniak.pl rusza już jutro.
Dzięki firmie oraz stronie mamy naprawdę fajne nagrody (no i kilka rzeczy dorzucę od siebie 🙂 ).

Zachęcam zatem do rejestrowania się na stronie i brania udziału w konkursie. Więcej informacji znajduje się na stronie konkursu: http://dotnetomaniak.pl/quiz

Kolejna kontrolki z kolekcji ItemControls to TabControl oraz Menu

TabControl

Utworzyć ją można w banalny sposób:

<TabControl>

    <TabItem Header=”Tab 1″>Content 1TabItem>

    <TabItem Header=”Tab 2″>Content 2TabItem>

    <TabItem Header=”Tab 3″>Content 3TabItem>

TabControl>

Od razu możemy zobaczyć jak możemy nazwać nasze Tab’y. Za pomocą właściwości TabStripPlacement możemy ustawić miejsce, gdzie będą wyświetlane karty – Bottom, Top, Left i Right

Menu

Menu tworzymy używając tagów Menu oraz MenuItem:

<Menu>

    <MenuItem Header=”_Plik”>

       <MenuItem Header=”_Nowy” />

       <MenuItem Header=”_Otwórz” />

       <Separator />

       <MenuItem Header=”_Koniec” />

    MenuItem>

    <MenuItem Header=”_Edycja”>

       <MenuItem Header=”_Skopiuj” />

       <MenuItem Header=”_Wytnij” />

       <MenuItem Header=”W_klej” />

    MenuItem>

    <MenuItem Header=”P_omoc” />

Menu>

Za pomocą znaku ‘_’ zaznaczamy literę, która będzie umożliwiać wywołanie danego polecenia za pomocą kombinacji ALT + znak. Dostępny jest też element separatora. Element MenuItem posiada, kilka właściwości, które są użyteczne przy konfigurowaniu wyglądu i działania.

  • Icon – umożliwia zdefiniowanie ikony, która pojawi się przy danej pozycji w menu
  • IsCheckable – pozwala zaznaczać i odznaczać dany element w Menu
  • InputGestureText – pozwala dodać tekst, skrótu klawiaturowego skojarzonego z daną pozycją Menu

W przypadku InputGestureText, należy zaznaczyć ich jest to tylko tekst. Aby skojarzyć InputGesture z pozycją w Menu należy posłużyć się opisanym mechanizmem komend.

Dodatkowo wszystko to ukraszone kilkoma zdarzeniami: Checked, Unchecked, SubmenuOpened, SubmenuClosed oraz Click.

Ciekawostka: Jeśli chcesz, możesz sprawić aby menu wyświetliło swoje elementy pionowo:

<Menu.ItemsPanel>

    <ItemsPanelTemplate>

        <StackPanel />

    ItemsPanelTemplate>

Menu.ItemsPanel>

ContextMenu

Jest to w zasadzie normalna kontrolka menu, zdefiniowana wewnątrz innego obiektu:

<StackPanel.ContextMenu>

    <ContextMenu>ContextMenu>

StackPanel.ContextMenu>

ContextMenu definiuje właściwość IsOpen i zdarzenia Opened, Closed.

Dodatkowo ContextMenuService definiuje kilka właściwości dzięki, którym możemy zmodyfikować działanie menu kontekstowego – takie jak: DropOnShadow, ShowOnDisabled, Placement.

Następnym razem kolejne kontrolki – TreeView, ToolBar oraz StatusBar.

Dziś odcinek odnośnie ListView. W WPF ListView tworzymy za pomocą poniższego kodu:

<ListView>

    <System:DateTime>2009-04-14System:DateTime>

    <System:DateTime>2009-04-15System:DateTime>

    <System:DateTime>2009-04-16System:DateTime>

ListView>

Jednak w takim wypadku to co otrzymamy nie będzie różnić się od ListBox’a. Musimy do naszego ListView dodać widok. I tu niestety przychodzi pierwsze rozczarowanie. ListView w WPF ma dostępny tylko widok typu Grid (co można porównać do widoku Details z WinForms). Aby dodać widok, musimy zdefiniować następujące wpisy:

<ListView.View>

                <GridView>

                    <GridViewColumn Header=”Date” />

                    <GridViewColumn Header=”Year” DisplayMemberBinding=”{Binding Year}” />

                    <GridViewColumn Header=”Month” DisplayMemberBinding=”{Binding Month}” />

                GridView>

            ListView.View>

Dzięki temu, dostaniemy 3 kolumny w gridzie, i będą one odpowiednio zawierać cały obiekt (wynik ToString()), rok i miesiąc. Oczywiście, jeśli mamy nasz obiekt, który ma publiczne właściwości to oczywiście możemy do nich przypiąć nasze kolumny za pomocą DisplayMemberBinding.

Dostępne ‘z pudełka’ mamy drag&drop kolumn, zmiana ich rozmiaru i automatyczne dostosowywanie rozmiaru do zawartości. Niestety brak sortowania.

Następnym razem kolejna kontrolka (już mam ich dosyć 🙂 ) – TabControl.

Dziś będzie o tym atrybucie i co za jego pomocą możemy uczynić.

Często debuggujemy nasze aplikacje i często używamy możliwości ‘podejrzenia’ co dana zmienna zawiera. Niestety w przypadku bardziej skomplikowanych typów to co oferuje nam domyślnie VS nie jest wystarczające.

Weźmy dla przykłady bitmapy. To co mamy domyślnie wygląda mniej więcej tak:

Pełno danych, ale tak naprawdę, nie mówią one mam tego najważniejszego. Jak ta bitmapa wygląda. O ile lepiej nam by się żyło, gdybyśmy mogli (oczywiście nadal zachowując możliwość wyświetlenia wszystkich właściwości i zmiennych) zobaczyć taki obraz:

Wbrew pozorom nie jest to wcale takie trudne. Wszystko dzięki atrybutowi DebuggerVisualizer oraz klasie DialogDebuggerVisualizer. Ale po kolei:

Żeby stworzyć taki Visualizer, wystarczy, że utworzymy projekt typu ClassLibrary. A następnie dziedziczmy naszą klasę z DialogDebuggerVisualizer:

public class BitmapVisualizerDialog : DialogDebuggerVisualizer

{

}

Klasa ta jest abstrakcyjna i wymaga od nas napisania ciała dla metody Show. W niej robimy to co chcemy.

var item = objectProvider.GetObject();

var i = (Image) item;

var form = new CompareBitmapDialog {Image = i};

form.ShowDialog();

Gdzie CompareBitmapDialog to zwykła forma z PictureBox’em. Pominę to jak to zrobić. Myślę, że każdy będzie to potrafił.

Na koniec musimy powiedzieć jeszcze jakiego typu/-ów dotyczy ten Vizualizer. Robimy to, wspomnianym w tytule atrybutem, DebuggerVisualizer.

[assembly: DebuggerVisualizertypeof(BitmapVisualizerDialog),                               

                                Target = typeof(Bitmap))]

 

[assembly: DebuggerVisualizertypeof(BitmapVisualizerDialog),                               

                                Target = typeof(Image))]

W zasadzie już wszystko. Pozostał jeszcze deployment. Sprowadza się on do skopiowania naszego wynikowego pliku .dll do odpowiedniego folderu.

\Common7\Packages\Debugger\Visualizers

lub

My Documents\Visual Studio\Visualizers

w zależności czy chcemy, aby dostęp mieli wszyscy czy tylko dany użytkownik. Po restarcie Visual Studio przy Bitmapach pojawi się mała lupka:

Klikając na nią uruchamiamy nasz Vizualizer.

Dziś odcinek poświęcony kontrolce ComboBox. Jak ComboBox wygląda chyba każdy wie. W XAMLu definiuje się go następująco:

<ComboBox>           

    <ComboBoxItem>Item1ComboBoxItem>

    <ComboBoxItem>Item2ComboBoxItem>

    <ComboBoxItem>Item3ComboBoxItem>

ComboBox>

Prawdziwa siła ComboBox’a to ponownie możliwości jakie danej nam WPF związane z konfiguracją wyglądu tej kontrolki. Nie muszą to być zwykłe, statyczne teksty:

<ComboBox>           

    <StackPanel Orientation=”Horizontal”>

        <Image Source=”warning.png” />

        <TextBlock Text=”Jakiś element “/>

    StackPanel>

    <StackPanel Orientation=”Horizontal”>

        <Image Source=”warning.png” />

        <TextBlock Text=”Jakiś element 2″/>

    StackPanel>

    <StackPanel Orientation=”Horizontal”>

        <Image Source=”warning.png” />

        <TextBlock Text=”Jakiś element 3″/>

    StackPanel>

ComboBox>


Co ciekawe nawet pomimo, bardziej zaawansowanej zawartości, nadal możemy skorzystać z funkcjonalności ComboBox’a pozwalającej wyszukiwać elementy po fragmencie tekstu. Musimy po prostu, kontrolkę odpowiednio skonfigurować:

<ComboBox IsEditable=”True” TextSearch.TextPath=”Children[1].Text”>

Lub też skorzystać z właściwości TextSearch.Text na elemencie w ComboBox’ie.

<StackPanel Orientation=”Horizontal” TextSearch.Text=”Jeszcze inny element 3″>

Jeśli chcemy możemy elementy opakować w element ComboBoxItem, ale nie jest to konieczne.

Na dzisiaj tyle. Następnym razem kolejna kontrolka – ListView.

Podwójny zaszczyt mnie dziś dostąpił.

Raczej z ciekawości zainstalowałem sobie IE8 dla programistów .NET na wirtualnej maszynie, gdyż brak, w momencie instalowania, wersji 64-bitowej uniemożliwiał mi to na mojej maszynie. Jakież było moje zdziwienie, gdy wśród blogów zaszczytnych osób, znalazł się mój mały blog. Ponownie przeżyłem “szok”, gdyż wśród Portali znalazł się dotnetomaniak (co prawda nie wiem co robi tam ikonka dotnetshoutout jeszcze :P).

Nie wiem komu dziękować, za wybór mojej osoby, ale miło się zrobiło.

Żeby nie było, że mi się przywidziało – zrobiłem sobie screenshot. Oczywiście gratulacje dla pozostałych osób.

…ale jeśli chodzi o .NET to rzadko go używają. Uruchamiając stronę dotnetomaniak.pl liczyłem, że dzięki tej inicjatywie uda się odnaleźć ciekawe blogi programistów .NET (pisane po polsku), które nie są znane i popularne, a które prezentują ciekawe treci i tematy. I muszę powiedzieć, że z mojego punktu widzenia udało się. Natrafiłem na kilka ciekawych miejsc w sieci, które dostarczają interesujące i świeże spojrzenie na .NET. Czasem na tematy, którymi do tej pory nie było dane mi się zajmować.

Jednak zauważyłem też inną rzecz. Wiele autorów zaczęło pisanie, ale nagle je przerwało. Czasem już po bardzo krótkim okresie czasu. Zastanawiają mnie powody takiego stanu rzeczy:

  • brak czasu?
  • brak tematów (w to trudo mi uwierzyć)?
  • brak wiary we własne zdolności pisarskie?
  • a może google jeszcze nie indeksuje twojego bloga?
  • czy .NET to tylko narzędzie pracy i jest ci ono kompletnie obojętne?
  • mała liczba odwiedzin i wrazenie ze nikt tego nie czyta?

Jeśli myślałeś o założeniu bloga to co cię powstrzymało?