• 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.

W ostatnim poście pisałem o tym, że ListBox wspiera domyślnie sortowanie, grupowanie i filtrowanie danych. W tym wpisie, postaram się pokazać jak coś takiego możemy prosto osiągnąć. Przyjmijmy na potrzeby tego dema, że mamy prostą klasę:

public class MyItem

{

    public string Property1 { get; set; }

    public string Property2 { get; set; }

    public int Property3 { get; set; }

 

    public override string ToString()

    {

        return string.Format(“{0}-{1}-{2}”, Property1, Property2, Property3);

    }

}

Jak widać nic zaawansowanego ona nie ma. 3 właściwości i przeładowana metodą ToString. Utwórzmy teraz kolekcję, które będzie zawierać kilka elementów naszej nowej klasy:

var list = new List<MyItem>

              {

                  new MyItem {Property1 = “1”, Property2 = “2”, Property3 = 1},

                  new MyItem {Property1 = “2”, Property2 = “3”, Property3 = 3},

                  new MyItem {Property1 = “3”, Property2 = “2”, Property3 = 2},

                  new MyItem {Property1 = “4”, Property2 = “3”, Property3 = 3},

                  new MyItem {Property1 = “5”, Property2 = “2”, Property3 = 2}

              };

Teraz jeśli chcemy pogrupować wystarczy, że napiszemy:

ICollectionView view = CollectionViewSource.GetDefaultView(list);

view.GroupDescriptions.Clear();

view.GroupDescriptions.Add(new PropertyGroupDescription(“Property2”));

 

listBox.ItemsSource = view;

Elementy zostaną pogrupowane, w zależności od wyników zwracanych przez właściwość Property2. Jeśli jednak uruchomimy taki kod (oczywiście majać w XAML’u ListBox o nazwie listBox) nie zobaczymy naszego grupowania (choć elementy będą pogrupowane). Musimy troszkę naszego ListBox’a podrasować:

<ListBox.GroupStyle>

    <GroupStyle>

        <GroupStyle.HeaderTemplate>

            <DataTemplate>

                <TextBlock Text=”{Binding Path=Name}” />

            DataTemplate>

        GroupStyle.HeaderTemplate>

    GroupStyle>

ListBox.GroupStyle>

Dzięki temu zdefiniujemy jak ma wyglądać nagłówek każdej grupy. W tym przypadku TextBox’a z wartością, która występuje w danej grupie.

Filtrowanie, również możemy w bardzo prosty sposób uzyskać poprzez ustawienie właściwości Filter:

view.Filter = i => ((MyItem) i).Property3 == 3;

Sortowanie też zatem skomplikowane nie będzie, wystarczy dodać definicję sortowania do kolekcji SortDescriptions np. tak:

view.SortDescriptions.Add(new SortDescription(“Property2”, ListSortDirection.Descending));

view.SortDescriptions.Add(new SortDescription(“Property3”, ListSortDirection.Ascending));

Miłej zabawy. W następnym odcinku powrócimy do kontrolek ItemsControls.

Ruszyły przygotowania do CodeCamp’09. To samo miejsce co ostatnio. 2x więcej sesji. Tak, tak plany są, aby CodeCamp był wydarzeniem dwudniowym. Pierwszego dnia sesje .NET, drugiego SQL.

Mam przyjemność pomagać przy stronie konferencji więc zachęcam do odwiedzania bo już niedługo pojawią się tam istotne informacje

Na chwilę obecną mogę podać datę – 30-31.05.2009.
Pełna treść wiadomości:

No i w końcu nasza największa atrakcja. Rozpoczęliśmy już przygotowania do tegorocznej edycji CodeCamp 2009, która odbędzie się w ostatni weekend majowy (30-31 maja) w tym samym miejscu co rok temu. Chcielibyśmy żeby tym razem spotkanie trwało dwa dni: w pierwszy będzie z myślą o programistach .NET, a w drugim agendę poświęconą SQL Server przygotują koledzy z PLSSUG. Na każdej z tych ścieżek mamy nadzieję zaprosić 5-6 prelegentów (w tym zwycięzcy Spiker Idola – patrzy wyżej). O przygotowaniach będziemy na bieżąco informować na spotkanich grupy oraz na stronie: www.codecamp.pl.

Dziś będzie o Item Controls. Mamy tego trochę więc na pewno nie dam rady opisać tego w jednym wpisie, ale nie traćmy czasu. Zaczynajmy.

Podstawy

Kontrolki ItemsControls charakteryzują się tym, iż udostępniają właściwość Items (typu ItemsCollection) za pomocą której możemy dostać się przechowywanych w tej kontrolce elementów. Każdy element w tej kolekcji jest typu object co powoduje, że nasze kolekcje mogą przyjmować dowolne elementy. Jeśli element dziedziczy po klasie UIElement jest renderowany, zgodnie ze swoim wyglądem, w przypadku obiektów innych typów – rysowane są wynik metody ToString() jako TextBlock.

ListBox

Tak jak pisałem wcześniej elementy w kolekcji Items są typu Object, nikogo nie powinna dziwić taka konstrukcja ListBox’a:

<ListBox>

    <Button Content=”Przycisk”/>

    <WpfExamDemo:MyClass />

    <System:DateTime>4-4-2009System:DateTime>

    <CheckBox Content=”CheckBox”/>

ListBox>

Jednak właściwość Items jest ReadOnly więc nie możemy za jej pomocą wskazać źródła danych. Możemy tylko dodawać ręcznie elementy do kolekcji. Jeżeli chcemy przypisać źródło elementów do ListBox’a musimy posłużyć się właściwością ItemSource. Inne właściwości ListBox’a to:

  • HasItems – pozwala zweryfikować czy ListBox zawiera jakieś elementy
  • IsGrouping – pozwala stwierdzić czy ListBox jest w trybie grupowania elementów (tak, tak pozwala na to)
  • DisplayMemberPath – umożliwia podanie właściwości, które zostanie użyta do wyświetlania obiektu.

Możemy napisać:

<ListBox x:Name=”listBox” DisplayMemberPath=”DayOfWeek”>

    <System:DateTime>4-4-2009System:DateTime>

    <System:DateTime>5-4-2009System:DateTime>

    <System:DateTime>6-4-2009System:DateTime>

    <System:DateTime>7-4-2009System:DateTime>

ListBox>

I zobaczymy jako wynik kolejne dni tygodnia. Co jeśli na liście znajdowałby się element, który nie ma właściwości DayOfWeek? Mielibyśmy pusty element na liście w tym miejscu. Przydatna cecha. Dodatkowo nie musi ona zawierać prostego łańcucha znaków. Może być to coś bardziej skomplikowane jak: List[0].Text – a zatem wspiera wielokrotne właściwości i indeksowanie. ListBox oczywiście zawiera także właściwości znane z WinForms takie jak: SelectedIndex, SelectedItem, SelectedValue Dodatkowo mamy dwie właściwośći typu Attached.

  • IsSelected – pozwala ustawić, że dany element jest zaznaczony
  • IsSelectionActive – (do odczytu) pozwala stwierdzić czy zaznaczony element ma focus

W następnym wpisie trochę o tym, jak możemy sprawić, aby ListBox sortował, grupował i filtrował naszą kolekcję elementów.

Ostatnia część o ContentControls czyli kontenery z nagłówkiem.

GroupBox

GroupBox dodaje ramkę wokół innych kontrolek, które utworzyliśmy. Dodatkowo możemy ustawić nagłówek. Całe piękno WPF’a objawia się w tym, że w przeciwieństwie do WinForms nagłówkiem może być dowolny obiekt. Wystarczy, że napiszemy:

<GroupBox>

    <GroupBox.Header>

        <TextBox Text=”Jestem edytowalnym nagłówkiem”/>

    GroupBox.Header>

    <StackPanel>

        <Label Content=”Item 1″ />

        <Label Content=”Item 2″ />

        <Label Content=”Item 3″ />

    StackPanel>

GroupBox>

i jako nagłówek mamy edytowalnego TextBox’a. Całkiem fajne

Expander

Expander to nowa kontrolka dostępna w WPF’ie. tworzy ona pojemnik na inne kontrolki, który umożliwia ich schowania i pokazywanie zawartości.

<Expander>

    <StackPanel>

        <Label Content=”Item 1″ />

        <Label Content=”Item 2″ />

        <Label Content=”Item 3″ />

    StackPanel>

Expander>

Expander umożliwia nam wybranie kierunku, w którym będzie się rozwijał. Właściwość ExpandDirection może być ustawione na wartość: Down, Left, Right, Up. Za pomocą właściwości IsExpanded możemy ustalić jaki stan ma przyjąć kontrolka jako domyślny. Całość domyka zdarzenie Expanded. Całkiem przyjemna kontrolka.

W następnym odcinku zaczniemy przyglądać się ItemControls.

Dziś kontynuacja nt. ContentControls

Kontenery

Label

Jaki Label jest każdy wie. Skupmy się zatem na tym co nowego/innego daje nam Label w WPF’ie.

Labelka ma ciekawe wsparcie dla klawiszy dostępu. Wystarczy, że napiszemy:

<Label Target=”{Binding ElementName=userName}”>_Nazwa użytkownikaLabel>

<TextBox x:Name=”userName” Width=”200″ />

A w run-time’ie po przyciśnięciu klawiszy ALT+N focus zostanie przeniesiony do pola TextBox. Aby coś takiego uzyskać musimy Labelce powiedzieć, której kontrolki ona dotyczy (właściwość Target) oraz zaznaczyć która litera ma być użyta jako znak dostępu (za pomocą pokreślenia _ ).

ToolTip

ToolTip’a też chyba nie trzeba nikomu przedstawiać. Jednak WPF daje nam możliwość dowolnej konfiguracji tej kontrolki. Może ona teraz zawierać nie tylko tekst, ale i bardziej złożone elementy. Kawałek kodu:

<TextBox x:Name=”userName” Width=”300″>

    <TextBox.ToolTip>

        <StackPanel>

            <TextBlock Background=”DarkRed” Foreground=”White”>OstrzeżenieTextBlock>

            <StackPanel Orientation=”Horizontal”>

                <Image Source=”warning.png” />

                <TextBlock>Nazwa użytkownika musi być wypełnionaTextBlock>

            StackPanel>

        StackPanel>

    TextBox.ToolTip>

TextBox>

i mamy całkiem ładnie wyglądającego ToolTip’a:

Dodatkowo jeśli tego potrzebujemy to ToolTip definiuje zdarzenia Open oraz Closed oraz dodatkowo klasa ToolTipService definiuje kilka właściwości które możemy wykorzystać. Są tam m.in.: ShowDuration – jak długo ToolTip ma być widoczny, ShowOnDisabled – czy elementy, które są zablokowane również pokazują ToolTip i jeszcze parę innych

Frame

O tej kontrolce było już przy okazji opisu Page Web navigation. Warto tylko przypomnieć, że Frame może wyświetlać zarówno strony napisane w XAML’u jaki i HTML’u.

Następnym razem ostatnia część sagi o ContentControl a konkretniej o Containers with a Header.

W dzisiejszym odcinku zaczniemy przyglądać się zagadnieniu zwanemu Content control.

Wśród tych kontrolek znajdziemy grupy takie jak:

  • przyciski (buttons)
  • proste kontenery (containers)
  • kontenery z nagłówkiem (Containers with a header)

Przyciski (buttons)

Przyciski to chyba podstawowe kontrolki mające zawartość. Wszystkie przyciski wywodzą się z klasy ButtonBase, która definiuje takie rzeczy jak zdarzenie Click, właściwość IsPressed oraz ClickMode. Ta ostatnia właściwość określa kiedy zdarzenie Click jest wywołane. Możliwe wartości to Release (domyślna wartość), Press oraz Hover.
Przyciski, które mamy w tej grupie to:

  • Button
  • RepeatButton
  • ToggleButton
  • CheckBox
  • RadioButton

Button

Przycisk (Button) prócz wymienionych powyżej właściwości posiada także: IsCancel oraz IsDefault. Ich znaczenie jest, gdy okno na którym są umieszczone pokazujemy za pomocą metody ShowDialog, wtedy przycisk z ustawioną właściwością IsCancel na true jako rezultat zwróci false

RepeatButton

To taki ciekawy nowy przycisk, który został dodany do WPF’a. Znajduje się on (w przeciwieństwie do pozostałych) w przestrzeni nazw System.Windows.Controls.Primitives, gdyż jest raczej przeznaczony do użycia wewnątrz innych kontrolek, niż użyta bezpośrednio. Całe działanie tego przycisku opiera się o właściwości Delay oraz Interval

Pierwsze z nich, określa jak długi jest czas pomiędzy pierwszym a drugim kliknięciem. Drugi ile czasu ma być pomiędzy wywołaniem zdarzenia Click dla kolejnych przyciśnięć.

ToggleButton

Ten przycisk trzyma stan tego czy został naciśnięty czy też nie. Pierwsze kliknięcie na taki przycisk przestawia stan właściwości IsChecked na true, kolejne na false. Jest ustawimy właściwość IsThreeState na true, sekwencja będzie inna: true, null, false. ToggleButton podobnie jak RepeatButton egzystuje w przestrzeni: System.Windows.Controls.Primitives

CheckBox

CheckBox to w WPF także przycisk Dokładniej ToggleButton z zaaplikowanym innym wyglądem. Nic dodać nic ująć.

RadioButton

RadioButton to ponownie ToggleButton ze zmienionym wyglądem i dodaną funkcjonalnością zaznaczenie tylko 1 elementu z wielu. Grupowanie RadioButtonów odbywa się poprzez ustawienie właściwości GroupName. Grupować można, także pomiędzy różnymi kontenerami, tak długo jak logiczny korzeń jest ten sam. W takim przykładzie:

<Window x:Class=”WpfExamDemo.Window1″

  xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

  xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

  Height=”300″ Width=”300″>

    <StackPanel>

        <StackPanel>

            <RadioButton GroupName=”Group1″>Opcja 1RadioButton>

            <RadioButton GroupName=”Group1″>Opcja 2RadioButton>

            <RadioButton GroupName=”Group1″>Opcja 3RadioButton>

        StackPanel>

        <StackPanel>

            <RadioButton GroupName=”Group1″>Opcja 4RadioButton>

            <RadioButton GroupName=”Group1″>Opcja 5RadioButton>

        StackPanel>

    StackPanel>

Window>

Wszystkie 5 RadioButtonów należy do tej samej grupy i zatem tylko jeden z nich może być w danej chwili zaznaczony.

W następnym odcinku o prostych kontenerach typu Label, ToolTip Frame.

W tym odcinku będzie o Manage application responsiveness – czyli Dispatcher

DispatcherObject

Większość obiektów w WPF dziedziczy po tej właśnie klasie a przez to niestety nie są thread-safety. Jeśli chcemy zmieniać właściwości tych obiektów z innego wątku niż ten w którym zostały utworzone, musimy posłużyć się specjalnym mechanizmem. Na szczęście klasa ta udostępnia specjalną właściwość Dispatcher, którą możemy wykorzystać do tego celu.

Przykładowy kod, który możemy do tego celu wykorzystać:

void method(object obj)

{

    var przycisk = (obj as Button);

    if (przycisk == null) return;

    if (przycisk.Dispatcher.CheckAccess()) // 1

    {

        przycisk.Content = “Update z wątku”;

    }

    else

    {

        przycisk.Dispatcher.Invoke(DispatcherPriority.Normal,

                            new Action<Button>(method), obj); //2

    }           

}

Najważniejsze są tu linie 1 oraz 2. W 1 sprawdzamy, czy jesteśmy w tym samym wątku, w którym została utworzona nasza kontrolka przycisk i jeśli tak to zmieniamy właściwość kontrolki. Jeśli nie używamy obiektu Dispatcher to wywołania naszej metody (2).

DispatcherPriority

W przypadku WPF’a mamy całkiem sporo możliwości konfigurowania priorytetu naszej aplikacji. Enumeracja DispatcherPriority oferuje, aż 12 różnych wartości. Znaleźć je wszystkie możemy na MSDN. Na początku ilość może przytłaczać, ale dzięki takiemu rozróżnieniu możemy precyzyjnie zaplanować nasze wątki.

Zwracanie wartości z wątków

Jeśli nasza metoda zwraca wartość to w głównym wątku możemy chcieć ją odczytać. Aby to zrobić możemy posłużymy się mniej więcej takim kodem:

   var result = Dispatcher.BeginInvoke(new Func<object, bool>(method), przycisk);

   result.Wait();   

   MessageBox.Show(result.Result.ToString());

Freezable Objects

Obiekty, które dziedziczą z tej klasy mogą znaleźć się w specjalnym stanie “zamrożenia”, w którym dostępne są tylko do odczytu. Są wtedy również thread-safe. Aby sprawdzić czy czy dany obiekt jest zamrożony wystarczy zawołać właściwość IsFrozen, aby sprawdzić czy obiekt może zostać zamrożony CanBeFrozen.Przykładowe klasy to: Brush, Pen, Geometry, Transform, AnimationTimeline.Po co takie obiekty nam są? Ponoć poprawiają wydajność naszych aplikacji w WPF oraz udostępniają szczegółowe notyfikacje o swoim stanie.

Następnym razem nowy temat – Building user interfaces. Zaczniemy od Content controls.

Niniejszym postem chciałbym zapoczątkować dyskusję odnośnie dotnetomaniak.pl, kontynuując wątek rozpoczęty na forum Codeguru. Chcę, aby był to portal dla nas wszystkich nas fanów technologii .NET.

Chciałbym zatem, abyś przeczytał poniższe informacje drogi czytelniku i zostawił swój komentarz:

Ogólne:

  • co najbardziej przeszkadza Ci na stronie?
  • co lubisz na stronie?
  • czy aktualny wygląd przeszkadza ci w użytkowaniu strony?
  • nazewnictwo (Promuj, Degraduj i dotnetomaniaki (punkty)) – jest ok czy zmienić to na coś innego?

Działanie strony:

  • przy chciałbyś przycisk ‘Oznacz jako spam’ dla już opublikowanych artykułów?
  • jak postępować z artykułami oznaczonymi jako spam, które już zostały wypromowane przez innych użytkowników? – np. jedno zgłoszenie o spam, a 2 użytkowników wypromowało wpis i oczywiście jest wpis na pograniczu technologii
  • dodawanie wpisów przez samych siebie – ukrócić czy jest to w porządku?

Konto:

  • dlaczego nie masz konta na dotnetomaniak.pl? (oczywiście jeśli go nie masz)
  • czy brakuje Ci jakiejś funkcjonalności w Twoim koncie

Nowości:

  • czy widzisz sens publikowania pełnych artykułów na dotnetomaniaku
  • czy widzisz sens w organizowaniu konkursów dla najbardziej aktywniejszych użytkowników? (jakie nagrody?)
  • może masz własne propozycje usprawnień/dodatków?

Proszę zostawiajcie komentarze, lub ślijcie do mnie bezpośrednio na maila. Każda konstruktywna odpowiedź jest dla mnie ważna. Oczywiście jeśli brakuje to jakiegoś pytania to pisz śmiało.

Z góry dziękuję za wszelki komentarz.

Rozpocząłem swoją zabawę z Silverlight 3. Na pierwszy ogień poszła nowa kontrolka czyli ChildWindow, za pomocą której możemy w łatwy sposób uzyskać efekt wyskakującego okienka.
Zapraszam do oglądania screencastu a ponieważ jest to mój pierwszy screencast z głosem (“pięknym inaczej”), to proszę o konstruktywną krytykę, opinie i rady.

Promuj

Dziś będzie o Application Settings w WPF. Niestety nie znalazłem nic w tym temacie ciekawszego niż to co dostępne już jest w WinForms. Jednak dla spójności naszych tematów omówmy i ten.

Design Time

Ustawienia możemy definiować za pomocą wygodnego designera zawartego w VisualStudio.

<userSettings>

    <WpfExamDemo.Properties.Settings>

        <setting name=FullScreen serializeAs=String>

            <value>Truevalue>

        setting>

    WpfExamDemo.Properties.Settings>

userSettings>

<applicationSettings>

    <WpfExamDemo.Properties.Settings>

        <setting name=AllowClosing serializeAs=String>

            <value>Falsevalue>

        setting>

    WpfExamDemo.Properties.Settings>

applicationSettings>

Ustawienia możemy podzielić na użytkownika jak i aplikacji, które to będą współdzielone przez wszystkich użytkowników.

RunTime

Zmienne, które zdefiniujemy przy pomocy VS, dostajemy ładnie jako właściwości w klasie Settings. Wystarczy więc napisać:

var isFullScreen = Settings.Default.FullScreen;

możemy też skorzystać ze słabo typowalnej wersji:

var isFullScreen = Settings.Default[“FullScreen”];

Aby zapisać zmiany w ustawieniach należy zawołać metodę Save na obiekcie Settings:

Settings.Default.Save();

Dodatkowo udostępniane jest kilka zdarzeń za pomocą, których możemy wpłynąć na wczytywanie i zapisywanie parametrów:

Settings.Default.SettingsLoaded += Default_SettingsLoaded;

Settings.Default.SettingsSaving += Default_SettingsSaving;

Co ciekawe SettingsSaving pozwala zablokować wczytywanie ustawień

void Default_SettingsSaving(object sender, System.ComponentModel.CancelEventArgs e)

{

    e.Cancel = true;

Następnym tematem będzie – Manage application responsiveness – ostatni z tematu Creating WPF application.