Krisztián's profileBátyai Krisztián[KRis]PhotosBlogListsMore Tools Help

Blog


    November 27

    Silverlight 4 Printing/Nyomtatás

    Nyomtassunk Silverlight-ból!

    A Silverlight 4 egyik nagy újdonsága, amit mindeki kért hogy tudjon nyomtatni. Én nekem ezzel kapcsolatban vannak fenntartásaim, de ezt ugye már megbeszéltük a DevPortal-on….

    Mondjuk amit most tud az SL az mindeképp jó, csak ne gondolja senki, hogy akkor el lehet felejteni a Rep.Serv. megoldásokat :D

    Tehát, kell valami adatforrás, amit megjelenítünk a feleületen…Ez legyen az AdventureWorks Product tábla.
    Jelenítsük ezt meg egy ListBox-ban, egy DataTemplate segítségével. Ekkor két lehetőségünk van:


    1. private void btnPrintGrid_Click(object sender, RoutedEventArgs e)
         {
             popCM.IsOpen = false;
      
             //Print
      
      
             int page = 1;
             int record = 0;
      
             // create print document:
             PrintDocument printDoc = new PrintDocument();
             printDoc.PrintPage += (s, args) =>
             {
      
                 double next_pos = 0;
                 double next_height = 40;
                 StackPanel spPrint = new StackPanel();
                 spPrint.Width = args.PrintableArea.Width;
                 while (record < datas.Count && next_pos + next_height <= args.PrintableArea.Height)
                 {
                     StackPanel spH = new StackPanel();
                     spH.Orientation = Orientation.Horizontal;
                     spH.Height = next_height;
                     spH.Children.Add(new TextBlock() {
                         Margin = new Thickness(0, 3, 3, 3), 
                         Text = datas[record].ProductID.ToString() });
      
                     spH.Children.Add(new TextBlock() { 
                         Margin = new Thickness(0, 3, 3, 3), 
                         Text = datas[record].Name.ToString() });
      
                     spH.Children.Add(new TextBlock() { 
                         Margin = new Thickness(0, 3, 3, 3), 
                         Text = datas[record].ListPrice.ToString("c") });
      
                     spH.Children.Add(new Rectangle()
                     {
                         Margin = new Thickness(0, 3, 3, 3),
                         Width = datas[record].ProductID / 10,
                         Fill = new SolidColorBrush(Colors.Red)
                     });
                     spPrint.Children.Add(spH);
      
                     record++;
                     next_pos += next_height;
                 }
      
      
                 args.HasMorePages = record < datas.Count;
                 args.PageVisual = spPrint;
      
                 page++;
             };
             printDoc.Print();
         }

    2.  
      private void btnWSYIWYG_Click(object sender, RoutedEventArgs e)
          {
              popCM.IsOpen = false;
      
              int page = 1;
              int record = 0;
      
              // create print document:
              PrintDocument printDoc = new PrintDocument();
              printDoc.PrintPage += (s, args) =>
              {
      
                  double next_pos = 0;
                  double next_height = 40;
                  StackPanel spPrint = new StackPanel();
                  spPrint.Width = args.PrintableArea.Width;
                  while (record < 
                      10//datas.Count
                      && next_pos + next_height <= args.PrintableArea.Height)
                  {
                      ContentPresenter cp = new ContentPresenter();
                      cp.Content = datas[record];
                      cp.ContentTemplate = this.Resources["dtProd"] as DataTemplate;
                      cp.Measure(new Size(args.PrintableArea.Width, args.PrintableArea.Height));
                      spPrint.Children.Add(cp);
      
                      next_pos += cp.DesiredSize.Height;
      
                      record++;
                      next_pos += next_height;
                  }
      
      
                  args.HasMorePages = record < 10;// datas.Count;
                  args.PageVisual = spPrint;
      
                  page++;
              };
              printDoc.Print();
          }
      

       

    3. A DataTemplate hozzá:

          <UserControl.Resources>
              <DataTemplate x:Key="dtProd">
                  <StackPanel Orientation="Horizontal">
                      <TextBlock Text="{Binding ProductID}" MinWidth="100"></TextBlock>
                      <TextBlock Text="{Binding Name}" MinWidth="100"></TextBlock>
                      <TextBlock Text="{Binding ListPrice}" MinWidth="100"></TextBlock>
                      <Rectangle Fill="{Binding Color}" MinWidth="100"></Rectangle>
                  </StackPanel>
              </DataTemplate>
          </UserControl.Resources>
      

    Első esetben az kerül nyomtatásra, amit mi alkotunk kézzel-lábbal-kóddal. Látható hogy mi vagyunk felelősek azért hogy összerakjunk mindent!.
    Második esetben a DataTemplate segít nekünk. Tehát itt tulajdonképpen azt kapjuk amit a monitoron is látunk. Ami több esetben rossz mint amennyiben jó… Ezzel vigyázni kell… Persze itt segít nekünk a Layout természetes adaptívsága.

    A nyomtatás egyszerűen 3 lépésből áll (minimum):

    1. PrintDocument létrehozása
    2. PrintPage-re iratkozás, és egy oldal megadása
    3. Print() metódus.

    Ennyi… nem is bonyolult.

    Forráskód: skydrive
    ScreenCast: devportal
    Silverlight Player : lejátszás

    Mi van a DataGrid hátulján? (Készítsünk saját vezérlőt (Visual Studio-ban) VSM-el I/II)

     

    Gondolom már mindenki elgondolkodott rajta mi van a DataGrid hátulján :) ugye?!?
    Vagy mégse?!?


    Azt ugye már tudjuk hogy pixel szinten pontosan ugyan az! (Velvárt András Silverlight 3 Konferencia 16:50)

    De mi azt akarjuk!!! megtudni mi van ténylegesen a DataGrid hátulján.
    Ehhez a következőkre lesz szükségünk:

    • Silverlight 3 VSM
    • Silverlight 3 Projection

     

    Első körben mindent Visual Studio-val oldunk meg, második felvonásban pedig Blend 3-al.

    1. Hozzuk létre a vezérlőnk class-át, melybe felvesszük az vezérlőt, és a hátulját :
      public class ControlAndBack:ContentControl
          {
              private UIElement frontControl;
              public UIElement FrontControl
              {
                  set
                  {
                      frontControl = value;
                      SetFrontAndBack();
                  }
                  get
                  {
                      return frontControl;
                  }
              }
      
              private ContentControl front;
              private ContentControl back;
              private void SetFrontAndBack()
              {
                  if (front != null)
                  {
                      front.Content = FrontControl;
                  }
                  if (back != null)
                  {
                      back.Content = BackControl;
                  }
              }
      
              private UIElement backControl;
              public UIElement BackControl
              {
                  set
                  {
                      backControl = value;
                      SetFrontAndBack();
                  }
                  get
                  {
                      return backControl;
                  }
              }
      }

      (az eljárásról a további pontokban)
      Ebben két property-ben tároljuk a vezérlőnk elejét, és hátulját.
      (a viccet félre téve, így bármelyik vezérlőnk hátuljára el tudunk helyezni bármit)

    2. Hozzuk létre a Themes\generic.xaml-t, és abban a vezérlőnk stílusát:
      <Style TargetType="local:ControlAndBack">
          <Setter Property="Template">
              <Setter.Value>
                  <ControlTemplate TargetType="local:ControlAndBack">
                      <Grid>
                          <Grid.ColumnDefinitions>
                              <ColumnDefinition Width="Auto"></ColumnDefinition>
                              <ColumnDefinition></ColumnDefinition>
                              <ColumnDefinition Width="Auto"></ColumnDefinition>
                          </Grid.ColumnDefinitions>
                                         
                          <Button x:Name="btnLeft" Grid.Column="0" Content="&lt;"></Button>
                          
                          <ContentControl x:Name="BackContentControl"
                              Grid.Column="1"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                          RenderTransformOrigin="0.5 0.5">          
                        
                          <ContentControl x:Name="FrontContentControl"
                              Grid.Column="1"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                          RenderTransformOrigin="0.5 0.5">
                                                 </ContentControl>
      
                          <Button  x:Name="btnRight" Grid.Column="2" Content="&gt;"></Button>
                      </Grid>
                  </ControlTemplate>
              </Setter.Value>
          </Setter>
      </Style>


      A vezérlőnk template-je nem más mint 2 gomb (balra-jobbra) ill. 2 ContentControl amiből egyszerre majd csak egy fog látszani.

    3. Osztály konstruktora, hogy egymásra találjon az osztály és a template:
      public ControlAndBack()
           {
               this.DefaultStyleKey = typeof(ControlAndBack);
           }
    4. override OnApplyTemplate, hogy egymásra találjon a Template-ben lévő vezérlő, és az osztály implementációja:
      public override void OnApplyTemplate()
          {
              //base.OnApplyTemplate();
      
              front = this.GetTemplateChild("FrontContentControl") as ContentControl;
              back = this.GetTemplateChild("BackContentControl") as ContentControl;
      
              Button b = this.GetTemplateChild("btnLeft") as Button;
              b.Click += new RoutedEventHandler(Change_Click);
      
              b = this.GetTemplateChild("btnRight") as Button;
              b.Click += new RoutedEventHandler(Change_Click);
      
      
              SetFrontAndBack();
          }
    5. Vezérlő Projection-beállítása:
      (hogy forgatni lehessen)
          <ContentControl x:Name="BackContentControl"
                                  Grid.Column="1"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                              RenderTransformOrigin="0.5 0.5">          
                                                         <ContentControl.Projection>
                                      <PlaneProjection RotationY="-270"></PlaneProjection>
                                  </ContentControl.Projection>
                              </ContentControl>
      
                              <ContentControl x:Name="FrontContentControl"
                                  Grid.Column="1"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                              RenderTransformOrigin="0.5 0.5">
                                                         <ContentControl.Projection>
                                      <PlaneProjection></PlaneProjection>
                                  </ContentControl.Projection>
                              </ContentControl>
      
    6. VSM elkészítése:
      (Hogy forogjon is. A két állapotban van megadva hogy mit és hogyan kell animálni mikor az adott állapotba érkezünk. Az egyik animáció előhozza míg a másik eltünkteni a megfelelő ContentControl-t)
      <vsm:VisualStateManager.VisualStateGroups>
                          <vsm:VisualStateGroup x:Name="PresentationStates" >
                              <vsm:VisualState x:Name="Front">
                                  <Storyboard>
                                  
      
                                      <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
      Storyboard.TargetName="BackContentControl"
      Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="-90"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00.3"
      Storyboard.TargetName="FrontContentControl"
      Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"> <DiscreteDoubleKeyFrame KeyTime="00:00:00.3" Value="-270" >
      </
      DiscreteDoubleKeyFrame> <EasingDoubleKeyFrame KeyTime="00:00:00.3" Value="-270"/> <EasingDoubleKeyFrame KeyTime="00:00:00.6000000" Value="-360"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name="Back"> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime="00:00:0.3" Storyboard.TargetName="BackContentControl" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"> <DiscreteDoubleKeyFrame KeyTime="00:00:00.3" Value="-270" >
      </
      DiscreteDoubleKeyFrame> <EasingDoubleKeyFrame KeyTime="00:00:00.3" Value="-270"/> <EasingDoubleKeyFrame KeyTime="00:00:00.6000000" Value="-359.999"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
      Storyboard.TargetName="FrontContentControl"
      Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:00.3000000" Value="-90"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </vsm:VisualState> </vsm:VisualStateGroup> </vsm:VisualStateManager.VisualStateGroups>
    7. Kódban állapotok közötti váltás:
      (Üzleti/vezérlő “logika”)
      private bool isFrontActive = true;
      void Change_Click(object sender, RoutedEventArgs e)
      {
          if (isFrontActive)
          {
              VisualStateManager.GoToState(this, "Back", true);
          }
          else
          {
              VisualStateManager.GoToState(this, "Front", true);
          }
          isFrontActive = !isFrontActive;
      }
    8. És teszt:
      <UserControl x:Class="ControlAndBack.MainPage"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:d=http://schemas.microsoft.com/expression/blend/2008
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480" Width="600" Height="400" xmlns:local="clr-namespace:ControlAndBack" > <Grid x:Name="LayoutRoot"> <local:ControlAndBack> <local:ControlAndBack.FrontControl> <Image Source="winter.jpg"></Image> </local:ControlAndBack.FrontControl> <local:ControlAndBack.BackControl> <Image Source="summer.jpg"></Image> </local:ControlAndBack.BackControl> </local:ControlAndBack> </Grid> </UserControl>

     

    Persze érdemes eljátszani az animációval, alignment-ekkel,stb…
    És persze érdemes megnézni a Toolkit-ben lévő TransitioningContentControl-t

    Forráskód:  skydrive
    ScreenCast letöltés : devportal
    Silverlight-link:

    November 25

    Instant Smooth HD tartalom elhelyezése weboldalunkra

     

    Azt hiszem mindenki találkozott már olyan weboldallal amin ugyan volt média/video elhelyezve, csak éppen a minősége és/vagy a (lejátszás) felhasználói élménye a 0-t közelítette.
    (ez egészen a kis álateledel webshopoktól egészen a nagy video-tartalom szolgáltatókon át az igazi nagyágyúkig… mindenki ismeri őket?!? ugye?!?)

    Mi sem egyszerűbb hogy ezen túllépjünk:

    Smooth Streaming

     

    Kell hozzá:

    Lépések

    1. Video beszerzése
      (kelleően jó minőségű, pl. 720p-1080p)
    2. Video enkódolása
      Történthet “kézzel” Expression Encoder-ben.
      1. New Job
      2. Import media
      3. Válasszuk ki a Smooth Streaming output formatot:
      image
      4. Adjunk meg igény szerint a különböző profilokat:
      image
      5. Adjunk meg Output template-t így egy kész Silverlight 3 lejtásztót tartalmazó HTML oldalt is kapunk.
      image 
      6. Encode :) ami eltart egy darabig… nagy fileoknál akár 10-20-60 perceket is, sőt!!!
      7. A kész output-ot másoljuk be az IIS7 alá, amibe már előtte telepítettük a Media Extension-t, ami képessé teszi Smooth Streaming-re
    3. Hogy megy ez “kézzel”, egészen pontosan kódda, c#-al?!?
      Új console app, majd adjunk referenciát a Expression Encoder SDK dll-ekre.
      "C:\Program Files\Microsoft Expression\Encoder 3\SDK"
      (Itt találunk pléda programot is!!!!)
      És…
    4. using System;
      using System.Collections.Generic;
      using System.Text;
      using Microsoft.Expression.Encoder;
      using Microsoft.Expression.Encoder.Live;
      using Microsoft.Expression.Encoder.Profiles;
      using System.IO;
      
      namespace Live
      {
          class Program
          {
              static void Main(string[] args)
              {
      
                  //
                  MediaItem mediaItem 
                  = new MediaItem(@"forras.mp4");
      
      
                  //ezt kell használni a profile-ok összeállítására....aspect ratio tartásával
                  Console.WriteLine("size={0}", mediaItem.VideoSize);
      
                  AdvancedVC1VideoProfile videoProfile = new AdvancedVC1VideoProfile();
      
                  // When you create a VideoProfile you'll get one stream by default.
                  // In this example remove that one as we’re going to explicity 
                  // add the three streams below.
                  videoProfile.Streams.RemoveAt(0);
      
                  //!!!!
                  // a megfelelő méret és aspect ration megadását meg kell csinálni,
                  // a forrás méretei alapján
                  // pl. érdemes puskázni az Expression Encoder default beállításaiból
                  // pl. ~3mbps, ~1600kbps, ~1200kbps, ~800kbps, ~500kbps
                  //  hozzá a megfelelő arányos méretekkel...
                  //!!!!
      
      
                  //videoProfile.Streams.Add(
                  //    new VariableConstrainedBitrate(1450, 1600),
                  //    new System.Drawing.Size(800, 600));
                  videoProfile.Streams.Add(
                      new VariableConstrainedBitrate(1050, 1600),
                      new System.Drawing.Size(640, 480));
                  videoProfile.Streams.Add(
                      new VariableConstrainedBitrate(600, 1600),
                      new System.Drawing.Size(400, 300));
      
                  // Use smooth streaming with automatically sized streams.
                  videoProfile.SmoothStreaming = true;
                  videoProfile.Streams.AutoSize = true;
      
      
                  mediaItem.OutputFormat.VideoProfile = videoProfile;
                  
                  Job job = new Job();
                  job.MediaItems.Add(mediaItem);
                  
      
                  // Set up the progress callback function
                  job.EncodeProgress 
                      += new EventHandler<EncodeProgressEventArgs>(OnProgress);
      
                  // Set the output directory and encode.
                  job.OutputDirectory = "c:\\temp";
      
                  job.CreateSubfolder = true;
                  job.Encode();
                
              }
      
              static void OnProgress(object sender, EncodeProgressEventArgs e)
              {
                  Console.WriteLine(e.Progress);
              }
      
          }
      }
      
    5. Majd az eredményhez a megfelelő lejátszó alkotása… ezt szintén lehet puskázni az Encoder által gyárott HTML-ből, esetleg puskázunk a forráskódból…
      (szintén megtalálható az SDK Sample könyvtárának bugyraiban…)

    Info : http://blogs.msdn.com/expressionencoder/archive/2009/07/29/9853000.aspx

    November 23

    Azure © oktatási anyagok

    Mindamellett hogy a PDC-ről letölthető számos előadás ill. a gyári blogokban kezdenek szállingózni a demok, oktatási példák, egy egész komoly anyag jelent meg a CH9-en is Azure-al kapcsolatban.

    (Step By Step jellegű, elég részletesek)

    http://channel9.msdn.com/learn/courses/Azure/

    November 22

    Ingyenes Ebook

     

    Találtam egy ingyenes könyvet, ennek apropóján gondoltam összeszedem, összeszedhetjük az ingyenes ebook-okat, amik elérhetők .Net technológiákról:

    Majd megjegyzésbe megy a többi…

    November 21

    Silverlight 3 – WCF-binary formatter

     

    Tudom tudom a 3 már történelem :D, de már az is tudta, hogy nem Soap borítékban mindenféle buta enkódlásban küldük át a bináris adat a kliensre, hanem binárisan. Ez persze alap a WCF-ben, de egy 3-4mbyte-os pluginban nem volt magától érthetődő (gondolom én), ezért pl. a SL2 nem is tudta (maradt a jó öreg basicHttpBinding-> HTTP+SOAP).

    Most egy (még) titkos projekt keretében bináris adatok kellene Server-Kliens kommunikációban Silverlight-ba küldeni, és azt tudtam hogy “komolyabb” binding-ot nem tud az SL, de rájöttem (rákerestem Google-ben és Bing-ben) hogy építeni tudok sajátot, így azzal megoldható a történet :
    (miért nem jutott ez eszembe magamtól is?!?!? )

     

     <customBinding>
            <binding name="binaryHttpBinding">
              <binaryMessageEncoding>         
              </binaryMessageEncoding>
              <httpTransport>           
              </httpTransport>
            </binding>
          </customBinding>
    <endpoint address="" binding="customBinding" bindingConfiguration="binaryHttpBinding"
          contract="IService">
              <identity>
                <dns value="localhost" />
              </identity>
            </endpoint>
    
    És kész… lőn bináris kommunikáció HTTP felett Silverlight-ban!