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!
    October 22

    MEF, avagy készítsünk kiterjeszthető alkalmazásokat 0.

    Előbb vagy útóbb minden fejlesztő szembesül azzal a problémával, hogy olyan alkalmazást kellene írni, amely tulajdonképpen egy keretrendszer bizonyos alapfunkciókkal, amihez idővel újabb és újabb modulok kerülnek majd illesztésre.

    Ha ez egy zárt projekt, és mi vagyunk a fejlesztői a keretnek és a moduloknak is, akkor nem is biztos hogy “keretrendszert” építünk általános megoldásokkal, hanem egyszerűen add new project, add refenrece, aztán ‘jónapot, had ‘szóljon, hivatkozunk az új dolgokra, rebuild, már mehet is az új exe+dll valahogy a usereknek.

    Ez a megoldás gyors, egyszerű, ellenben ha sokan dolgozunk a projekten pl. *nd*aiakkal :D, és nem kellőképen dokumentált a fejlesztés módja, akkor egy nagy káosz kialakulásának leszünk jobb esetben csak szemtanui, rosszabb esetben résztvevői.
    Továbbá ez e megoldás kivitelezhetetlen, ha ténylegesen egy szuper-világmegváltó-hiperfrankó-keretrendszert alkottunk, pl. egy grafikai eszközt, egy hitel/pénzügyitermék-prortfóliót kezelő rendszert. És azt akarjuk hogy bárki a világon fejleszthessen hozzá (bizonyos feltételekkel) modulokat: egy új effectet, egy új terméket/jutalékszámító eszközt,stb.
    Ilyen esetben nem megoldás az hogy megkérjük a ‘világot hogy küldje már el a forráskódot, mi meg belefordítjuk… mert A usernek M modul, B usernek meg N modul kell, stb…

    Mit lehet tenni?

    Alkutunk egy saját leíró nyelvet: XML-ben össze lehet tenni a felületet, algoritmust, szabályokat, stb. Publikáljuk a “leírónyelvünk” specifikációját, és a modul futtatása nem más XML parszolás (saját parszerrel), majd futtatás…
    Egyszerű dolgoknál működik, sőt néha ez a “tökéletes” megoldás (pl workflow rule engine), de ugye látjuk a korlátait, nehézségeit?

    Nem marad más hátra, minthogy dll-t gyártatunk az önjelölt modulfejlesztőkkel, amit _nem_ teszünk be a keretalkalmazásba, és ezt a modult valahogy elérjük futási időben.
    Nos, ez ugye a Reflection .Net-ben.

    Milyen lehetőségeink vannak Reflection-el?

    • Nem adunk meg semmilyen kötöttséget, kivéve, hogy meghatározzuk 1<= “kulcs-pontot”. Ez lehet egy belépési pont, egy osztály, egy “programkód”,stb
      Pl. a keretalkalmazásunk nem tud mást mint, hogy az adott DLL-ben megkeresi az EztInditsdEl nevű (Form-ból származott) osztályt, példányosít egyet, és meghivja rajta a Show-t:
    • Assembly a = Assembly.LoadFile(dll_path);
                Type t = null;
                foreach (Type item in a.GetTypes())
                {
                    if (item.Name == "EztInditsdEl")
                    {
                        t = item;
                        break;
                    }
                }
      
                if (t!= null && t.BaseType == typeof(Form))
                {
                    ConstructorInfo ci= t.GetConstructor(new Type[0]);
                    object o= ci.Invoke(null);
                    Form f = o as Form;
                    f.MdiParent = this;                
                    f.Show();
                }
                else
                {
                    throw new Exception("hiba a modulban");   
                }

      Persze ezt lehet fokozni, konkrét osztálynevekkel, interfészekkel, attributumokkal, stb.
      Látszik, hogy nehézkes a használata: rengeteg reflection (minden egyes meghíváshoz, példányosításhoz, propertyhez,stb). ami ráadásul “lassú” is a late-binding miatt.
      Macera, megint.

    • A jól definiált “korlátokat”, kötelezettségeket határozunk meg, amiket be kell tartania a modul fejlesztőjének.
      Ezek tipikusan  baseclass-ok, interfészek, attribútumok, virtuális metódusok, stb…
      Ezeket betesszük egy külön DLL-be, mi adunk referenciát a DLL-re, és használjuk. A fenti megoldással szemben hatalmas az előnyünk. Reflection-t (szerencsés esetben) csak “egyszer” kell használnunk: a modul assembly betöltése után a “belépési” pont megkeresésésre és példányosítására.
      Utána már használhatjuk pl. a mi kis interfészünket.
      A modul fejlesztőjének nincs más dolga, mint az interfész megvalósítása (miután letöltötte az áltaunk publikussá tett DLL-t)

      Interfész:

      namespace ModulBase
      {
          public interface IModul
          {
              void Kiir(string mitirki);
      
              string Beolvas(string kerdes);
          }
      }
      Modul:
      namespace Modul1
      {
          public class MyModul:ModulBase.IModul
          {
              #region IModul Members
      
              public void Kiir(string mitirki)
              {
                  Console.WriteLine(mitirki);
              }
      
              public string Beolvas(string kerdes)
              {
                  Console.Write(kerdes);
                  return Console.ReadLine();
              }
      
              #endregion
          }
      }
      
      Alkalmazás:
    • Assembly a = Assembly.LoadFile(dll_path);
      ModulBase.IModul modul =null;
      foreach (Type item in a.GetTypes())
      {
         
          if ((item.GetInterface(typeof(ModulBase.IModul).FullName)) != null)
          {
              object o= item.GetConstructor(new Type[0]).Invoke(null);
              modul = o as ModulBase.IModul;
              break;
          }
      }
      
      if (modul != null)
      {
          modul.Kiir("alma");
          string valasz = modul.Beolvas("barack");
          Console.WriteLine(valasz);
      }
      else
      {
          throw new Exception("hiba a modulban");
      }

      Mint látható itt Reflection-t csak a példányosításra használjuk, utána már az interfészünkön keresztül programozzuk a modult.
      Halleluja. Mindkét fél élete egyszerű.
      De…

    (persze lehetne még fokozni, rengeteg egyéb ügyesebb-okosabb, de rosszabb megoldás is van…)

    Rengeteg olyan általános probléma van ami minden moduláris alkalmazásnál előjön. Tipikus generikus problémák amikre tipikus generikus válasz adható… Minek feltalálnunk újra a spanyolviaszt?!?!
    És mi van ha még a fenti intefész-DLL-t sem akarom odaadni, akarja használni a modul fejlesztője?!?!

    Ekkor jön be a MEF-Managed Extensibility Framework, amely választ ad ezen generikus problémákra, ill. előbb-útobb a .Net része lesz, vagyis elfogadottá válik, így máris megvan a “szerződés” a keret- ill. a modul-alkalmazás fejlesztője között…

    A témával egyelőre még nem foglalkoztam sokat, de amit láttam eddig az felkeltette az érdeklődésemet, így útjára indítok egy sorozatot, ami sorra veszi szépen a MEF-es fejlesztés mérföldköveit…

    October 20

    DragDrop Silverlight 3-ban

    Végre!
    Megérkezett a Drag&Drop támogatás a Silverlight 3-ban! Egészen pontosan a Silverlight Toolkit-ben!

    Bár még nem generikus a megoldás, de reméljük az lesz. Egyelőre a következők támogatják az adott vezérlőben a drag&drop-t:

    • ListBoxDragDropTarget
    • TreeViewDragDropTarget
    • DataGridDragDropTarget
    • DataPointSeriesDragDropTarget

    Használatuk ‘rémegyszerű:

    1. Silverlight Toolkit October telepítése
    2. Referenciát adunk a megfelelő silverlight és toolkit dll-ekre:
      c:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.Windows.Controls.dll
      c:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.Windows.Controls.Data.dll
      c:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.Windows.Controls.Data.Input.dll
      C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Oct09\Bin\System.Windows.Controls.Toolkit.dll
      C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Toolkit\Oct09\Bin\System.Windows.Controls.Data.Toolkit.dll
      c:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries\Client\System.Windows.Data.dll
    3. Aztán kellenek ugye a névterek is:
    4. xmlns:mswindows="clr-namespace:Microsoft.Windows;assembly=System.Windows.Controls.Toolkit"
      xmlns:datatoolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Toolkit"                             
      xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

    5. Ezek után használjuk a megfelelő DragDropTarget-et:
      toolkit:ListBoxDragDropTarget
      datatoolkit:DataGridDragDropTarget
      ….
    6. Ha egy elemet, pl. egy ListBox-t körbefogtunk egy ilyen elemmel, akkor máris tudunk belőle kiráncigálni elemet,elemeket:
      (az ItemsPanelTemplate felüldefiniálása, nem feltétlen szükséges, ez amiatt kell, hogy alapból virtualizált panel szerepel benne…)
    7. <toolkit:ListBoxDragDropTarget Name="lb1" >
               <ListBox Name="lb1">
                   <ListBox.ItemsPanel>
                       <ItemsPanelTemplate>
                           <StackPanel Orientation="Vertical" />
                       </ItemsPanelTemplate>
                   </ListBox.ItemsPanel>
               </ListBox>
           </toolkit:ListBoxDragDropTarget>
    8. Ahhoz  hogy Drop-ot is fogadjon engedélyezni kell ezt:

      <toolkit:ListBoxDragDropTarget mswindows:DragDrop.AllowDrop="True">
    9. És már csak egy megfelelő adatforrásra van szükségünk:

      var lst1 = new ObservableCollection<int>();
                lst1.Add(1);
                lst1.Add(2);
                lst1.Add(3);
                lb1.ItemsSource = lst1;
    10. Szokásos eseményekre természetesen mi magunk is reagálhatunk “kézzel”:
      DragEnter
      DragLeave
      DragOver
      Drop
      ItemDragStarting
      ItemDroppedOnSource
      ItemDroppedOnTarget

      Vagyis tudunk mindenféle jópofa UX dolgot csinálni, ill az ItemDragStarting el tudunk indítani egy elemet, ill a Drop-pal és a ItemDroppedOnSource/ItemDroppedOnTarget-el pedig reagálni tudunk mind a cél mind a forrás vezérlőn…

    Ha ezzel megvagyunk, akkor tökéletesen tudunk ide oda rángatni pl. ListBox-ból ListBoxba.

    dd

    A teljes kód (letöltés):

    <UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"  x:Class="sl3_drag_drop_demo.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" 
                 
        xmlns:mswindows="clr-namespace:Microsoft.Windows;assembly=System.Windows.Controls.Toolkit"
        xmlns:datatoolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Toolkit"                              
                 
        xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
                 
        mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
        <Grid x:Name="LayoutRoot">        
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <toolkit:ListBoxDragDropTarget Grid.Column="0"  mswindows:DragDrop.AllowDrop="True">
                <ListBox Name="lb1"   Background="LightBlue" MinWidth="50" MinHeight="150">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical" />
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>
            </toolkit:ListBoxDragDropTarget>
            <toolkit:ListBoxDragDropTarget Grid.Column="1" Drop="ListBoxDragDropTarget_Drop"  mswindows:DragDrop.AllowDrop="True">
                <ListBox Name="lb2" Background="LightYellow" MinWidth="50" MinHeight="150">
                    <ListBox.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Vertical" />
                        </ItemsPanelTemplate>
                    </ListBox.ItemsPanel>
                </ListBox>
            </toolkit:ListBoxDragDropTarget>
            <datatoolkit:DataGridDragDropTarget  mswindows:DragDrop.AllowDrop="True" Grid.Row="1" Grid.Column="0" >
            <data:DataGrid Name="grd1" ></data:DataGrid>
                </datatoolkit:DataGridDragDropTarget>
            <datatoolkit:DataGridDragDropTarget  mswindows:DragDrop.AllowDrop="True" Grid.Row="1" Grid.Column="1" >
                <data:DataGrid Name="grd2"></data:DataGrid>
            </datatoolkit:DataGridDragDropTarget>
        </Grid>
    </UserControl>

    http://timheuer.com/blog/archive/2009/10/19/silverlight-toolkit-adds-drag-drop-support.aspx

    June 19

    .Net 2.0-3.5 AKCIÓS képzések @ NetAcademia

    Sziasztok!

    Engedjétek meg, hogy közzétegyek egy kis reklámot.

    Aki (vagy a cég ahol dolgozik) esetleg mostanában tervezett .Net képzést, annak figyelmébe ajánlom a következő tanfolyamokat:
    (A szokásosnál jóval kedvezőbb áron… pláne ha lapul a cég fiókjában egy két Vócser)

    A fejlesztői tanfolyam kódja

    Akciós dátum:

    Hossz:

    A C# 3.0 . NET Framework programozási nyelv (50150)

    2009.06.29.

    5 nap

    Microsoft .NET 2.0 fejlesztési alapismeretek (2956/2957)

    2009.07.06.

    5 nap

    Webalkalmazás fejlesztése .NET Framework 2.0 - 3.5-ben (2543/2544/2310)

    2009.07.20.

    5 nap

    Visual Studio ADO.NET 3.5 (6464)

    2009.07.27.

    3 nap

         

    A C# 3.0 . NET Framework programozási nyelv (50150)

    2009.08.03.

    5 nap

    Adatelérés fejlesztése Visual Studio 2005-ben (2541/2542)

    2009.08.24.

    5 nap

    Webalkalmazás fejlesztése .NET Framework 2.0 - 3.5-ben (2543/2544/2310)

    2009.08.31.

    5 nap

         

    Windows Presentation Foundation (6460)

    2009.09.07.

    3 nap

    Microsoft Windows Communication Foundation (6461)

    2009.09.14.

    3 nap

     

    A fenti táblázatban szereplő tanfolyamok ára a tanfolyam hosszától és a megrendelés leadásának időpontjától függ:

    A megrendelés időpontja:

    A képzés fapados ára 5 napos oktatás esetén:

    Június 30-ig

    159.000 Ft + ÁFA

    A megrendelés időpontja:

    A képzés fapados ára 4 napos oktatás esetén:

    Június 30-ig

    149.000 Ft + ÁFA

    A megrendelés időpontja:

    A képzés fapados ára 3 napos oktatás esetén:

    Június 30-ig

    139.000 Ft + ÁFA

    Július 1. után a „fapados” jelentkezési lehetőség véget ér, a tanfolyamokra ezt követően az adott tanfolyam listaárán lehet regisztrálni. SA vouchert elfogadunk!

    Bővebb információ: www.netacademia.net/nyariakcio

    April 17

    MVP

    Egy kicsit csendben voltam blog ill. cikk írás dologban az elmúlt hónapokban.MVP_Horizontal_BlueOnly
    (remélem ez most újra megváltozik majd)

    Szerencsére
    ennek az volt az oka, hogy eléggé elfoglalt voltam munka ügyben. Számos rendezvény volt ahol részt vettem és ‘jópár tanfolyamot tartottam mindeközben. (és tartok folyamatosan)

    Az elmúlt egy-másfél én munkája, köztük a fenti rendezvények, alapján a Microsoft érdemesnek tartott arra hogy tagja legyek a magyarországi MVP csapatnak.
    Április elsején :))) MVP címmel jutalmazott, Client App Dev “témakörben”.

    Hogy mi is az az MVP cím?!?
    Azt hiszem ezt sokkal jobban leírták már nálam:

    A program keretében ezentúl számos dologhoz hozzáférhetek a publikussá válása előtt (persze mindenféle NDA mellett), könnyen kapcsolatot teremthetek mindenféle Product Grouppal az Olimposzon ( Seattle-Redmond-Microsoft HQ), talán még el is juthatok oda jövőre, és még sok minden egyéb…

    Remélem, hogy így még hasznosabban tudok majd részt venni a hazai .Net életben

     

    És a lényeg :
    (nem udvariasságból, hanem őszintén, tényleg!!!)

    Köszi mindenkinek : NetAcademia, Microsoft-os “kollégák”
    nélkületek nem jöhetett volna ez létre :)))

    Rendezvény, meghívó, Azure, Silverlight, Sync Services

     

    Egy Május 4.-én Szegeden megrendezésre kerülő eseményre szeretném felhívni a figyelmet, ahol lesz szerencsém előadni egy témában.

    Akit érdekelnek a következő témák, és Szeged közelében lakik az jöjjön el:

    • AZURE, cloud computing
    • Silverlight 3, RIA
    • Sync services

    Az előadásokat Bátorfi Zsolt barátom fogja felvezetni a szokásos :) ‘mivel fogunk találkozni a következő hónapokban, évben a platformon és körülötte témával.
    Ezek után 3 MVP tart 3 előadást Silverlight, RIA és Sync Services témakörben.

    Helyszín és időpont:
    2009. május 4. 9.00 – 15.00, Ipari Kamara, Szeged

    További részletek, jelentkezés : http://devportal.hu/content/usergroupszeged.aspx

    Fejlesztői MCP (Microsoft Certified Professional)

    image

    Get certified…

    A tanfolyamaim során gyakorlatilag minden esetben előjönnek az MCP vizsgák. Bár ma Magyarországon annyira nem mindennapos, hogy a megszerzett tudásunkat bizonyítsuk egy bizonyítvány segítségével. Hogy ez miért így van arról rengeteget lehetne ötletelni, gondolkodni. De most nem ez a lényeg.

    ‘Hanem az, hogy legtöbbször nincsenek tisztában az emberek a vizsgákkal, azok egymásra épülésével, ill. hogy ezek milyen kapcsolatban vannak a minősítésekkel. Az is kicsit zavaros hogy milyen kapcsolatban van a 2.0 és 3.0/3.5. Honnan érdemes kezdeni.

    Lássuk!

    Érdemes az elején leszögezni, hogy a 2.0-s dolgokra szükség van. Leszámítva egy két dolgot, gyakorlatilag tekinthetjük úgy, hogy a 3.0-3.5 az egy szép nagy kiegészítése a 2.0-nak, megfordítva a 3.0-3.5 a 2.0-ra épül.

    Képzeljük magunkat egy olyan ember helyzetébe, aki most ismerkedik a .Net-tel, most akar elmélyedni benne, szakemberré válni. Hogy egy frissen végzett egyetemistáról, egy áttérő/megtérő :) Delphi-s/JAVA-s ról van szó, vagy hobbyprogramozóról, az mindegy.

    Tehát e leendő szakember rendelkezik általános ismeretekkel, és van fogalma arról hogy mi az a programozás, mi az a ciklus, és alap OOP ismeretekkel is rendelkezik.
    (ha nem, akkor…)

    Természetesen önálló tanulással, könyvekkel, gyakorlással, munkahelyen tapasztalatszerzéssel, image -val , screencastokkal és sok más egyéb segítségével is meg lehet szerezni a tudást. Én itt most a “hivatalos”, azaz MS tanfolyami útra fókuszálok :

    1. Az első tanfolyam amire be kell ülnie az a C# nyelv mélységeibe bevezető 5 napos szeánsz:
      Két lehetőség adódik : 2124 vagy 50150
      Én ez utóbbit javaslom, pláne hogy az elsőn is gyakorlatban ugyan az anyag :)

      E tanfolyam után a jelölt elölről hátulról ismerni fogja a c# 3.0 nyelvet. Persze csak ha sokat gyakorol…
    2. A következő tanfolyam a sokat megélt 2956/2957.
      Ez nem mást a .Net keretrendszer megismerését szolgálja. Sokrétű tanfolyam, rengeteg fejezettel. Olyanokkal is amiket valószínűleg soha nem fog használni az ember, de ez is fontos ahhoz hogy egy “szemlélet” kialakuljon az emberben a .NET-tel, mint platformmal kapcsolatban.

      Ha ez abszolválásra kerül, akkor rendelkezésre állnak az alapvető építőkockák, ezek kombinációja, kapcsolata. Tehát még nem fogunk tudni profi web/desktop alkalmazást írni, de jó úton haladunk afelé!

      E tanfolyam után van lehetőség az első megmérettetésre : 70-536
      Ez az egyik legsokrétűbb vizsga. A fenti linken található leírásban szereplő témakörök gyakorlatilag 80-90%-ra tuti rákérdeznek. Ha megvan ezekké váltunk :
      image

      Ez a vizsga azért is fontos, mert erre épül minden további 2.0 és 3.0-3.5-s minősítés is!!!
    3. Leszámítva egy két esetet a sok ezerből amikor nincs szükség adatelérésre, a legtöbb alkalmazás adat intenzív. Tehát még mielőtt elkezdenénk mindenféle formokat dobálgatni, esetleg asp.net oldalakat készíteni, szükséges hogy megismerkedjünk az alapvető adatkezelési/adatelérési lehetőségekkel.

      Itt több lehetőség adódik, de szerintem érdemes itt is a 2.0-s alapokkal kezdeni : 2541/2542
      (azért ezen a tanfolyamon is el szokott már hangzani egy két “újdonság” : LINQ,EF)
      Ezek után/mellett/helyett (a helyzettől függően) érdemes lehet még megismerkedni a következőkkel : LINQ  és Entity Framework

      2.0-s vizsga nincs kifejezetten ADO.Net-ből, mert a desktop ill a webes vizsga tartalmazza.
      Ellenben 3.0s vizsga van, és tartozik is hozzá minősítés : 70-561 
      image
    4. Az első döntési ponthoz értünk. Vagy WEB vagy DESKTOP vagy ELOSZTOTT rendszer fejlesztők leszünk…(vagy ezek bármilyen variációja)

      WEB esetén : 2543/2544/2310
      Ez a tanfolyam bemutatja az ASP.Net 2.0-3.5 fejlesztés trükkjeit
      Vizsga : 70-528     70-562    (kinek melyik a cél…2.0 – 3.5)
      image

      WinForms esetén : 2546/2547
      Mivel hogy 3.0-s Winforms nincs :))) ezért ez a tanfolyam a 2.0-ról szól…
      (OFF : Ha 0-ról kezdenénk el most desktop alkalmazást fejleszteni érdemes a WPF-el megismerkedni, és az alapján dönteni. lsd. lent)
      Vizsga : 70-526    70-505
      image

      Eloszott rendszer esetén : 2548/2549
      Vizsga : 70-529

      Itt fontos lehet, hogy számos olyan dolog van a tanfolyamban, amit lehet már soha nem fogunk használni, ‘merthogy már WCF-t használunk :)
      Érdemes tehát átnézni a tematikát és eldönteni hogy mit is fogunk/kell használni.
      Valószínűleg arra fogunk jutni hogy érdemes csak WCF tanfolyamra elmennünk… ezt lsd. lent.
    5. Ha már szereztünk egy kis gyakorlatot, akkor mehetünk tovább Professional szintekre (MCPD).

      Ezekre tanfolyam nincs, pontosabban a tanfolyam maga az élet :)
      A vizsgán szereplő kérdések legtöbbje tervezési, biztonsági, architekturális témakörbe tartozik. Tehát sokkal kevesebb a konkrét technológia kérdés, viszont annál több a fifikás tervezési kérdés: kapunk egy 1 oldalas szituációt, amelyben el van “rejtve” 5-10 kulcsszó, majd felteszik a kérdést valamire fokuszálva (sebesség, biztonság, stb) és meg kell találunk az erre passzoló választ…
      figyelni kell mert lehet mind jó, csak az egyik gyorsabb, a másik nem biztonságos,stb. Tehát itt nem arra kíváncsiak hogy tudunk e szintaktikai hibát keresni…

      Vizsgák :
      WEB: 70-547      70-564
      image
      Desktop : 70-548      70-563 
      image

      Kifejezetten distributed MCPD nincs, van helyette enterprise. Szükséges hozzá mindhárom technológiai alap szint.
      Az MCPD:EA szakember nem más, mint aki ismeri WEB/DESKTOP és többrétegű/elosztott rendszerek fejlesztését, és tervezését.
      Tulajdonképpen ez a technológiai csúcs, és talán már túl is van ezen : architekt.
      Enterprise : 70-549    70-565
      image

      Mint látható itt is megvan a 2.0 – 3.5 “szint”. El kell döntenünk hogy melyikre van szükségünk. A 3.5-ös minősítéshez a 3.5-ös techn. szintek szükségesek.
      MCDE:EA-hoz pedig a ADO.NET+WCF+WinForms+ASP.Net 3.5
    6. ++
      A három alap foundation-ből szintén lehet minősítést szerezni.

      Workflow:
      Akkor lehet kifejezetten szükséges, ha folyamat szemléletű elosztott alkalmazást fejlesztünk.
      Érdemes vele ismerkedni, hasznos technológia. Továbbá érdemes odafigyelni a 4.0-s változatra, mert rengeteg fejlesztés történt!
      Tanfolyam : 6462 
      Vizsga  : 70-504
      image

      WCF:
      Fontosságát nem lehet eléggé hangsúlyozni. Gyakorlatilag ha elosztott rendszereket akarunk fejleszteni (3.5-el), akkor nem fogjuk tudni kikerülni, merthogy ez maga a szükséges technológia.
      Rengeteget lehet róla hallani, sokszor kerül elő. A ma létező majdnem összes kommunikációs lehetőséget támogatja, sőt sajátokat is fejleszthetünk….
      Tanfolyam : 6461
      Vizsga: 70-503
      image

      WPF:
      A következő generációs megjelenítési réteg. Minden ez irányba mutat. Ha valaki most kezd el 0-ról desktop alkalmazást fejleszteni, érdemes ezzel ismerkednie!
      Tanfolyam: 6460
      Vizsga: 70-502
      image
    7. +++
      Minősítés, egyelőre, nincs hozzá de nem hagyható ki a felsorolásból a Silverlight 2 (3).
      Ugye nem kell bemutatni?!?

      Tanfolyam : SL2
    8. Upgrade

      Ha valakinek esetleg van már 2.0 minősítése, akkor lehetőség van az upgrade-re, és akkor több vizsgát letudhat egy alkalommal, ez ugye idő és pénz takarékos megoldás.
    9. és…. lassan jönnek a 2010-es minősítések is…
    10. Master-Architekt szint…
       image
      Sajna egyelőre fejlesztőknek nem szól a program. Talán majd egyszer…

      Miről szól:
      Néhányszor 5-10 év eltelte után, ha időnk-pénzünk-kapcsolataink megengedik, akkor részt vehetünk egy több hetes kiképzésen Redmondban, melynek a végén sikeres vizsga után Master minősítést kaphatunk.
      Újabb éveket szentelve a történetnek, és komolyabb (sikeres) projekteket letéve az asztalra, hírnevet szerezve akár Architect minősítésünk is lehet. De ilyenből kb 100-150 van a világon.
      Masterből talán kicsit több…
      http://www.microsoft.com/learning/mcp/architect/default.mspx
      http://www.microsoft.com/learning/mcp/master/default.mspx
    11. MCT
      Trainer, azaz oktatói minősítés.
      Ha valaki hívatásos MS oktató akar lenni, akkor annak meg kell szereznie a megfelelő minősítést a fentiek közül, és utána egy “alkalmassági” vizsgán kell átesnie…
      http://www.microsoft.com/learning/mcp/mct/default.mspx
    12. MVP
      Nem vizsgával szerezhető “cím”/elismerés (nem minősítés).
      Hanem aki sokat tesz a közösségért, a technológiáért mint elismert szakember azt jutalmazhatják ezzel a címmel.

      Bővebb információk :
      http://www.microsoft.com/hun/technet/tc/?id=ad4953e2-b693-4960-bf5e-5140f9c51385
    13. Beta vizsgák:
      A tényleges vizsga megjelenése előtt lehetőség van ingyen vizsgázásra korlátozott számban.
      Ennek nem tudjuk meg azonnal az eredményét, csak mikor megjelenik a tényleges vizsga.
      Ha a felső X%-ban vagyunk, akkor megkapjuk a rendes végleges minősítést.
      Jellemzői hogy A-Zig mindenre rákérdeznek. Tehát sok a kérdés, hosszú a vizsga, és nincs hozzá training kit :)))

      Megpróbálni meglehet, bliccelni nincs értelme.

      Infók:

      http://blogs.technet.com/betaexams
      http://blogs.msdn.com/trika
      http://blogs.msdn.com/gerryo/

     

    Ugyan a vizsga nem olcsó (pláne a tanfolyam), de én úgy gondolom hosszútávon, esetlegesen külföldi munkavállalásban gondolkodva mindenképp előny (lehet).

    Természetesen a megszerzett “papír” soha nem helyettesíti a tudást és a tapasztalatot.

    Egyéb infók :

    Ha van kérdése valakinek, ne tartsa vissza!!!
    Itt… a NetAcademia-nál, vagy a http://www.devportal.hu/ megfelelő forumában!

    January 22

    Saját LINQ provider készítése (LINQ 2 MyWebService)

    Szerény LINQ tapasztalataim azt mutatják (nem reprezentatív, meg persze a kivételek…), hogy az emberek nagy többsége nem úgy közelíti meg a LINQ-t ahogy azt kellene (szerintem).

    A legtöbb ember fejében a következő egyenlőség él :

    LINQ == LINQ 2 Sql

    Máshogy fogalmazva a LINQ 2 Sql maga a LINQ. Hogy ez miért van így az egy másik érdekes kérdés, részben mert azzal találkozik az ember először, mert ezzel demóznak mindenhol, és mert legtöbbször adatbázissal dolgozunk és ekkor adódik ugye maga LINQ 2 SQL.

    Furcsállják is a tanfolyam-hallgatók, amikor a 2 napos LINQ tanfolyam első felében LINQ 2 Object-ről beszélünk, saját providert írunk, stb…
    A végére persze mindenki megtanulja,  hogy a LINQ 2 Object+c#3.0 maga a LINQ , és ezeknek a következménye, pontosabban a providerek következménye, az hogy van olyan is hogy LINQ 2 Sql.

    Mi köze ennek a blogbejegyzés címében előrevetített témához?!?
    Hát mindösszesen annyi, hogy ahhoz hogy valaki saját providert írjon viszonylag mélyen kell ismerni a LINQ-t, azaz a LINQ 2 Object-et és a c# 3.0 újdonságait.

    Tehát mielőtt tovább olvasnád, javaslom ezen témakörök átbogarászását:

    Ha ez megvolt… akkor bele is vághatunk.

    LINQ 2 akármiből tízesével lehet találni a google-ön. De hogy?!?

    Első gyors megoldás, hogy kiterjesztjük az osztályunkat IEnumberable- interface-el, és máris LINQ alatt felhasználhatóvá vált az osztály query irására. Előnyei : mindösszesen 2 perc szükséges fejlesztés. Hátrányai : látszólagos, és sok esetben nem skálázható, nem finomítható… Persze ettől még sok esetben jó megoldás lehet.

    Ha pl. az adatforrás, ahonnan kapjuk az adatokat egy hagyományos WS, ami XML-ben adja vissza az adatokat, és a feladat az, hogy mi ne “lássuk” a WS-t, csak egy halom(List<>) adatot kapjunk, akkor adódik a megoldás hogy készítünk egy wrapper osztályt, ami megvalósítja a fent említett interface-t. Mégpedig úgy hogy lekéri az összes terméket az összes tulajdonságával… mindig. Aztán majd a LINQ query elmolyol rajta: leszűri amire kell, és kiválogatja a megfelelő tulajdonságokat…

    public class ProductSearch_bad : IEnumerable<Product>
       {
           #region IEnumerable<Product> Members
    
           public IEnumerator<Product> GetEnumerator()
           {
               return (IEnumerator<Product>)((IEnumerable)this).GetEnumerator();
           }
    
           #endregion
    
           #region IEnumerable Members
    
           IEnumerator IEnumerable.GetEnumerator()
           {
               ProductWS.Service1SoapClient client = new Linq2WebService.ProductWS.Service1SoapClient();
    
               string ret = "";
               try
               {
                   //fontos hogy mindig az összes lejön!!!!
                   ret = client.GetAll();
               }
               catch (Exception ex)
               {
    
               }
    
               XDocument xdoc = XDocument.Parse(ret);
    
               var q = from x in xdoc.Descendants("product")
                       select
                       new Product()
                       {
                           ProductID = int.Parse(x.Attribute("ProductID").Value),
                           Name = x.Element("Name").Value,
                           ProductNumber = x.Element("ProductNumber").Value,
                           ListPrice = x.Element("ListPrice").Value
                       };
               Console.WriteLine("WS : letöltöttem {0} db terméket",q.Count() );
               return q.GetEnumerator();
           }
    
           #endregion
       }
    
    Használata:
    Console.WriteLine("Most jól elkérjük a WS-től az összeset:");
               ProductSearch_bad search_bad = new ProductSearch_bad();
    
               var qq = from pp in search_bad
                         where pp.Name.Contains("b")
                        select pp;
    
               foreach (var item in qq)
               {
                   Console.WriteLine(item.Name);
               }

    Ugye mindenki látja hogy miért nem jó (2 kell de 20 jön át) a megoldás? Annak ellenére hogy a (kódot) “felhasználó” programozó örül majd mind majom a fa…nak, mert sose volt még ilyen egyszerű adatelérése.

    A megoldás adódik: valahogy át kell juttatni a feltételeket, és a kért mezőket, a “túloldalra”, ami ezek után csak tényleges adatokat adja majd vissza.

    Ehhez elég lesz néhány osztály és pár 10 sor kód. A kódolást több oldalról el lehet kezdeni (TOP-Down, Down-TOP), én az elejéről kezdem.

    1.Kell egy WS ami tud feltételeket kezelni, és mezőket válogatni:

    [WebMethod]
          public string GetProducts(string name,string productnumber,string cols)
          {
              AdventureWorksDataContext dc = new AdventureWorksDataContext();
    
    
              XDocument xdoc;
              xdoc = new XDocument(new XElement("Products",
                  (from p in dc.Products
                   where (String.IsNullOrEmpty(name) || p.Name.ToLower().Contains(name.ToLower())) &&
                          (String.IsNullOrEmpty(productnumber) || p.ProductNumber.ToLower().Contains(productnumber.ToLower()))
                   select ProductSelector(cols,p)
                  )
                  ));
    
              return xdoc.ToString();
          }
    
          private object ProductSelector(string cols, Product p)
          {
              XElement ret = new XElement("product",
                       new XAttribute("ProductID", p.ProductID)
                       );
              if (cols.Contains("Name")) ret.Add(new XElement("Name", p.Name));
              if (cols.Contains("ProductNumber")) ret.Add(new XElement("ProductNumber", p.ProductNumber));
              if (cols.Contains("ListPrice")) ret.Add(new XElement("ListPrice", p.ListPrice));
              return ret;
          }

    Látható hogy a WS a feltételeknek megfelelően fog csak adatokat visszadni, sőt! csak az adott oszlopokat fogja visszaadni!
    Itt jegyezném meg hogy a példa moricka, azaz nem kezel hibákat, sok mindent nem tud… és bele lehet kötni 5 helyen… természetesen éles szituációban tovább kell gondolni

    2/1. Kliens oldal

    Így akarjuk használni :

    var q = from p in new ProductSerach()
                      where p.Name == "Race" && p.ProductNumber == "1"
                      select new
                      {
                          p.Name            
                      };
    
              foreach (var item in q)
              {
                  Console.WriteLine(item.Name);
              }

    Tehát kell egy segédosztály, ami IEnumerable<Product>, ez tuti :

    2/2. Segéd osztály1

    public class Product
       {
           public int ProductID { get; set; }
    
           public string Name { get; set; }
    
           public string ProductNumber { get; set; }
    
           public string ListPrice { get; set; }
       }

    2/3 Segéd osztály2

    public class ProductSerach : IEnumerable<Product>
       {
           private ProductQueryCriteria _criteria;
           //default
           private string cols = "Name|ProductNumber|ListPrice";
    
           public ProductSerach Where(Expression<Func<Product, Boolean>> predicate)
           {
               _criteria = new ProductSearchExpressionVisitor().ProcessExpression(predicate);
               return this;
           }
    
           public ProductSerach Select<TResult>(
             Expression<Func<Product, TResult>> selector)
           {
               cols = new ProductSelectExpressionVisitor().ProcessExpression(selector);
               return this;
           }
    
    
           #region IEnumerable<Product> Members
    
           public IEnumerator<Product> GetEnumerator()
           {
               return (IEnumerator<Product>)((IEnumerable)this).GetEnumerator();
           }
    
           #endregion
    
           #region IEnumerable Members
    
           System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
           {
              
               IEnumerable<Product> prods = ProductHelper.PerformQuery(_criteria,cols);
    
               return prods.GetEnumerator();
           }
    
           #endregion
       }
    public class ProductQueryCriteria
       {
           public string ProductNumber { get; set; }
    
           public string Name { get; set; }
       }

    Mi van ebben az osztályban?!?

    • 2 segédváltozó, amelybe gyűjtjük a szükséges adatokat : where feltételek, select feltételek
    • IEnumberable megvalósítás, amely szükség esetén elvégzi a tényleges adatelérést. lsd később…
    • Select és a Where metódus
      Nos ez már érdekes. Nagyon.

      Mit tud? Azt hogy ez nem egy Statikus Extension Method, MÉGIS meghívódik, még mielőtt a GetEnumerator() lefutna, így fel tudunk készülni.
      Hogy hogy?!? Ez a query expression pattern

      Másik fontos dolog, hogy ez nem magát a lambda kifejezést várja, hanem csak az expression tree-t!

    Tehát ez az osztály bitosítja az enumerálhatóságot, szép magyarosan.

    2/4. Segéd osztály3

    Fel kellene dolgozni magát a Where részt:

    public class ProductSearchExpressionVisitor
      {
          ProductQueryCriteria _Criteria;
        
    
          public ProductQueryCriteria ProcessExpression(Expression expression)
          {
              _Criteria = new ProductQueryCriteria();
              VisitExpression(expression);
              return _Criteria;
          }
    
          private void VisitExpression(Expression expression)
          {
              if (expression.NodeType == ExpressionType.AndAlso)
              {
                  VisitAndAlso((BinaryExpression)expression);
              }
              else if (expression.NodeType == ExpressionType.Equal)
              {
                  VisitEqual((BinaryExpression)expression);
              }          
              else if (expression is LambdaExpression)
              {
                  VisitExpression(((LambdaExpression)expression).Body);
              }
          }
    
          private void VisitAndAlso(BinaryExpression andAlso)
          {
              VisitExpression(andAlso.Left);
              VisitExpression(andAlso.Right);
          }
    
          private void VisitEqual(BinaryExpression expression)
          {
                     if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
                (((MemberExpression)expression.Left).Member.Name == "ProductNumber"))
              {
                  if (expression.Right.NodeType == ExpressionType.Constant)
                      _Criteria.ProductNumber = (String)((ConstantExpression)expression.Right).Value;
                  else if (expression.Right.NodeType == ExpressionType.MemberAccess)
                      _Criteria.ProductNumber = (String)GetMemberValue((MemberExpression)expression.Right);
                  else
                      throw new NotSupportedException("Expression type not supported for ProductNumber: " + expression.Right.NodeType.ToString());
              }
              else if ((expression.Left.NodeType == ExpressionType.MemberAccess) &&
                (((MemberExpression)expression.Left).Member.Name == "Name"))
              {
                  if (expression.Right.NodeType == ExpressionType.Constant)
                      _Criteria.Name = (String)((ConstantExpression)expression.Right).Value;
                  else if (expression.Right.NodeType == ExpressionType.MemberAccess)
                      _Criteria.Name = (String)GetMemberValue((MemberExpression)expression.Right);
                  else
                      throw new NotSupportedException("Expression type not supported for Name: " + expression.Right.NodeType.ToString());
              }
            
          }    
    
      }

    (fontos dolgok kiemelve)

    Elsőre bonyolult, másodikra még inkább. Sajna át kell látni az Expression-t A-Z-ig. (Albert István)
    Tehát ha megtaláljuk a megfelelő hivatkozást pl. egy mezőre való szűrést, ami jelen esetben egy Contains lesz tulajdonképpen (lehetett volna metódushívás vizsgálat a contains-re, de én direkt az == operandust használom erre), akkor ezt megjegyezzük (segédosztály), és megyünk tovább rekurzívan…

    Ezt az igények szerint el lehet bonyolítani…

    2/5. Segéd osztály4

    Select feldolgozása:

    public class ProductSelectExpressionVisitor
      {
          string cols;
    
          public string ProcessExpression(Expression expression)
          {
              cols = "";
              VisitExpression(expression);
              return cols;
          }
    
          private void VisitExpression(Expression expression)
          {
              if (expression is LambdaExpression)
              {
                  VisitExpression(((LambdaExpression)expression).Body);
              }
              if (expression is NewExpression)
              {
                  VisitNewExpression((NewExpression)expression);
              }
          }
    
          private void VisitNewExpression(NewExpression newExpression)
          {
              //EZ NEM A TELJES MEGOLDÁS, CSAK EBBEN AZ ESETBEN működik
    
              //ez csak abban az esetben működik, ha az anonymous tipusban CSAK a product osztály 
              // tulajdonságai vannak, azonos névvel!!!!
    
              //amilyen bonyolult Select-et akarunk írni, úgy kell "elbonyolítani" a bejárást...
              foreach (var item in newExpression.Constructor.ReflectedType.GetProperties())
              {
                  cols += "|" + item.Name;
              }
          }
    
          private void VisitAndAlso(BinaryExpression andAlso)
          {
              VisitExpression(andAlso.Left);
              VisitExpression(andAlso.Right);
          }
    
      }

    Ez CSAK abban az esetben működik, ha anonymous tipust akarunk csinálni belőle, a megfelelő mezőket válogatva….
    Ezt is lehet tovább fokozni, hogy ha az Anonymous type nem ilyen egyszerű.

    2/6. Lekérdezés elvégzése:

    public static class ProductHelper
        {
    
            static internal IEnumerable<Product> PerformQuery(ProductQueryCriteria criteria, string cols)
            {
                ProductWS.Service1SoapClient client = new Linq2WebService.ProductWS.Service1SoapClient();
    
                string ret = "";
                try
                {
                    ret = client.GetProducts(criteria.Name, criteria.ProductNumber, cols);
                }
                catch (Exception ex)
                {
                                    
                }            
    
                XDocument xdoc = XDocument.Parse(ret);
    
                var q = from x in xdoc.Descendants("product")
                        select
                        CreateProductFromCols(cols,x);
                return q;
            }
    
            private static Product CreateProductFromCols(string cols,XElement x)
            {
                Product ret = new Product() { ProductID = int.Parse(x.Attribute("ProductID").Value) };
    
                if (cols.Contains("Name")) ret.Name = x.Element("Name").Value;
                if (cols.Contains("ProductNumber")) ret.ProductNumber = x.Element("ProductNumber").Value;
                if (cols.Contains("ListPrice")) ret.ListPrice = x.Element("ListPrice").Value;
    
                return ret;
            }
        }

    Miután megvan a criteria és a cols változó, ami kell a lekéréshez, meg tudjuk hívni a megfelelő WS-t.
    (itt újra megyjegyzem hogy a Where és a Select hamarabb fog lefutni, mint GetEnumerator)

    Ha megvannak a SZÜKSÉGES adatok (nem az összes!!), akkor már csak Productot kell belőle varázsolni.
    (direkt XML-el dolgozom, hogy minél “szabványosabb” legyen, lehetne direkt objektumokat ráncigálni…)

    3. Testre szabás…

    Az igények szerint :)

     

    Összefoglalva: a lényeg hogy a kliens oldali felhasználás egyszerű, és mindig csak a megfelelő adatokon dolgozik, egy hidat képeztünk a rétegek között a LINQ kiterjesztésével.

    Persze ez még mindig csak IEnumberable, és ne IQueryable, ami között az a nagy különbség, hogy ha az készítünk egy query-t majd azt felhasználjuk egy másikban, akkor késleltetett végrehajtás ide vagy oda, az első query le fog futni önmagában… függetlenül a másodiktól.
    Erre megoldás az IQueryable irányába való továbbfejlesztés, ami a következő blogbejegyzés témája lesz…

    Alapötlet : LINQ 2 Amazon

    Forrás : http://devportal.hu/groups/linq/media/p/5855.aspx

    demo adatbázis : Microsoft AdventureWorks

    http://www.codeplex.com/SqlServerSamples
    http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=4004

    December 22

    C# && VB.Net coding standards

    Sokszor van arra szükség, akár ha egyedül dolgozunk, akár 10-20-n egy csapatban, hogy kialakítsuk a "saját" elnevezési konvenciónkat, kódolási szabályzatunkat.

    Sokszor elég egy másik által készítettből kiindulni...
    (ez nem plágium, pláne ha a készítője osztja meg a nagyvilággal)

    • http://www.notsotrivial.net/blog/post/2008/12/Holiday-Goodie-Bag-Free-C-and-VB-Coding-Standards-Reference-Documents.aspx
    • http://www.tiobe.com/content/paperinfo/gemrcsharpcs.pdf
    • http://msdn.microsoft.com/en-us/library/czefa0ke.aspx
    • http://blogs.msdn.com/brada/articles/361363.aspx
    • http://www.codeproject.com/KB/cs/c__coding_standards.asp
    --
    KRis
    December 19

    LINQ 2 SQL null kérdések…

     

    Egy fontos dologra bukkantam, ami nem biztos hogy elsőre egzakt, legalábbis nekem nem volt az…

    LINQ 2 SQL használat közben adatbázis oldalon minden lehet null.
    Erre akár szűrhetünk is. hogy állunk hozzá?!?

    Where(p => p.NullableField == null)

    mire fog ez lefordulni?!?!

    …where NullableField is null…

    Helyes! ezt vártuk!
    Node. Van nekünk int? tipusunk, akkor miért ne használnánk?

    int? filter=null;
    …Where(p => p.NullableField == filter)

    mire fog ez lefordulni?!?!

    …where NullableField = @p0

    Helyes!?!? A francokat!
    ( a null semmivel sem egyenlő… ezért használjuk az is null ellenőrzést!)

    Mi a következtetés?!? Hát ezt nem szabad használni!
    Helyette:

    int? filter=null;
    Where(p=>object.Equals(p.NullableField, filter))

    Ez pedig a megfelelő SQL-t fogja minden esetben tartalmazni. (Vagy is null, vagy = @p)

    Aki nem hiszi járjon utána!

    December 05

    Paralell C#

     

    Kezdtem mostanában már XAML-el álmodni... gyakorlatilag mostanában csak SL2-vel, WPF-el és WF-val dolgoztam...

    Úgy gondoltam kicsit visszakanyarodok az alapokhoz : C# és a paralellizmus...

    Miről is van szó?

    Ma már gyakorlatilag történelem az egy processzort/magot tartalmazó gépek, tehát adott a párhuzamosítás lehetősége architekturális szinten.
    És hol tart hozzá a fejlesztő környezet? Runtime? Gyakorlatilag sehol. Pontosabban ugyan ott ahol 10 éve. Van Thread/ThreadPool/Process osztály... no meg BackgroundWorker komponens, de ez végső soron ugyan az...

    Vagyis ha akarunk többszálú alkalmazást, akkor írjuk meg mi kézzel! mindent!
    De mi nem akarjuk! Nem akarjuk ezeket explicite kézzel írogatni. Nem akarunk adatbázis-, adat-elérést irogatni (fejlődés : DataAdapter/DataSet/LINQ2SQL/EF stb...). Nem akarunk "UX-hez" kapcsolódó dolgokat kézzel kódolni (fejlődés : XAML,WPF,SL2, BLEND,stb...) és így tovább...
    Nem akarunk mi kézzel többszálú alkalmazást írogatni. Viszont ki akarjuk használni a több processzor adta lehetőségeket. Implicit. De semmikép nem Explicit.

    Tehát akkor hogyan nem?

    Itt egy példa : brute force hash gyártás :)))

    (természetesen ez csak egy teszt "alogritmus"/állatorvosiLÓ, biztos van jobb,gyorsabb...  lehet hibás is... ;-)  )

    public static void Feltor(object pars)
    {
    object[] ot = pars as object[];
    //mettol
    int tol = (int)ot[0];
    //meddig kell a vezető karaktert keresni...
    int ig = (int)ot[1];
    //milyen hosszu a keresendő pass...
    int hossz = (int)ot[2];


    Console.WriteLine("kereses : Tid={0} - szalon {1}-tol {2}-ig ",System.Threading.Thread.CurrentThread.ManagedThreadId,tol,ig );
    string generalt = "";
    StringBuilder sb ;
    int[] allapot = new int[hossz];
    bool vanmeg = true;

    MD5 md = MD5.Create();
    byte[] jelszo_teszt;
    byte[] hash_teszt;

    for (int i = tol; i <= ig; i++)
    {
    //kovetkezo vezeto karakter, az adott szalhoz
    allapot[0] = i;
    vanmeg = true;
    for (int z = 1; z < hossz; z++)
    {
    allapot[z] = 0;
    }
    //van meg a vezető karakter utan...
    while (vanmeg)
    {
    if (feltores_sikeres)
    {
    //ha veletlen megtalaltuk a masik szalon, akkor nem keresunk tovabb...
    return;
    }
    sb = new StringBuilder();
    for (int j = 0; j < hossz; j++)
    {
    //maradek karakterek generalasa az allapothoz....
    sb.Append(karakterek.Substring(allapot[j], 1));
    }


    jelszo_teszt = Encoding.Default.GetBytes(sb.ToString());
    hash_teszt = md.ComputeHash(jelszo_teszt);

    //szamlalas
    Interlocked.Increment(ref ciklus);

    if (Program.CompareByteArray(hash_teszt,hash_jelszo))
    {
    //megvan
    feltort_password = sb.ToString();
    feltores_sikeres = true;
    return;
    }

    bool atvitel = true;

    int k = hossz - 1;
    //léptet
    while (atvitel)
    {
    if (allapot[k] == karakterek.Length - 1)
    {
    atvitel = true;
    allapot[k] = 0;
    }
    else
    {
    allapot[k] = allapot[k] + 1;
    atvitel = false;
    }
    k--;
    if (k == 0 || atvitel == false)
    {
    break;
    }
    }
    if (atvitel)
    {
    //nincs több az adott vezető karakterhez...
    vanmeg = false;
    }
    }
    }
    //pech... nincs meg...
    return;
    }

    Ezt lehet indítani 1-N szálon:

    public static void Keres(int hossz,int szalak_szama)
    {

    Console.WriteLine("Most keresek {1} szálon {0} hosszal!", hossz, szalak_szama);
    jelszo_hossz = hossz;
    ciklus = 0;

    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

    sw.Start();

    Thread[] thr = new Thread[szalak_szama];
    int akt = 0;
    for (int i = 0; i < szalak_szama; i++)
    {
    object[] ot = new object[3];
    thr[i] = new Thread(new ParameterizedThreadStart(Feltor));
    ot[0 ]= akt;
    if (i <= szalak_szama -1)
    {
    ot[1]= akt+ karakterek.Length/szalak_szama-1;
    }
    else
    {
    ot[1 ]= karakterek.Length-1;
    }
    ot[2 ]= jelszo_hossz;

    akt += karakterek.Length / szalak_szama;
    thr[i].Start(ot);
    }
    for (int i = 0; i < szalak_szama; i++)
    {
    thr[i].Join();
    }

    sw.Stop();

    Console.WriteLine("");
    Console.WriteLine("eredmény");
    Console.WriteLine("{0} ciklus : ", ciklus);
    Console.WriteLine("{0} hossz = {1} ms",jelszo_hossz,sw.ElapsedMilliseconds);
    Console.WriteLine("Sebesseg {0:f0} db /ms", ciklus / sw.ElapsedMilliseconds);



    }

    Teszt után egyértelműen kiderül hogy a 2 szál gyorsabb mint az 1 :)

    image

    A 4 meg több mint a 2 :)

    4

    Az első teszt egy CORE2 DUO 7300-al ment.
    A második egy Q6600 proci felett lévő WS2008-Hyper-V-ben lakó Vista-val történt :)

    Nos, ez volt ugye az explicit, hagyományos szálkezelés.
    Lássuk mit lehet tenni a következőkkel :

    Alakítsuk át a kódót a következő módon:

    1. Adjunk referenciát a System.Threading.dll -re (a Paralell CTP-ben találhatóra)
    2. Írjuk át a Feltor meghívását, úgy mintha 1 proc. lenne:

      Feltor(0, karakterek.Length - 1, hossz);

    3. Írjuk át a Feltor eljárást:
      System.Threading.Parallel.For(tol, ig+1, i =>
      {
      StringBuilder sb;
      int[] allapot = new int[hossz];
      bool vanmeg = true;

      MD5 md = MD5.Create();
      byte[] jelszo_teszt;
      byte[] hash_teszt;
      ...

      });

    A lényeg hogy bár nem teljesen implicite kezelünk több szálat, mert le kell cserélni a for ciklust a Paralell.For-ra, és mint lambda kifejezés/anonymous-delegate kell átadnunk a ciklus törzsét.

    DE sehol nem kell leírni a Thread szót, és még több processzoron kerül végrehajtásra a ciklus:

    image

    image

    ------------------------

    Mi történik a háttérben?

    "valamilyen algoritmus" alapján a mögöttes kód(Paralell.For implementációja) eldönti hogy mennyi szálon kellene futtatni (mi lenne az optimális) a ciklust, és hasonlóan ahogy mi felszabdaltuk a ciklust X részre, úgy tesz a Paralell.For is...

    Persze fontos hogy a ciklusban végrehajtott action ne akarjon olyan erőforráshoz hozzáférni, amelyhez egy esetleges másik szálon vele párhuzamosan futó ciklustörzs is hozzá akar férni.
    Ez lehet egy tényleges másik erőforrás, de lehet pl. olyan eset amikor az n. lépésben az n-1. lépés eredményét  fel akarjuk használni. ilyen esetben a párhuzamosítás nem lehetséges. Se hagyományos módon, se a Paralell névtér segítségével se... A párhuzamosítás nagymértékben függ a feladattól, algoritmustól!

    -----------------------

    A másik része a Paralell Extension-nek a Paralell LINQ.
    A LINQ kifejezések legtöbbje párhuzamosítható... kivéve persze ahol az algoritmus ezt nem vagy csak nehezen teszi lehetővé... tipikus példa : rendezés...

    Nézzünk rá egy példát:

    public static bool IsPrime(int i)
    {
    ...
    }
    ....
    int l = 500000;
    tomb = new int[l];
    for (int i = 0; i < l; i++)
    {
    tomb[i] = i;
    }

    Stopwatch sw = new Stopwatch();
    sw.Start();
    int c = tomb.AsParallel().Where(i => IsPrime(i)).Count();

    sw.Stop();

    Console.WriteLine("megvan paralell : {0} {1} ms alatt",c,sw.ElapsedMilliseconds);

    Console.WriteLine();

    sw = new Stopwatch();
    sw.Start();
    c = tomb.Where(i => IsPrime(i)).Count();

    sw.Stop();

    Console.WriteLine("megvan siman : {0} {1} ms alatt", c, sw.ElapsedMilliseconds);
    Console.ReadLine();
    Eredmény:

    image

    Ha nem is dupljája de látható hogy egy LINQ lekérdezésen is lehet gyorsítani.
    Sőt... kell is a mai 2-4-8 magos PC-ken :)

    Rengeteg példa, és maga CTP is letölthető innen:

    http://msdn.microsoft.com/en-us/concurrency/default.aspx

    Forráskód : http://devportal.hu/groups/fejlesztk/media/p/4256.aspx

    Annyi screencast-ot ígértem már mostanában (amelyek hamarosan jönnek), hogy nem merem megígérni, hogy ebből is lesz egy... talán ha CTP-ből valami magasabb fázisba lép a projekt...

    --
    KRis

    September 12

    Rolling Menu

     

    menu

    Találtam egy érdekes/designos menüt, amit egy kicsit átalakítottam, hogy bármilyen UI elemet tudjon fogadni, és azt egyszerűen meg lehessen adni, és design alatt látni hogy mit gyártunk...

    Átalakítás:

    <UserControl x:Class="SilverKatalogus.MenuImage"
    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="90" d:DesignHeight="90"
        >
        <UserControl.Resources>
            <Storyboard x:Name="Storyboard1">
                <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="content" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
                    <SplineDoubleKeyFrame KeyTime="00:00:00.2000000" x:Name="MyKeyFrame" Value="-1">
                        <SplineDoubleKeyFrame.KeySpline>
                            <KeySpline ControlPoint1="0,0" ControlPoint2="0.504000008106232,1"/>
                        </SplineDoubleKeyFrame.KeySpline>
                    </SplineDoubleKeyFrame>
                </DoubleAnimationUsingKeyFrames>
            </Storyboard>
        </UserControl.Resources>
        <!-- don't remove the background, required for correct LeaveEvent-->
        <Grid x:Name="LayoutRoot" 
                MouseEnter="Image_MouseEnter" 
                MouseLeave="image_MouseLeave"
                Background="Transparent"
                Cursor="Hand"
                RenderTransformOrigin="0.5,0.5">
            <ContentPresenter RenderTransformOrigin="0.5,0.5" x:Name="content">
                <ContentPresenter.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                    </TransformGroup>
                </ContentPresenter.RenderTransform>
            </ContentPresenter>
            <!--<Image 
                   RenderTransformOrigin="0.5,0.5" x:Name="image">
                <Image.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform />
                    </TransformGroup>
                </Image.RenderTransform>
            </Image>-->
            <Grid.RenderTransform>
                <TransformGroup>
                    <RotateTransform x:Name="MyAngle"/>
                </TransformGroup>
            </Grid.RenderTransform>
        </Grid>
    </UserControl>
    

     

    Látható, hogy egy kép helyett ContentPresenterben jelenítem meg a dolgokat...

    Ehhez 2 DependencyProperty-re van szükség, és ezt a UIElement-et jelenítem meg a 2 kép helyett (normal, rolled).
    Így gyakorlatilag bármit meg tudunk jeleníteni!

    (a kódban a dep propertyk a lényegek, csak a teljesség kedvéért tettem ide az egész osztályt...)

    public partial class MenuImage : UserControl
       {
           public MenuImage()
           {
               InitializeComponent();
    
               Storyboard1.Completed += new EventHandler(Storyboard1_Completed);
    
           }
    
           private enum MyStates { Normal, Started1, Started2, Reverse1, Reverse2 };
           private MyStates MyState = MyStates.Normal;
    
    
           public int Duration
           {
               get { return (int)GetValue(DurationProperty); }
               set { SetValue(DurationProperty, value);MyKeyFrame.KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, value));  }
           }
    
           // Using a DependencyProperty as the backing store for Duration.  This enables animation, styling, binding, etc...
           public static readonly DependencyProperty DurationProperty =
               DependencyProperty.Register("Duration", typeof(int), typeof(MenuImage), null );
    
    
    
           public int Angle
           {
               get { return (int)GetValue(AngleProperty); }
               set { SetValue(AngleProperty, value);      MyAngle.Angle = value;}
           }
    
           // Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
           public static readonly DependencyProperty AngleProperty =
               DependencyProperty.Register("Angle", typeof(int), typeof(MenuImage), null);
    
    
    
           public UIElement UINormal
           {
               get { return (UIElement)GetValue(UINormalProperty); }
               set { SetValue(UINormalProperty, value); content.Content = value; }
           }
    
           // Using a DependencyProperty as the backing store for UINormal.  This enables animation, styling, binding, etc...
           public static readonly DependencyProperty UINormalProperty =
               DependencyProperty.Register("UINormal", typeof(UIElement), typeof(MenuImage), null);
    
    
           public UIElement UIRoll
           {
               get { return (UIElement)GetValue(UIRollProperty); }
               set { SetValue(UIRollProperty, value); }
           }
    
           // Using a DependencyProperty as the backing store for UIRoll.  This enables animation, styling, binding, etc...
           public static readonly DependencyProperty UIRollProperty =
               DependencyProperty.Register("UIRoll", typeof(UIElement), typeof(MenuImage), null);
    
    
    
           private void Reverse2() {
               MyState = MyStates.Reverse2;
               //this.image.Source = _normalImage;
               content.Content = UINormal;
    
               MyKeyFrame.Value = 1;
               Storyboard1.Begin();
           }
    
           private void Reverse1() {
               MyState = MyStates.Reverse1;
               MyKeyFrame.Value = 0;
               Storyboard1.Begin();
           }
    
           private void Start1() {
               MyState = MyStates.Started1;
               MyKeyFrame.Value = 0;
               Storyboard1.Begin();
           }
    
           private void Start2() {
               MyState = MyStates.Started2;
               //this.image.Source = _rollImage;
               content.Content = UIRoll;
               MyKeyFrame.Value = 1;
               Storyboard1.Begin();
           }
    
           private void Image_MouseEnter(object sender, MouseEventArgs e) {
               Canvas.SetZIndex(this, Canvas.GetZIndex(this) + 4);
               switch (MyState) {
                   case MyStates.Normal:
                   case MyStates.Reverse2:
                       Start1();
                       break;
                   default:
                       Start2();
                       break;
               }
           }
    
           private void image_MouseLeave(object sender, MouseEventArgs e) {
               Canvas.SetZIndex(this, Canvas.GetZIndex(this) - 4);
               switch (MyState) {
                   case MyStates.Started2:
                       Reverse1();
                       break;
                   case MyStates.Started1:
                       Reverse2();
                       break;
               }
           }
    
           void Storyboard1_Completed(object sender, EventArgs e) {
               switch (MyState) {
                   case MyStates.Started1:
                       Start2();
                       break;
                   case MyStates.Reverse1:
                       Reverse2();
                       break;
                   case MyStates.Reverse2:
                       MyState = MyStates.Normal;
                       break;
               }
           }
       }

    Használat:

    <local:MenuImage Angle="10" Width="120" Height="120" Margin="10">
                 <local:MenuImage.UINormal>
                     <Image Source="Images/users.png"></Image>
                 </local:MenuImage.UINormal>
                 <local:MenuImage.UIRoll>
                     <Border BorderBrush="Gray" BorderThickness="2" CornerRadius="3" >
                         <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10">Oktatók</TextBlock>
                     </Border>
                 </local:MenuImage.UIRoll>
             </local:MenuImage>

    És az eredmény :


    September 11

    ScreenCast

     

    Elkészült az első screencastom, első első és első Silverlight 2.0.

    Hogy is szokták mondani?!?
    Kicsit ...., kicsit...., de legalább az enyém :)

    Remélem hamarosan jön a többi is, egy értelmes tematika szerint...

    http://www.devportal.hu/groups/silverlight/blog/archive/2008/09/10/els-silverlight2-screencast.aspx

    WebMappa : http://files.devportal.hu/Demo/

    --
    KRis

    September 10

    XAML && Binding && Converter && IMultiValueConverter

     

    Igen hasznos dolog WPF/SL-os XAML újdonság a Binding. Ügyesen használva minimális "erőfeszítéssel", értsd kódolással-hekkeléssel, egész komplex működést is el lehet érni.

    Milyen problémákba ütközhetünk?

    • Source megadása/megtalálása (nem simán DataContext)
      (Property az egyszerű, mivel csak ki kell tölteni a Path-t)
    • Konverzió
    • Konverzió paraméterezése-> fix paraméter ( valamilyen paraméterre van szükség)
    • Konverzió paraméterezése-> több paraméter is szükséges, több helyről...

    Oldjuk fel a problémákat!!

    Source megadása

    • RelativeSource használata Binding-ban:
      {Binding RelativeSource={RelativeSource Self}}
    • Template esetén : {Binding RelativeSource={RelativeSource TemplatedParent}}
    • Ős megkeresése : {Binding RelativeSource={RelativeSource FindAncestor,
      AncestorLevel=n, AncestorType={x:Type desiredType}}}
    • Adott elem megkeresése : {Binding ElementName=elemName,.... }

    Ezzel gyakorlatilag mindent le lehet fedni, mindenkit meg lehet találni akinek a Property-jét fel akarjuk használni.

    Konverzió

    Erre a WPF-ben és SL-ban a konverterek állnak rendelkezésre:

    Gyári konverterek, pl:

    Ez sok esetben kevés, sőt :) általában kevés. De sebaj, gyártani tudunk sajátot:

    public class MyConverter : IValueConverter
       {
           #region IValueConverter Members
    
           public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
           {
               throw new NotImplementedException();
           }
    
           public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
           {
               throw new NotImplementedException();
           }
    
           #endregion
       }

    Mint látható kapunk egy értéket amit konvertálni kell, kapunk egy paramétert amit fel tudunk használni a konverzióhoz ( megkapjuk a cél type-t, és a culture-t).
    Implementáljuk a logikát és már is fel tudjuk használni a binding-ban:

    {Binding Converter="{StaticResource HeightConverter}"...}

    Paramétert a ConverterParameter="123"-al tudunk megadni a binding-ban.

    De.... mi van ha több paramétert akarok megadni, és bindolni szeretnék?!?

    Hát akkor nincs más hátra, mint az IMultiValueConverter:
    (a példából amit csatolok)

     

    public class HeightConverter : IMultiValueConverter
       {
    
           #region IMultiValueConverter Members
    
           public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
           {
               double value = (double)values[0];
               double height = (double)values[1];
               double min= (double)values[2];
               double max = (double)values[3];
    
               return (height-min) * (double)value / (max-min)*0.8;
           }
    
           public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
           {
               throw new NotImplementedException();
           }
    
           #endregion
       }

    Itt már nem csak egy értéket hanem bármennyit kaphatunk.... és a lényeg bárhonnan:

    <Rectangle x:Name="rectFill" Fill="DarkRed" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
             <Rectangle.Height>
                 <MultiBinding Converter="{StaticResource HeightConverter}"  >
                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualHeight"/>
                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
                     <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
                 </MultiBinding>                                 
             </Rectangle.Height>
         </Rectangle>

    Mint látható minden egyes paraméternek külön meg lehet adni a forrást (jelen példában ugyanaz...), így akár több helyről is össze tudjuk szedni szükséges értékeket...

    Jelen példában készítettem a progressbar-t, ami stílusosan egy sörösüveg :), ami megtellik...
    ehhez szükség volt a progressbar value property-jére, és az aktuális magasságra...

    image

    Source : http://beta.devportal.hu/groups/wpf/media/p/946.aspx

    September 03

    Silverlight MDI Surface

     

    WPF-ben tanulási időszakban készítettem egy Surface-t amire mindenféle elemeket lehetett dobálgatni, ott átméretezni, rendezgetni stb.

    Ezt WPF-ben könnyen meg lehet tenni egy Canvas és a Thumb segítségével.

     

    De miért ne tennénk ezt meg Silverlight2-ben? És hívjuk az elemet Window-nak, legyen Title-je, és máris van egy Winforms MDI szerű rendszerünk!

    Lássuk!

    1. MDI Window

    Mi sem egyszerűbb! Mindösszesen egy Canvas:

    <UserControl x:Class="SilverWindowEngine.Page"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Width="800" Height="600">
        <Grid x:Name="LayoutRoot" Background="White">
            <Canvas x:Name="canvasMDI">
            </Canvas>
        </Grid>
    </UserControl>

    Természetesen, ha szeretnénk olyan funkciókat, hogy rendezés ( Cascade,Tile,stb), vagy Window listát, akkor azt itt implementálni kell.
    Ebben a demo-ban ezt most kihagyom.

    2. Szükségünk van egy Window control-ra, ami tud működni egy MDI felületen, azaz egy Canvas-on.

    Készítsünk egy UserControl-t : SilverWindow
    Mit kell tudnia?

    • Legyen címe
    • Legyen X, azaz bezár gomb
    • Legyen mozgatható
    • Legyen méretezhető
    • Ha a fejlécre (egyszerűség kedvéért) kattintok akkor jöjjön "előre"

    Ehhez alakítsuk ki a felületünket:
    Legyen a gridnek 2 sora 2 oszlopa

    <Grid.RowDefinitions>
               <
    RowDefinitionHeight="20"></RowDefinition>
               <
    RowDefinition></RowDefinition>
           </
    Grid.RowDefinitions>
           <
    Grid.ColumnDefinitions>
               <
    ColumnDefinition></ColumnDefinition>
               <
    ColumnDefinitionWidth="30"></ColumnDefinition>
           </
    Grid.ColumnDefinitions>       

    Cím:

    <StackPanel Grid.Row="0" Grid.Column="0"  HorizontalAlignment="Center">
               <TextBlock>Title</TextBlock>
           </StackPanel>     

    Mozgatás:

    <Rectanglex:Name="rectDrag"MouseLeftButtonDown="rectDrag_MouseLeftButtonDown"
    MouseMove="rectDrag_MouseMove" MouseLeftButtonUp="rectDrag_MouseLeftButtonUp"
    Fill="Transparent" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="0"  >
    </
    Rectangle>

    Bezárás:

    <Button x:Name="btnClose" Content="X" Grid.Column="1" Grid.Row="0" 
    Click="btnClose_Click"></Button>
    Tartalom:
    <Grid x:Name="grdContentPresenter" Grid.Row="1" Grid.ColumnSpan="2">
            </Grid>        

    Ebbe a gridbe fogjuk betenni az ablak tartalmát!

    Méretezés:

    <Rectangle x:Name="rectResizeWidth" 
    MouseLeftButtonDown="rectResizeWidth_MouseLeftButtonDown"
    MouseLeftButtonUp="rectResizeWidth_MouseLeftButtonUp"
    MouseMove="rectResizeWidth_MouseMove"
    Cursor="SizeWE" Grid.Column="1" Grid.RowSpan="2" Fill="Yellow"
    Width="7" Margin=" 0 0 -2 0" VerticalAlignment="Stretch"
    HorizontalAlignment="Right"></Rectangle> <Rectangle x:Name="rectResizeHeight"
    MouseLeftButtonDown="rectResizeHeight_MouseLeftButtonDown"
    MouseLeftButtonUp="rectResizeHeight_MouseLeftButtonUp"
    MouseMove="rectResizeHeight_MouseMove" Cursor="SizeNS"
    Grid.ColumnSpan="2" Grid.Row="1" Fill="Yellow" Height="7"
    Margin=" 0 0 0 -2" VerticalAlignment="Bottom" HorizontalAlignment="Stretch">
    </
    Rectangle>

    A megfelelő paraméterek beállításával a két szélén az ablaknak érzékeny lesz a 2 Rectangle, ha megfelelően írjuk meg az eseményvezérlőket, akkor pont azt fogják csinálni amit szeretnénk!
    Jelen esetben sárga ez a két terület, ezt át lehet állítani Transparent-re.
    (WPF-ben van egy Thumb osztály, ami megtalálható Silverlight-ban is, de sajnos sealed, így itt nem használható Drag-re. de sebaj néhány sor kód...)

    Díszítés:

    <Border BorderThickness="2" Grid.ColumnSpan="2" Grid.RowSpan="2" 
    BorderBrush="Black" CornerRadius="2"></Border>

    A sorrend azért fontos, hogy megfelelő legyen a fedése az egyes részeknek!!!

    Nézzzük meg az eseményvezérlőket:

    Mozgatás:

    #region Move
           public bool MouseDown { get; set; }
           public Point mouseDownPoint { get; set; }
           public Point mouseDownWindowPos { get; set; }
           private void rectDrag_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
           {
    
               Canvas c = this.Parent as Canvas;
               (this.Parent as Canvas).Children.Remove(this);
               c.Children.Add(this);
    
               double left = Canvas.GetLeft(this);
               double top = Canvas.GetTop(this);
    
               mouseDownPoint = e.GetPosition(this.Parent as Canvas);
    
               mouseDownWindowPos = new Point(left, top);
               MouseDown = true;
               rectDrag.CaptureMouse();
           }
    
           private void rectDrag_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
           {
               MouseDown = false;
               rectDrag.ReleaseMouseCapture();            
           }
    
           private void rectDrag_MouseMove(object sender, MouseEventArgs e)
           {
               if (!MouseDown)
               {
                   return;
               }
               double left = mouseDownWindowPos.X;
               double top = mouseDownWindowPos.Y;
    
               Point p = e.GetPosition(this.Parent as Canvas);
    
    
               double deltaHorizontal =  p.X - mouseDownPoint.X;
               double deltaVertical = p.Y -mouseDownPoint.Y;
    
    
               Canvas.SetLeft(this, left + deltaHorizontal);
               Canvas.SetTop(this, top + deltaVertical);
           }
    
           #endregion

    Vagyis egér lenyomásra megjegyzem a poziciót a Parent-hez képest (amiről tudom hogy Canvas), majd ezt felhasználom az egér mozgása eseményben. Ahol szépen beállítom a Canvas Left és Top property-jét, vagyis mozogni fog az ablak.

    Bezárás:

    private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            (this.Parent as Canvas).Children.Remove(this);
        }

    Egyszerűen ki kell venni a Parent Canvas gyerekei közül...
    Itt lenne lehetőség olyan események kiváltására mint Closing... Closed... stb.

    Méretezés:

    #region SizeWidth
    
       public bool MouseDownSizeWidth { get; set; }
       public Point mouseDownPointSizeWidth { get; set; }
       public double mouseDownWidth { get; set; }
    
       private void rectResizeWidth_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
    
           mouseDownPointSizeWidth = e.GetPosition(this.Parent as Canvas);
    
           MouseDownSizeWidth = true;
           mouseDownWidth = this.Width;
           rectResizeWidth.CaptureMouse();
    
       }
    
       private void rectResizeWidth_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
       {
           MouseDownSizeWidth = false;
           rectResizeWidth.ReleaseMouseCapture();     
       }
    
       private void rectResizeWidth_MouseMove(object sender, MouseEventArgs e)
       {
           if (!MouseDownSizeWidth)
           {
               return;
           }
           Point p = e.GetPosition(this.Parent as Canvas);
    
    
           double deltaHorizontal = p.X - mouseDownPointSizeWidth.X;
    
           this.Width = mouseDownWidth +deltaHorizontal;
       }
    
       #endregion
    
       #region SizeHeight
    
       public bool MouseDownSizeHeight { get; set; }
       public Point mouseDownPointSizeHeight { get; set; }
       public double mouseDownHeight { get; set; }
    
       private void rectResizeHeight_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           mouseDownPointSizeHeight = e.GetPosition(this.Parent as Canvas);
    
           MouseDownSizeHeight = true;
           mouseDownHeight = this.Height;
           rectResizeHeight.CaptureMouse();
       }
    
       private void rectResizeHeight_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
       {
           MouseDownSizeHeight = false;
           rectResizeHeight.ReleaseMouseCapture();     
       }
    
       private void rectResizeHeight_MouseMove(object sender, MouseEventArgs e)
       {
           if (!MouseDownSizeHeight)
           {
               return;
           }
           Point p = e.GetPosition(this.Parent as Canvas);
    
    
           double deltaVertical = p.Y - mouseDownPointSizeHeight.Y;
    
           this.Height = mouseDownHeight + deltaVertical;
       }
    
       #endregion

    Hasonlóan a mozgatáshoz, itt is figyeljük az egér mozgását.Csak most nem a Top és a Left propertyt állítjuk, hanem a Height és a Width property-ket!

    Már csak az maradt, hogy hozunk létre egy gyerekablakot?!?

    SilverWindow w1 = new SilverWindow(new DemoChildWindow());
               w1.Height = 200;
               w1.Width = 200;
    
               canvasMDI.Children.Add(w1);

    Erre akár készíthetünk egy általános CreateWindow statikus metódust is.
    (DemoChildWindow egy demo user control egy kevés tartalommal...)

    És voálá...

    image 

    Mindenki saját ízlése és igenyei szerint fejlessze tovább!!!

    • pl. CreateWindow-ban Title megadása
    • különböző propertyk mappelése/bindolása : Background, Margin, stb...
    • WindowList
    • rendezések : Tile,Horizontal,Vertical...
    • MinSize, MaxSize, Resizable...
    • Modal
    • stb...

    Demo forráskód:

    http://beta.devportal.hu/groups/silverlight/media/p/744.aspx