Pokazywanie postów oznaczonych etykietą Controls. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą Controls. Pokaż wszystkie posty

piątek, 2 października 2009

[Behaviors] Mouse Over ComboBox Open (Behavior)

Po ostatnim małym sukcesie (7 dni i ponad 700 ściągnięć) z behaviorsem (patrz poprzedni wpis), postanowiłem że gdy kolejny raz przyjdzie mi do głowy jakiś nowy prosty behavior, również się nim podzielę.

Prościej się nie da

Mój najnowszy behavior nie może być prostszy, bo poniżej jednej linii kodu która rzeczywiście coś robi, nie da się zejść ;) Na szczęście jego działanie stawia go w innym świetle. A o co chodzi? Otóż mój nowy behavior, jak nazwa tego wpisu sugeruje, otwiera listę ComboBoxa po najechaniu na nią myszką. Tada!!! :P

Live demo

Niby nic ale rzeczywiście przydaje się w wielu aplikacjach. Po co użytkownik ma klikać na listę żeby się rozwinęła, skoro może najechać na nią myszką, zawsze to o jeden click mniej! :)

Dodajemy do kodu

<ComboBox Height="29" Width="130" d:LayoutOverrides="Margin">
<interaction:Interaction.Behaviors>
<behavior:OpenComboBoxBehavior />
</interaction:Interaction.Behaviors>
<ComboBoxItem>
<TextBlock Text="First element" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Second element" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Third element" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="Fourth element" />
</ComboBoxItem>
</ComboBox>

, gdzie "i:" jest przestrzenią nazw dla "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity", a "behavior:" dla projektu w którym umieszczony jest kod bahaviora.

Wady

Ten Behavior w ogóle nie nadaje się w interfejsach gdzie mamy wiele elementów i ciągle rozwijająca się lista tylko by zasłaniała pozostałe elementy, natomiast jest świetny w paskach menu, przyciskach z dodatkowymi opcjami itp.

Inspiracja

Oczywiście sam na taki pomysł ulepszenie ergonomii interfejsu nie wpadłem, a zwyczajnie podpatrzyłem go na stronie youtube.com. :) Jeżeli przyjrzycie się swojemu użytkownikowi w prawym górnym rogu, to zobaczycie że jak najedziecie na swój profil myszką, to bez klikania rozwija się bardzo wygodna lista dodatkowych opcji.

Source Code

Tradycyjnie, ponieważ kod jest krótki, wklejam całość.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;

/// Behavior for ComboBox control.
/// It invokes drop down list when mouse is over it.
///
/// Jacek Ciereszko
/// http://geekswithblogs.net/SilverBlog/
///

///

namespace ComboBoxBehavior
{
public class OpenComboBoxBehavior : Behavior
{
///
/// Called after the Behavior is attached to an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.MouseEnter += new MouseEventHandler(AssociatedObject_MouseEnter);
}

///
/// Called after the Behavior is detached from an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnDetaching()
{
this.AssociatedObject.MouseEnter -= new MouseEventHandler(AssociatedObject_MouseEnter);
base.OnDetaching();
}

///
/// When mouse is over ComboBox, control drop down will open
///

///
///
void AssociatedObject_MouseEnter(object sender, MouseEventArgs e)
{
this.AssociatedObject.IsDropDownOpen = true;
}
}
}

Do pobrania

Kod jest także dostępny do pobrania na stronie http://gallery.expression.microsoft.com/en-us/OpenComboBoxDropDown.


Pozdrawiam,

Jacek Ciereszko

poniedziałek, 21 września 2009

[Behaviors] TextBox Enter Button Invoke (TargetedTriggerAction)

Jakiś czas temu zdarzyło mi się napisać własny behavior, który w odróżnieniu od tych które dłubie na co dzień, może mieć zastosowanie w wielu aplikacjach, stąd też pomysł aby się nim podzielić :)

Co to są behaviorsy nie będę się rozpisywał w tym temacie. Zagadnienie jest większe, a do poczytania o nim polecam świetny artykuł: http://www.silverlightshow.net/items/Behaviors-and-Triggers-in-Silverlight-3.aspx

O co chodzi?

Skoro już wszyscy wiedzą co to są behaviorsy w Silverlight 3.0, to wypadało by powiedzieć że mój jest typu "TargetedTriggerAction", czyli wykonuje akcję na innym obiekcie gdy ten do którego jest przypisany, wywoła wybrany event.

Mój behavior po wciśnięciu przycisku "Enter" we wskazanym textboxsie zasymuluje wciśnięcie wskazanego przycisku (wszystko co dziedziczy z ButtonBase).

Pewnie pomyśleliście sobie od razu, co za bzdura, przecież można podpiąć event i wywołać tą samą metodę w kodzie. Tylko co w przypadku gdy namiętnie stosujemy MVVM, gdzie nasz "code behind" jest czyściutki i zawiera tylko konstruktor? W takim wypadku behavior jest tym czego poszukujemy. Co ważniejsze, "code behind" pozostaje nienaruszony, nie śmiecimy również w ViewModelu, a operacje "interfejsowe" pozostają ładnie oddzielone i nadają się do ponownego użycia.

Standardowe zastosowanie

Jak wspomniałem, behavior ma zastosowanie przede wszystkim w aplikacjach z wzorcem MVVM, a jego miejsce to np. pole wyszukiwania.

Live demo

Wciskając "Enter" w polu tekstowym otrzymujemy ten sam efekt co wciskając przycisk.

Dodajemy do aplikacji

    <Button x:Name="TargetedButton" Content="Targeted Button"  />
<TextBox Text="TextBox" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown" >
<behavior:TextBoxEnterButtonInvoke TargetName="TargetedButton" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

, gdzie "i:" jest przestrzenią nazw dla "clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity", a "behavior:" dla projektu w którym umieszony jest kod bahaviora.

Kod źródłowy

Kodu jest niewiele, więc postanowiłem wkleić go cały.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Windows.Controls.Primitives;

/// TargetedTriggerAction for TextBox control.
/// Invokes targeted button when Enter is pressed inside TextBox.
///
/// Jacek Ciereszko
/// http://jacekciereszko.pl
///

///

namespace TextBoxEnterBehavior
{
public class TextBoxEnterButtonInvoke : TargetedTriggerAction
{
///
/// Gets or sets the peer.
///

/// The peer.
private AutomationPeer _peer { get; set; }

///
/// Gets or sets the target button
///

private ButtonBase _targetedButton { get; set; }

///
/// Called after the TargetedTriggerAction is attached to an AssociatedObject.
///

/// Override this to hook up functionality to the AssociatedObject.
protected override void OnAttached()
{
base.OnAttached();
_targetedButton = this.Target;
if (null == _targetedButton)
{
return;
}

// set peer
this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
if (this._peer == null)
{
this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
}
}

///
/// Called after targeted Button change.
///

/// Override this to hook up functionality to the new targeted Button.
protected override void OnTargetChanged(ButtonBase oldTarget, ButtonBase newTarget)
{
base.OnTargetChanged(oldTarget, newTarget);
_targetedButton = newTarget;
if (null == _targetedButton)
{
return;
}

// set peer
this._peer = FrameworkElementAutomationPeer.FromElement(_targetedButton);
if (this._peer == null)
{
this._peer = FrameworkElementAutomationPeer.CreatePeerForElement(_targetedButton);
}
}

///
/// Invokes the targeted Button when Enter key is pressed inside TextBox.
///

/// KeyEventArgs with Enter key
protected override void Invoke(object parameter)
{
KeyEventArgs keyEventArgs = parameter as KeyEventArgs;
if (null != keyEventArgs && keyEventArgs.Key == Key.Enter)
{
if (null != _peer)
{
IInvokeProvider invokeProvider = _peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProvider.Invoke();
}
}
}
}
}

Do pobrania

Kod jest także dostępny do pobrania na stronie http://gallery.expression.microsoft.com/en-us/TextBoxInvokeButton.


Pozdrawiam,

Jacek Ciereszko

piątek, 21 sierpnia 2009

Youtube w Silverlight 3.0?

Wraz z nowym Expression Blendem 3, a właściwie to z Expression Encoderem 3 otrzymaliśmy nową kontrolkę do wyświetlania mediów, czyli MediaPlayer!

Czym jest MediaPlayer?

MediaPlayer to zaawansowana kontrolka do odtwarzania plików video, która opakowuje wszystkie funkcjonalności jakie możemy sobie wymarzyć. Oprócz podstawowego odtwarzania pozwala na tworzenie Playlist, Chapters, AutoLoad, AutoPlay, działa w trybie Offline (po zaakceptowaniu zwiększenia przestrzeni IsolatedStorage), Popout, Transport Controls, Progress Bar, Volume Bar, Full Screen i Closed Caption buttons.

Uruchomienie

Jeśli mamy zainstalowanego Expression Blenda 3 oraz Expression Encoder 3 to kontrolka powinna pojawić się w zakładce Assets-> Media. Jednak jeśli tak się nie stanie, można zrobić to ręcznie, przechodząc do katalogu instalacyjnego Expression Encodera (zwykle jest to "C:\Program Files\Microsoft Expression\Encoder 3") i wybierając katalog "BlendMediaPlayer". W nim znajduje się biblioteka "MediaPlayer.dll" którą wystarczy dołączyć do projekt Silverlight np. w Visual Studio.

W aplikacji Silverlight (dowolnej) w kodzie xaml dodajemy odniesienie do namespace-a, np. "xmlns:media="clr-namespace:ExpressionMediaPlayer;assembly=MediaPlayer" oraz kod odtwarzacza

"<media:MediaPlayer />".

Filmy które chcemy odtwarzać ustawiamy w playlist. To w jaki sposób przekażemy je do kontrolki zależy już tylko od nas. W moim przykładzie ustawiam akurat adresy na sztywno w kodzie.

<media:MediaPlayer x:Name="mediaPlayer" >
<media:MediaPlayer.Playlist>
<media:Playlist>
<media:Playlist.Items>
<media:PlaylistItem MediaSource="adresDoFilmu" Title="Star Trek Trailer" VideoHeight="1024" VideoWidth="864" />
</media:Playlist.Items>
</media:Playlist>
</media:MediaPlayer.Playlist>
</media:MediaPlayer>

Oczywiście cały powyższy proces można zrealizować w Expression Blend 3 przy pomocy kilku kliknięć. :)

Wygląd

Jeśli podstawowy wygląd kontrolki nie przypadł nam do gustu, możemy zmodyfikować jej template i dostosować wygląd do naszych wymagań. Najłatwiej można to zrobić używając Expression Blenda 3, poprzez wybór prawym myszki na kontrolce, "Edit Template" -> "Edit a copy..".

Live demo

Demo odtwarza HD film "Car accident" w formacie wmv (thx to http://stormscenes.com). Link.

Source Code

link

References

Pozdrawiam,

Jacek Ciereszko

niedziela, 26 kwietnia 2009

Silverlight Count Down Control – Wasze dni są policzone

Jakiś czas temu wymyśliłem sobie malutki programik który będzie odliczał ustawiony czas. Ktoś by zapytał: po co to komu? Jednak jak się dobrze zastanowić, to taki "counter" czasu może być bardzo fajnym dodatkiem do wielu stron. Na pewno fajnie przypomni o nadchodzącej konferencji czy też spotkaniu, chociaż jestem przekonany że znajdzie się dla niego wiele innych ciekawych zastosowań :)

Wychodząc naprzeciw oczekiwaniom stworzyłem taki programik i umieściłem wraz z kodem źródłowym na codeplex-sie pod adresem: http://silverlightgadgets.codeplex.com/ (mam nadzieję że uda mi się tam także umieścić wiele innych "gadgetów")

Demo znajdziecie pod adresem (tak wiem, grafika wygląda tragicznie ;)):

http://wpierdalaj.pl/SWG/SilverlightCountDown/Run/SilverlightCountDownTimerExampleTestPage.html

Jak go użyć

Counter został stworzony tak aby był łatwo konfigurowalny i zgodny z wymaganiami wzorca Model-View-ViewModel (MVVM). Najłatwiej jest zwyczajnie:

  1. Pobrać bibliotekę kontrolki (SilverlightCountDownTimer.dll) ze strony http://silverlightgadgets.codeplex.com/,
  2. Dołączyć ją do rozwijanego projektu (Add References),
  3. Umieścić w kodzie:
<UserControl x:Class="SilverlightCountDownTimerExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:timeCounter="clr-namespace:SilverlightTimer assembly=SilverlightCountDownTimer"
Width="200" Height="100">
<Grid x:Name="LayoutRoot" Background="Transparent">
<timeCounter:SilverlightTimerControl EventDescription="Time to New Year Party"
EventTime="2010-01-01 00:00" />
</Grid>
</UserControl>

Tak jak widzimy w przykładzie, wystarczy wstawić kontrolkę i ustawić podstawowe parametry aby odliczanie ruszyło.

Parametry

Do dyspozycji mamy następujące parametry konfiguracji kontrolki:

  • EventDescription – Tekst który wyświetli się pod odliczanym czasem. W tej wersji istnieje ograniczenie długości pola tekstowego jakie może pomieścić textbox.
  • EventTime – Data do której będzie odliczany czas.
  • EventTimeUrl – Adres pliku tekstowego który zawiera datę. Ten parametr umożliwia dynamiczne modyfikowanie daty bez ingerencji w kod aplikacji. Wystarczy że zmienimy datę w pliku, a counter zacznie odliczać czas do nowej daty. Przykładowy plik z datą: http://wpierdalaj.pl/SWG/date.txt. Uwaga, jeśli ustawimy także parametr "EventTime", "EventTimeUrl" zostanie pominięty. Parametr"EventTime" ma pierwszeństwo przed "EventTimeUrl". Należy także zwrócić uwagę czy plik z datą jest dostępny dla odwołań z zewnątrz (patrz ustawienia Client Access Policy na blogu Tim Heuera)
  • CounterFinish – Event który zostanie wywołany gdy counter skończy odliczanie. W ten sposób możemy zainicjalizować jakąś akcję w aplikacji gdy upłynie ustawion czas.
  • EventTimeCache – Ten parametr uruchamia funkcję cache'owania daty. Ma to zapobiec sytuacji nadmiernego odpytywania serwera (poprzez parametr EventTimeUrl) o datę do odliczania. Odpytanie jest mało kosztowne, a sama data to kilka bajtów, ale jeśli można odciążyć serwer, to warto skorzystać z tej możliwości. Domyślnie cache jest wyłączony, a jego czas ważności ustawiony na jeden dzień, po tym terminie counter sprawdzi czy ma aktualne dane.
  • EventTimeCacheDuration – Ta opcja zmienia domyślny czas cachowania daty. Jednostką jest dzień, a więc ustawienie tego parametru na wartość 40, sprawi że aplikacja przez 40 dni nie będzie aktualizować odliczanej daty.

Wszystkie wyżej wymienione parametry możemy także ustawiać bezpośrednio w kodzie i zmieniać w czasie działania kontrolki. Np.:

.XAML:

<timeCounter:SilverlightTimerControl x:Name="myCounter" />

.CS (C#):

myCounter.EventTime = new DateTime(1983, 12, 14, 0, 0, 0);
myCounter.EventDescription = "Moje Urodziny";

Ponieważ aplikacja wspiera pattern Model-View-ViewModel (MVVM), możliwe jest także ustawienie binding-u na w/w paramentry. Np.:

<timeCounter:SilverlightTimerControl x:Name="myCounter" EventTime="{Binding Path=EventTime}" />

Podłączenie aplikacji bez dotykania kodu i Visual Studio

Dla tych którzy nie mają ochoty na zabawę z Visual Studio, dostępna jest także opcja gotowej aplikacji konfigurowanej z poziomu kodu html. W pliku "HtmlVersion" znajduje się kompletny przykład takiej konfiguracji, a poniżej wycinek z pliku SilverlightCountDownTimerExampleTestPage.html:

<object data="data:application/x-silverlight-2,"
type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/SilverlightCountDownTimerExample.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="3.0.40307.0" />
<param name="autoUpgrade" value="true" />

<!--// EventTimeUrl will be ignored because EventTime is set-->
<param name="initParams"
value="EventDescription=Time to MIX 2010,
EventTime=2010-03-15 08:00,
EventTimeUrl=http://wpierdalaj.pl/SWG/date.txt,
EventTimeCache=True,
EventTimeCacheDuration=40"
/>

</object>

Aby uruchomić counter, nie musimy ustawiać wszystkich w/w parametrów. Jeśli coś nie działa, sprawdźcie czy nie zrobiliście błędu w zapisie. Niestety opcja "initParams" jest bardzo czuła na dodatkowe znaki oraz nie pozwala na znaki specjalne, np. cudzysłowy czy przecinki w ustawianych wartościach.

Dodatki

Jeśli chcemy aby counter był klikalny i np. przekierował osobę na inną stronę, wystarczy otoczyć go prostym Hiperlinkiem w kodzie XAML:

<HyperlinkButton NavigateUri="http://jacekciereszko.pl" TargetName="_blank" >
<timeCounter:SilverlightTimerControl x:Name="myControl" />
</HyperlinkButton>

Wygląd

Na ten moment nie przewiduje dla "countera" skinsów ani wsparcia na zmianę grafiki. Powodem tego jest brak jakichkolwiek umiejętności graficznych, w związku z tym zakładam że każdy będzie sam w stanie korzystając z kodu źródłowego dostosować wygląd aplikacji do swoich potrzeb.

Jeśli znajdzie się ktoś kto chciałbym coś ładnego namalować i się tym podzielić, chętnie dodam to do projektu.

Podsumowanie

Proszę piszcie jeśli macie jakieś propozycje lub zastrzeżenia, będę starał się ulepszać na bierząco "odliczacza" czasu :) Na razie planowany jest downgrade do wersji Silverlight 2.0.

Strona projektu: http://silverlightgadgets.codeplex.com/

Pozdrawiam,

Jacek Ciereszko

czwartek, 3 kwietnia 2008

Button jako Content ToolTipa z Buttona w Buttonie

W artykule tym, jak wskazuję tytuł, postaram się opisać fajny feature Silverlighta 2.0, czyli Content kontrolek. Otóż grupa kontrolek w SL, posiada właściwość Content, która pozwala nam wypełnić ją wszystkim, czyli wstawić np. StackPanel i wrzucić do środka co nam się zamarzy. Do tej grupy należą kontrolki, które dziedziczą po ContentControl, czyli:

(fotka pobrana z Liquid Boyfotka oryginalna )

Jak widać, jest wśród nich ToolTip, który szczególnie zwrócił moją uwagę. Otóż pomyślałem, że można by zagnieździć kolejno w ToolTipie Buttona, a do tego Button w ToolTipe przypisać inny ToolTip, a w nim znowu Button z ToolTipem. Niestety kontrolka ToolTip, nie chce wyświetlać z wewnętrznego Buttona kolejnego ToolTipa (patrz demo).

Udało się za to zrealizować zagnieżdżanie przycisków i ich obsługę, co ilustruje ListBox. Dodatkowo, w ToolTipie umieściłem filmik, które bez problemu się odtwarza i daje zupełnie nowe spojrzenie na zastosowanie ToolTipa.

Oczywiści zagnieżdżanie, takie jak zrobiłem przy użyciu ToolTipa oraz Buttona, można zrobić także z innym kontrolkami wyświetlonymi powyżej. Możliwości jest na prawdę dużo.

Demo:






Source Code:


Resources:


Jacek Ciereszko