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

sobota, 6 października 2012

[HTML|JS|CSS] AngularJS: Directives

Dyrektywy w Angularze są mechanizmem pozwalającym w prosty sposób tworzyć potężne mechanizmy, służące zarówno do definiowania zachowań, jak i manipulacji  modelem DOM. Podczas procesu kompilacji dyrektywy są wyszukiwane w kodzie HTML i przetwarzane zgodnie ze zdefiniowaną w nich logiką. Angular JS umożliwia wprowadzenie czterech rodzajów własnych dyrektyw. Mogą one być umieszczane w:
  • nazwach elementów
  • klasach
  • atrybutach
  • komentarzach
Istnieje pewna konwencja, której należy przestrzegać: w kodzie html dyrektywy piszemy jako tzw. snake - names (to-jest-dyrektywa), natomiast w code behind w tzw. camel - case (toJestDyrektywa). Deklaracja dyrektyw w widoku może przebiegać w następujący sposób.

<!doctype html>
<html ng-app="directivesSample">
<head>
<meta charset="utf-8">
 <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
 <script src="scripts/myscript.js"></script>
</head>
<body> 
 <div class="my-first-directive"> </div>
 <my-second-directive></my-second-directive>
 <div my-third-directive></div>
 <!-- directive: my-fourth-directive exp -->
</body>
</html>

Aby AngularJS mógł odpowiednio zinterpretować dyrektywy zawarte w widoku, należy skonfigurować moduł aplikacji w code behind.

angular.module('directivesSample', []).
 directive('myFirstDirective', function(){
   return {
    restrict : 'C',
    template : "<div><button>First directive</button>"+
    "<label>{{myAttribute}} </label>" + 
    "<label>{{literal}} </label>" + 
    "<label>{{text}}</label>" + 
    "</div>",
    scope: { 
     myAttribute:'@myAttribute',
     literal : '=literal' 
    },
    controller : function($scope){
     console.log('controller first... ');
     $scope.text = "someText";
     $scope.literal += ' modified';
     console.log("=literal " + $scope.literal);
    }
  }
 })

W obiekcie konfigurującym mamy do dyspozycji szereg właściwości i funkcji, które możemy modyfikować. Poniżej omówione zostały niektóre z nich:
  • restrict
Informacja na temat tego, gdzie została umieszczona dyrektywa (C - w klasie, M - w komentarzu, A - w atrybucie, E - jako osobny element).
  • template
Zawiera kod HTML, który zostaje doklejony na końcu ciała elementu z dyrektywą. Można użyć property templateUrl z podaną ścieżką do osobnego pliku html z szablonem.
  • replace
Po ustawieniu na true dyrektywa zostanie zastąpiona szablonem (wymagane dla dyrektyw w komentarzach). Domyślnie wartość false, przez co szablon jest wstawiany do wnętrza dyrektywy
  • scope
true - tworzy nowy scope w obrębie dyrektywy, dziedziczy po parent scope
{} -  nowy izolowany scope (brak bezpośredniego dostępu do properties z parent scope). Podczas tworzenia scope można pobierać atrybuty z elementu DOM na którym zastosowana jest dyrektywa (np. '@myAttribute', oraz dworzyć dwukierunkowy binding do właściwości z parent scope (np. '=literal'). Poniżej przykład:

<body ng-controller="myController"> 
 <div>{{literal}}</div>
 <div class="my-first-directive" literal="literal" my-attribute="myAttr"></div>
</body>


function myController($scope){
 console.log('creating outer Scope...');
 $scope.literal = 'outerScope';
}

angular.module('directivesSample', []).
 directive('myFirstDirective', function(){
   return {
    restrict : 'C',
    template : "<div><button>First directive</button>"+
    "<label>{{myAttribute}} </label>" + 
    "<label>{{literal}} </label>" + 
    "<label>{{text}}</label>" + 
    "</div>",
    scope: { 
     myAttribute:'@myAttribute',
     literal : '=literal' 
    },
    controller : function($scope){
     console.log('controller first... ');
     $scope.text = "someText";
     $scope.literal += ' modified';
     console.log("=literal " + $scope.literal);
    }
  }
 })

Wyliczany napis w pierwszym divie zostanie przez data binding zaktualizowany na "outerScope modified".
  • compile: function compile(tElement, tAttrs, scope)
Funkcja wywoływana podczas procesu kompilacji, na tym etapie transformuje się drzewo DOM, np. klonuje elementy za pomocą ng-repeat. Rzadko stosowana.
  • link: function(scope, element, attrs)
W tym miejscu następuje rejestracja event handlerów dla elementów modelu DOM.
link: function(scope, element, attrs) {
 $(element).bind('click',function(){
  alert('click');
 })
}

niedziela, 30 września 2012

[HTML|JS|CSS] AngularJS: Routing

Podczas tworzenia zaawansowanych stron internetowych zachodzi potrzeba zarządzania wieloma widokami tak, aby użytkownik mógł sprawnie nawigować w obrębie strony. AngularJS wspiera mechanizm routingów umożliwiając łatwe zarządzanie szablonami i ich kontrolerami na podstawie podanego adresu url rozpoczynającego się od znaku #. Aby skorzystać z gotowego mechanizmu należy skonfigurować moduł $routeProvider. Zatem pierwszym krokiem, jaki należy wykonać jest podanie, jakie szablony html mają być wyświetlane przy odpowiednich adresach url i jaki zastosować do nich kontroler. Przykład poniżej:

angular.module('routingsample', []).
config(['$routeProvider', function($routeProvider) {
 $routeProvider.
 when('/first/:myparam', {templateUrl: 'pages/first.html', controller: templateController}).
 when('/second/:myparam', {templateUrl: 'pages/second.html', controller: templateController}).
 when('/third/:myparam', {templateUrl: 'pages/third.html', controller: templateController}).
 otherwise({redirectTo: '/first/:myparam'});
}]);

Nazwę modułu (routingsample) podaje się w widoku html w instrukcji ng-app. Konfiguracja polega na podaniu odpowiednich szablonów dla każdego możliwego przypadku. Instrukcja otherwise przekieruje stronę do domyślnego szablonu. Po dwukropku podać można opcjonalny parametr routingu dostępny w kontrolerze. Przykładowy url strony to:

http://localhost:8800/#/first/22

Tworząc kontroler należy za pomocą mechanizmu Dependency Injection zdeklarować chęć użycia parametru routingu, dostępnego w providerze $routeParams.

Przykładowy kontroler może ustawiać parametr routingu w obiekcie $scope do którego bindowany jest widok.

function templateController($scope, $routeParams)
{
 console.log($routeParams.myparam);
 $scope.param = $routeParams.myparam;
}

Szablony html podawane w konfiguracji wstawiane są w widoku w miejsca oznaczone atrybutem ng-view. Tak więc osobny szablon nie musi być całą stroną, a jedynie jej fragmentem. Na przykład:

<!doctype html>
<html lang="en" ng-app="routingsample">
<head>
<meta charset="utf-8">
 <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
 <script src="scripts/routingexample.js"></script>
</head>
<body ng-controller="RoutingExampleController"> 
<ul>
 <li>
  <a href="#/first/">First</a>
 </li>
 <li>
  <a href="#/second/">Second</a>
 </li>
 <li>
  <a href="#/third/">Third</a>
 </li>
</ul>
<div ng-view></div>
</body>
</html>

W takim przypadku pliki z szablonami mogą zawierać kod html bez znaczników head i body z instrukcjami angulara, np. {{param}}, gdzie do bindingu wykorzystany zostanie kontroler, który deklarujemy przy konfiguracji routingu.

czwartek, 30 sierpnia 2012

[WPF] ControlTemplate

Choć jesteśmy przyzwyczajeni do WPF - owych kontrolek w takiej postaci, w jakiej występują one w naszym systemie operacyjnym, nie jesteśmy w żaden sposób ograniczeni do takiego ich wyglądu. Aby w pełni zreorganizować wygląd kontrolek, należy zdefiniować dla nich ControlTemplate. Dzięki temu nie stracimy dostępu do DependencyProperties czy Eventów charakterystycznych dla danej kontrolki, a nadamy jej unikalny wygląd. Mechanizm TemplateBinding umożliwia zbindowanie się do property z oryginalnej kontrolki.


<Window.Resources>
    <ControlTemplate x:Key="TriangleButton">
        <Grid Width="100" Height="100">
            <StackPanel Orientation="Vertical">
            <Path Data="M 30 10 L 50 40 10 40 Z"
                StrokeThickness="48"
                StrokeLineJoin="Round"
                Stroke="Blue"
                Fill="Blue" />
                <TextBlock FontSize="15" 
                            HorizontalAlignment="Left"
                            Text="{TemplateBinding Property=Button.Content}" />
            </StackPanel>
        </Grid>
            
    </ControlTemplate>
</Window.Resources>
<Grid>
    <Button Content="Exit" 
            Template="{StaticResource TriangleButton}" 
            Click="Button_Click" />
</Grid>

Efekt :


piątek, 24 sierpnia 2012

[WPF] Data Binding : Relative Source

Ustawiając w xaml data binding, możemy określić źródło korzystając z RelativeSource. Istnieje kilka sytuacji, w których warto użyć tej opcji.

  • Gdy chcemy, aby źródło i cel bindingu były tą samą kontrolką, np. zmiana wartości slidera powoduje zmianę jego nieprzezroczystości.
<Slider Minimum="0.1" Maximum="1" TickFrequency="0.1"
   Value="{Binding Path=Opacity, RelativeSource={RelativeSource Self}}" />

  • Podczas tworzenia CustomControl w WPF, dodajemy do niej styl w pliku Generic.xaml. Custom control może składać się z wielu mniejszych kontrolek i gdy chcemy aby taka kontrolka bindowała się do property z CustomControl, używamy RelativeSource TemplatedParent.

<Style TargetType="{x:Type local:MySimpleCustomControl}">
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="VerticalAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MySimpleCustomControl}">
                    <Grid Margin="3">                     
                        <Border BorderThickness="1" BorderBrush="Gray" 
                            Margin="2" Grid.RowSpan="2" 
                            VerticalAlignment="Center" HorizontalAlignment="Stretch">
                            <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Margin}" 
                                Width="60" TextAlignment="Right" Padding="5"/>
                        </Border>                      

                    </Grid>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

...możemy stworzyć instancję takiej kontrolki, ustawić jej marginesy i zostaną one zbindowane do textblocka.
  • Czasami zachodzi potrzeba zbindowania się do property z kontrolki, która znajduje się wyżej w drzewie wizualnym. Możemy znaleźć najbliższego przodka danego typu.

<TextBlock Text="{Binding Path=ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}" />

Istnieje także możliwość określenie, który z kolei przodek nas interesuje, dopisując AncestorLevel=...

niedziela, 5 sierpnia 2012

[C#|Visual Studio] Generowanie kodu za pomocą plików T4

Pliki T4 (Text Template Transformation Toolkit) służą do generacji plików o dowolnym rozszerzeniu z bloków tekstu połączonych z blokami kodu pisanych w C# lub Visual Basic. Obowiązuje pewna prosta do opanowania składnia umożliwiająca oddzielenie kodu od tekstu oraz obliczanie wartości które chcemy wstawić w danym miejscu. Transformacja pliku następuje w momencie, gdy zapiszemy plik o rozszerzeniu .tt.

Aby dodać nowy plik, wybieramy Add...New Item... lub ctrl + shift + A. Z listy wybieramy Text Template:


Wygenerowane zostaną dwa pliki : .tt i .txt. Rozszerzenie możemy zmienić w nagłówku pliku .tt, podobnie jak język, w którym chcemy pisać. Kod od tekstu i ustawień oddziela się różnymi rodzajami tagów:
Tag otwierający ustawienia : <#@
Tag otwierający kod : <#
Zwykły tekst nie jest zamykany w żadnych tagach.

Poniższy przykład pokazuje możliwości szablonów T4.
Załóżmy, że chcemy na podstawie pewnej tablicy wygenerować klasy z konstruktorami. Poniższy kod pokazuje, jak to uczynić.


<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>

namespace MyNamespace 
{

<#  var Countries = new string[]{"Poland","England","Ukraine"};
 foreach (var country in Countries)
    {#>
 public class <#=country#>
 {
  public <#=country#>()
  {
  }
 }
                 
<#}#>
}

W wyniku otrzymamy plik .cs o następującej treści :

namespace MyNamespace 
{

 public class Poland
 {
  public Poland()
  {
  }
 }
                 
 public class England
 {
  public England()
  {
  }
 }
                 
 public class Ukraine
 {
  public Ukraine()
  {
  }
 }
                 
}

sobota, 7 lipca 2012

[Wzorce projektowe] Template Method

Analogia z życia:

Piłkarze czołowych klubów europejskich trenują według ściśle zaplanowanego grafiku. Jednego dnia trenują wszyscy stałe fragmenty gry, innego grę piłką. W ciągu miesiąca oprócz meczów swojego zespołu, zdarzają się też takie dni, w których wszyscy wyjeżdżają na zgrupowania swoich reprezentacji narodowych. W tym czasie każdy piłkarz zajmuje się czym innym, zgodnie z zaleceniami swojego trenera - selekcjonera. Po powrocie z reprezentacji, piłkarze wracają do wspólnych treningów w klubie.



Zastosowanie:

Wzorca metody szablonu używa się podczas modelowania pewnego algorytmu składającego się z etapów. Każdy etap może być inny, natomiast całość powinna wykonywać się w odpowiedniej kolejności. Zatem zgodnie z założeniem narzucamy jedynie strukturę pewnego algorytmów, natomiast wykonanie kolejnych kroków zależy od konkretnych implementacji. Część kroków, wspólna dla całego algorytmu, może być także zdefiniowana w klasie bazowej.

Zasada działania:

Szablon metody definiowany jest w abstrakcyjnej klasie bazowej, gdzie w odpowiednich miejscach wywoływane są metody abstrakcyjne. Klasy dziedziczące z klasy bazowej redefiniują odpowiednie metody, wprowadzając w nich swoje zachowania. Przydatne mogą się też okazać metody wirtualne.

Przykład implementacyjny:

public abstract class AbstractLetter
    {
        private readonly string _letterContent;

        public AbstractLetter(string letter)
        {
            _letterContent = letter;
        }

        public void PrintLetter()
        {
            Console.Write("\t\t");
            Console.Write(Recipent() + "\n");
            Console.WriteLine();
            Console.WriteLine(_letterContent);
            Console.WriteLine("\t\t" + Signature());
        }

        public abstract string Recipent();
        public abstract string Signature();

    }
    class FormalLetter : AbstractLetter
    {
        public FormalLetter(string s) : base(s)
        {
            
        }

        public override string Recipent()
        {
            return "Dear Sir/Madam";
        }

        public override string Signature()
        {
            return "Yours faithfully";
        }
    }
    public class InformalLetter : AbstractLetter
    {
        public InformalLetter(string s) : base(s)
        {
            
        }
        
        public override string Recipent()
        {
            return "Hi Jack";
        }

        public override string Signature()
        {
            return "See Ya";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            string s = "This is sample letter";
            FormalLetter formalLetter = new FormalLetter(s);
            InformalLetter informalLetter = new InformalLetter(s);

            formalLetter.PrintLetter();
            Console.WriteLine();
            informalLetter.PrintLetter();
            Console.WriteLine();
        }
    }