|
|
November 27 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:
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();
}
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();
}
-
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):
- PrintDocument létrehozása
- PrintPage-re iratkozás, és egy oldal megadása
- Print() metódus.
Ennyi… nem is bonyolult.
Forráskód: skydrive ScreenCast: devportal Silverlight Player : lejátszás
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. - 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)
- 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="<"></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=">"></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.
- Osztály konstruktora, hogy egymásra találjon az osztály és a template:
public ControlAndBack()
{
this.DefaultStyleKey = typeof(ControlAndBack);
}
- 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();
}
- 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>
- 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>
- 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;
}
- É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 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 - Video beszerzése
(kelleően jó minőségű, pl. 720p-1080p) - 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:
 4. Adjunk meg igény szerint a különböző profilokat:
5. Adjunk meg Output template-t így egy kész Silverlight 3 lejtásztót tartalmazó HTML oldalt is kapunk.
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 - 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…
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);
}
}
}
- 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 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 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 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!
|