Silverlight projeleriniz büyüdükçe projenin bazı bölümlerini sonradan istemci
tarafına aktarmayı daha uygun bir seçenek olarak görebilirsiniz. Bu gibi
durumlarda acaba ayrı bir XAP dosyası yapsak da onu haricen istemciye yüklesek
diye düşünürseniz maalesef söz konusu XAP dosyasını kendi kodlarınız ile ZIP
şeklinde açmanız ve içerisindeki Manifest.xml'i yine kendi kodunuz ile okuyup
tek tek DLL'leri yüklemeniz gerekecektir. Bu konuda detaylı bir makaleye
buradan ulaşabilirsiniz.
Bu zorluklarla uğraşmadan hızlı bir şekilde belki de sadece bir UserControl'ü
haricen sonradan yüklemek istiyorsanız aslında çok daha pratik ve hızlı bir
yöntem de kullanılabilir. Bu yönteme sadece UserControl'ler değil harici olarak
yazılan sınıflar da dahil. Gelin daha fazla teorik konuşma yerine bir örnek
üzerinden ilerleyelim.
Haricen yüklenecek içeriği hazırlayalım....
İlk olarak ana Silverlight uygulamamıza sonradan yüklenecek olan içeriği
hazırlayalım. Bunun için Visual Studio içerisinde "File / New Project" dedikten
sonra "Silverlight" seçeneği altındaki "Silverlight Class Library"
proje tipini seçiyoruz. Bu proje tipinde doğrudan tüm proje içeriği bir DLL
içerisine konacak fakat bu DLL ayrıca bir XAP dosyası içerisinde
sıkıştırılmayacak. Böylece biz de Silverlight ile istemci tarafında bir XAP
dosyası açmak veya Manifest ile uğraşmak zorunda kalmayacağız.
Normal şartlarda Silverlight Class Library projesi yarattığınızda proje
içerisinde sadece bir CS veya VB dosyası görebilirsiniz. Oysa bu projelere de
isterseniz XAML dosyaları ile beraber UserControl'ler eklenebilir. Projenize sağ
tuş tıklayarak Solution Explorer içerisinden "Add New Item" demeniz ve gelen
seçeneklerden de "Silverlight User Control"ü seçmeniz yeterli olacaktır. Artık
isterseniz bu projeyi Blend içerisinde de açıp normal bir Silverlight
projesindeki gibi animasyonlar vs kullanabilirsiniz.
Örnek olarak projemize bir resim dosyası ekleyerek UserControl'ümüz
içerisinde de onu gösterebilir. Unutmayın ki resim dosyasını projeye "Add
Existing Item" diyerek eklerseniz artık bu resim de DLL'inizin içerisine dahil
edilecektir.
[XAML]
<UserControl x:Class="SilverlightClassLibrary1.SilverlightControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Image Margin="71,47,97,122" Source="Forest.jpg"/>
</Grid>
</UserControl>
Yukarıdaki şekli ile UserControl'ümüz hazır olduktan sonra projemizi Build
ederek DLL'imizi yaratmış oluyoruz. Bu DLL'i bir sonraki adımda yaratacağımız
Silverlight projesinin XAP dosyası ile aynı konuma koyabilirsiniz. Silverlight
projemiz içerisinden bu DLL'i istemciye asenkron olarak download ederek sahneye
DLL içerisindeki UserControl'ü yükleyeceğiz.
Gelelim Silverlight projemize...
Tertemiz bir Silverlight projesi yarattıktan sonra proje ile beraber gelen
ASP.NET sitesi içerisinde ClientBin klasörüne bir önceki adımda yarattığımız DLL
dosyasını kopyalayalım. Böylece projeyi Build ettiğimiz aynı konuma otomatik
olarak kopyalanacak olan XAP dosyası üzerinden DLL'e de rahatlıkla ulaşabiliriz.
Yeni Silverlight projemizin ana Page.XAML dosyasına bir Button ve bir de
Canvas ekleyelim. Böylece düğmeye basıldığında harici DLL'i yükleyecek ve DLL
içerisindeki UserControl'ümüzü de Canvas içerisine yerleştireceğiz.
[XAML]
<UserControl x:Class="SilverlightApplication5.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Button x:Name="btnTikla" Height="19" HorizontalAlignment="Right" Margin="0,0,18,17" VerticalAlignment="Bottom" Width="89" Content="Button"/>
<Canvas x:Name="Icerik" Margin="13,13,18,54"/>
</Grid>
</UserControl>
Düğmeye tıklandığı anda hemen bir WebClient yaratarak download işlemimizi
başlatalım.
[VB]
Private BirAssembly As System.Reflection.Assembly
Public Sub New()
InitializeComponent()
AddHandler Me.btnTikla.Click, AddressOf btnTikla_Click
End Sub
Private Sub btnTikla_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim Yukleyici As New WebClient()
AddHandler Yukleyici.OpenReadCompleted, AddressOf Yukleyici_OpenReadCompleted
Dim Yol As String = System.Windows.Application.Current.Host.Source.AbsoluteUri.Replace("SilverlightApplication5.xap", "SilverlightClassLibrary1.dll")
Yukleyici.OpenReadAsync(New Uri(Yol, UriKind.Absolute))
End Sub
[C#]
System.Reflection.Assembly BirAssembly;
public Page()
{
InitializeComponent();
this.btnTikla.Click += new RoutedEventHandler(btnTikla_Click);
}
void btnTikla_Click(object sender, RoutedEventArgs e)
{
WebClient Yukleyici = new WebClient();
Yukleyici.OpenReadCompleted += new OpenReadCompletedEventHandler(Yukleyici_OpenReadCompleted);
string Yol = System.Windows.Application.Current.Host.Source.AbsoluteUri.Replace("SilverlightApplication5.xap", "SilverlightClassLibrary1.dll");
Yukleyici.OpenReadAsync(new Uri(Yol, UriKind.Absolute));
}
Yukarıdaki kodu dikkatli incelemek gerekirse ilk adımda en üstteki Assembly
tipindeki BirAssembly adındaki değişkenimizi açıklamak gerekecek. Kodumuz
sunucudan bir DLL indirecek ve içindeki UserControl'ü sahneye koyacak. Aslında
DLL'i indirdikten sonra içerisinden UserControl1 sınıfından bir instance alarak
sahneye koyacağız. Eğer bu işlemi yaptıktan sonra başka instance'lara da
ihtiyacımız olursa tekrar DLL'i indirmemek için eldeki Assembly'yi bir değişken
olarak tutmak daha mantıklı olacaktır. O nedenle en üstteki BirAssembly
değişkenimiz şimdiden yerini almış durumda.
Button'umuzun Click koduna baktığımızda bir WebClient yarattığımızı ve
OpenReadCompleted event listener'ını da başka bir koda bağladığımızı
görebilirsiniz. Sunucudan bir dosya indireceği ve indirme işlemi bittiğinde de
başka işler yapacağız. O nedenle bu event'ları yakalayabiliyor olmak çok önemli.
İsteyenler WebClient'ın DownloadProgressChanged event'ını da
yakalayarak download durumu ile ilgili yüzde üzerinden ne kadarının
indirildiğine dair bilgileri de ekranda gösterebilirler.
Sunucudan indireceğimiz dosyanın tam yolunu verebilmek için şu anki XAP
dosyasının tam yolunu alıp sadece dosya adını değiştiriyoruz. Bizim örneğimizde
saten her şeyin yeri ve dosya adları belli olduğu için herhangi bir sorun
olmayacaktır.
Son olarak OpenReadAsync metoduna da indirilecek olan dosyanın yolunu verip
download işlemini başlatıyoruz. Peki ya bu işler bitince çalışacak olan
Yukleyici_OpenReadCompleted metodunda neler yapacağız?
[VB]
Private Sub Yukleyici_OpenReadCompleted(ByVal sender As Object, ByVal e As OpenReadCompletedEventArgs)
Dim GelenAssembly As New AssemblyPart()
BirAssembly = GelenAssembly.Load(e.Result)
Dim Kontrol As UserControl = DirectCast(BirAssembly.CreateInstance("SilverlightClassLibrary1.SilverlightControl1"), UserControl)
Me.Icerik.Children.Add(Kontrol)
End Sub
[C#]
AssemblyPart GelenAssembly = new AssemblyPart();
BirAssembly = GelenAssembly.Load(e.Result);
UserControl Kontrol = (UserControl)BirAssembly.CreateInstance("SilverlightClassLibrary1.SilverlightControl1");
this.Icerik.Children.Add(Kontrol);
Download işlemi bittiği anda bir AssemblyPart değişkeni
yaratarak onun da Load metodunu kullanıyoruz. Load
metoduna e.result ile aslında
Yukleyici_OpenReadCompleted event-listener'ına gelen argüman üzerindeki
datayı almış oluyoruz. Yani özünde sunucudan indirdiğimiz DLL'in
Stream'i e.result içerisinde saklanıyor ve biz de bu
AssemblyStream'i doğrudan bir AssemblyPart üzerinden
Load ederek Assembly tipindeki
BirAssembly değişkenimize yüklüyoruz. Hatırlarsanız zaten bu
değişkenimiz de global anlamda sürekli hafızada tuttuğumuz bir değişkendi. Bir
sonraki adımda bir UserControl değişkeni tanımlayarak bunu da Assembly'miz
içerisinde SilverlightControl1'e eşitlememiz gerekiyor.
Assembly üzerinden CreateInstance metodu bizden yaratılacak nesnenin
TypeName'ini istiyor. Silverlight Class Library projesinin içerisindeki
UserControlümüzün tipinin adını full path olarak veriyoruz. Bunu zaten
UserControl'ün XAML dosyasının en üstünden de bulabilirsiniz. Artık elimizdeki
Kontrol değişkeni yine elimizdeki BirAssembly'nin
içerisinden SilverlightControl1'in bir instance'ıdır. Herhangi bir UserControl
gibi bu da alıp sahnede istediğimiz yere yerleştirebiliriz.
Hepinize kolay gelsin.