
Bu makalemiz XNA’de Windows Kontrolleri ve WPF
uygulamalarını kullanmaya yönelik olacaktır.XNA’ye yeni başlayanlara bırakın
WPF’in XNA içinde kullanılmasını,Windows Kontrollerinin bile dahil edilemeyeceği
söylenir!
Bu büyük bir bilgi kirliliğidir.Bu makalemizde bunun mümkün olduğunu sizlere
kanıtlayacağım.Unutmayın! İmkansız diye
birşey yoktur.Gerekli Araştırma ve Geliştirme yapıldıktan sonra herşey
mümkündür.Lafı daha fazla uzatmadan
işlemlerimize başlıyoruz...
Bileşenler:
Kullanılacak Windows Kontrolleri
Button
TextBox
CheckBox
ElementHost
Kullanılacak Araçlar
XNA GS 3.1 veya Visual Studio 2008(SP1)
.NET Framework 3.5(SP1)
Örnek Kodlar
İşlemler:
XNA GS veya Visual Studio 2008 imizi açıp yeni bir XNA 3.1
uygulaması oluşturuyoruz:

Uygulamayı oluşturduğumuzda kodlarımız şu şekildedir...
using System;
using
System.Collections.Generic;
using
System.Linq;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Audio;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.GamerServices;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Input;
using
Microsoft.Xna.Framework.Media;
using
Microsoft.Xna.Framework.Net;
using
Microsoft.Xna.Framework.Storage;
namespace DemoTest
{
public class Game1 :
Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager
graphics;
SpriteBatch
spriteBatch;
public
Game1()
{
graphics = new
GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected
override void
Initialize()
{
base.Initialize();
}
protected
override void
LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected
override void
UnloadContent()
{
}
protected
override void
Update(GameTime gameTime)
{
base.Update(gameTime);
}
protected
override void
Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue)
base.Draw(gameTime);
}
}
}
Şimdi yapacağımız işlem,Project->Add Reference ile
“System.Windows.Forms” namespace ini projemizin referanslarına dahil etmektir.

Ve namespace i de projemizde deklare ediyoruz:

Not: Ekstra dan System.Drawing namespace’ini de ekleyip
Deklare ediniz...
TextBox Kontrolü:
Input işlemleri için kullanabileceğimiz bir Windows Kontrolüdür.XNA projemize
Textbox ı:
Uygulamanın değişken tanımlayabileceğimiz herhangi bir
yerinde
TextBox ornek = new TextBox();
tarzında yeni bir TextBox nesnesi tanımlıyoruz
ve yüklenmesini sağlamak için de aşağıdaki fonksiyona arkaplanı gri olarak
görülen kodları yazıyoruz.
protected override
void Initialize()
{
base.Initialize();
ornek.Location = new
System.Drawing.Point(40, 40);
ornek.BorderStyle = BorderStyle.None;
ornek.Multiline = true;
ornek.Size = new Size(400, 400);
Control.FromHandle(Window.Handle).Controls.Add(ornek);
}
“Control.FromHandle(Window.Handle).Controls.Add(ornek);”
kod yapısını birazcık açıklamamda fayda var.
“Control.FromHandle” anlaşılacağı üzere
İlgili handle üzerindeki controlü çağırmamıza yaramaktadır.
“Control.FromHandle(Window.Handle)” Window adı verilen GameWindow nesnesinin
Handle ını alıyor.Game sınıfı bir kontrol değildir. Ama Window nesnesi bir
kontrol olduğundan ötürü handle ını çağırıp kontrol ekleyebilir veya
kaldırabilirsiniz.Windows Formlarında her şeyin birer kontrol olduğunu
varsayarak istediğimiz yere istediğimiz kontrolü yerleştirebiliyorduk.Windows
Geliştiricileri için şöyle bir varsayım yapmalarını rica edeceğim: “Form
nesnesi ile GameWindow nesnesi birbirine benzemektedir.” Bu şekilde düşünürsek
XNA uygulamalarımızda Windows Forms da yaptığımız “RAD(Rapid Application
Development)” ı aynen XNA’de de uygulayabiliriz.
Lakin uygulamanızı çalıştırdığınızda Textbox a harf giremediğinizi
farkedeceksinizdir.
Bunun sebebi Textbox ın “System.Windows.Forms.Keys” değerlerini kabul
ederken,XNA’in “XNA.Framework.Input.Keys” i kabul etmesidir.Windows yöntemiyle
yapamayacağımıza göre girilen inputları bir string değerine aktarıp okutmaktır.
string deger;
diye bir değişken tanımlayalım ardından Update
fonksiyonuna gelerek aşağıdaki gibi bir kodlama ekleyelim:
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
if
(ornek.Focused)
{
KeyboardState
ns = Keyboard.GetState();
foreach
(Microsoft.Xna.Framework.Input.Keys a in ns.GetPressedKeys())
{
deger = a.ToString();
ornek.Text += deger;
}
}
}
“KeyboardState ns = Keyboard.GetState();”
kodu ile o an basılan tuşların değerlerini aldık.Tabi Textbox için tüm tuşları
alıyoruz(“ns.GetPressedKeys()”).Dilerseniz tüm tuşları almayıp if else yapısı
ile sadece belirli tuşların basılmasını izleyip değer değişkeni güncelleyebilir
dilerseniz de foreach döngüsü içerisinde if else yapısı kullanarak Textbox a
yazılmasını istemediğiniz tuşları eleyebilirsiniz.
Uygulamayı bu haliyle çalıştıralım bakalım.Ne olacak?

1 kere A tuşuna basınca birden fazla tuş
Textbox ımıza yazıldı.bunu biraz açıklayalım.
Xna de Update kısmında yapılan her olay belirli
Gametime değerine göre olur.1 snlik işlemde 5 kere tekrar edilir.1 işlem 12
salise sürer.5 kere aynı işlemden yapılınca 60 salise = 1 sn eder.Burda 5 kere
“A” harginin yazılmasının sebebi de budur.
Peki bunun çözümü nasıldır?
bir int değeri oluşturup Update işlemlerini sorgulayacağız.
Şöyle:
İlk önce ct adında bir int değer tanımlıyoruz
değişkenleri tanımladığımız alanda.
int ct = 0;
Ardından Update fonksiyonumuzu aşağıda
görüldüğü üzere güncelliyoruz:
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
if
(ornek.Focused)
{
ct = ct -1;
if(ct <
0)
{
ct = 5;
}
if(ct ==
0)
{
KeyboardState
ns = Keyboard.GetState();
foreach
(Microsoft.Xna.Framework.Input.Keys a in ns.GetPressedKeys())
{
deger = a.ToString();
ornek.Text += deger;
}
}
}
}
Bundan böyle istediğimiz tuşu tekrarlanmadan girebiliriz:

Tüm uygulamanın kaynak kodları...
using System;
using
System.Collections.Generic;
using
System.Linq;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Audio;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.GamerServices;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Input;
using
Microsoft.Xna.Framework.Media;
using
Microsoft.Xna.Framework.Net;
using
Microsoft.Xna.Framework.Storage;
using
System.Windows.Forms;
using
System.Drawing;
using
System.Threading;
namespace DemoTest
{
public class Game1 :
Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager
graphics;
SpriteBatch
spriteBatch;
TextBox
ornek = new TextBox();
string
deger;
int ct
= 0;
public
Game1()
{
graphics = new
GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected
override void
Initialize()
{
base.Initialize();
ornek.Location = new System.Drawing.Point(40,
40);
ornek.BorderStyle = BorderStyle.None;
ornek.Multiline = true;
ornek.Size = new Size(400,
400);
Control.FromHandle(Window.Handle).Controls.Add(ornek);
}
protected
override void
LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected
override void
UnloadContent()
{
}
protected
override void
Update(GameTime gameTime)
{
base.Update(gameTime);
if
(ornek.Focused)
{
ct = ct -1;
if(ct
< 0)
{
ct = 5;
}
if(ct
== 0)
{
KeyboardState
ns = Keyboard.GetState();
foreach
(Microsoft.Xna.Framework.Input.Keys a in ns.GetPressedKeys())
{
deger = a.ToString();
ornek.Text += deger;
}
}
}
}
protected
override void
Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}
TextBox ile yapılan bu uygulamamız umarım
işinize yarar.
BUTTON:
Button kontrolü bir işlemi onayladığımızı gösteren kontrollerden birisidir.Bu
bölümde Button kontrolü nasıl yüklenir ondan bahsedeceğim:
Not:Yukarıdaki Textbox yüklemesi yapılmadan
önceki işlemleri(referans yükleme ve tanımlama) yaptığınızdan emin olun.
Button btn = new Button();
Şeklinde deklare edilir.
Projede kullanılması:
protected override void
Initialize()
{
base.Initialize();
btn.Text = "Beni
Tıkla!";
btn.Location = new
System.Drawing.Point(50, 50);
btn.FlatStyle = FlatStyle.Popup;
Control.FromHandle(Window.Handle).Controls.Add(btn);
}
Şeklindedir.lakin bu button a ait bir
eventhandler yazmadığımızı farketmişsinizdir.şimdi onu da yazalım.
protected override void
Initialize()
{
base.Initialize();
btn.Text = "Beni
Tıkla!";
btn.Location = new
System.Drawing.Point(50, 50);
btn.FlatStyle = FlatStyle.Popup;
btn.Click += new
System.EventHandler(ButtonClick);
Control.FromHandle(Window.Handle).Controls.Add(btn);
}
private void ButtonClick(object
sender, EventArgs e)
{
MessageBox.Show("Button Tıklandı!");
}
Şeklinde kodlarımızı güncelliyoruz.
Yukarıda eventhandlerımızı da yazmış
bulunmaktayız.Button yükleme olayı da bundan ibarettir.

Button Uygulamasının tüm kodları:
using System;
using
System.Collections.Generic;
using
System.Linq;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Audio;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.GamerServices;
using
Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using
Microsoft.Xna.Framework.Media;
using
Microsoft.Xna.Framework.Net;
using
Microsoft.Xna.Framework.Storage;
using
System.Windows.Forms;
using
System.Drawing;
using
System.Threading;
namespace DemoTest
{
public class Game1 :
Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager
graphics;
SpriteBatch
spriteBatch;
Button
btn = new Button();
public
Game1()
{
graphics = new
GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected
override void
Initialize()
{
base.Initialize();
btn.Text = "Beni
Tıkla!";
btn.Location = new System.Drawing.Point(50,
50);
btn.FlatStyle = FlatStyle.Popup;
btn.Click += new System.EventHandler(ButtonClick);
Control.FromHandle(Window.Handle).Controls.Add(btn);
}
private
void ButtonClick(object
sender, EventArgs e)
{
MessageBox.Show("Button Tıklandı!");
}
protected
override void
LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected
override void
UnloadContent()
{
}
protected
override void
Update(GameTime gameTime)
{
base.Update(gameTime);
}
protected
override void
Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}
CHECKBOX Kontrolü:
Checkbox kontrolü çoklu seçimi olan işlerde
kullanılan bir Windows Kontrolüdür.
Deklare edilişi:
CheckBox cb = new CheckBox();
Kullanılışı:
protected override void
Initialize()
{
base.Initialize();
cb.CheckState = CheckState.Unchecked;
cb.Location = new
System.Drawing.Point(50, 50);
cb.Text = "Evet";
cb.BackColor = System.Drawing.Color.CornflowerBlue;
Control.FromHandle(Window.Handle).Controls.Add(cb);
}
Şeklindedir.

Bir eventhandler ekleyerek
checkbox textini değiştirelim:
protected override void
Initialize()
{
base.Initialize();
cb.CheckState = CheckState.Indeterminate;
cb.Location = new
System.Drawing.Point(50, 50);
cb.Text = "Tanımsız";
cb.BackColor = System.Drawing.Color.CornflowerBlue;
cb.CheckStateChanged += new EventHandler(CBChanged);
Control.FromHandle(Window.Handle).Controls.Add(cb);
}
private void CBChanged(Object
sender, EventArgs e)
{
if
(cb.CheckState == CheckState.Unchecked)
{
cb.Text = "Hayır";
}
else if (cb.CheckState == CheckState.Checked)
{
cb.Text = "Evet";
}
}
Uygulamayı birazcık
değiştirdik.ve ilk yüklendiğinde tanımsız olmasını istedik.
Check olması=Checked
Check olmaması=Unchecked
Her ikisinin de olmaması=Indeterminate
Uygulamayı çalıştırıyoruz.
Indeterminate Mod:

Unchecked Mod:

Checked Mod:

Windows Kontrolleri örneklerimizi buraya kadar elimden geldiğince XNA de
uygulatmaya çalıştım.Şimdi de işin en heyecanlı kısmına gelelim: WPF!
WPF Uygulamaları:
WPF Uygulamalarını XNA e
dahil etmek işin en heyecan verici ve zaman isteyenidir.
Eklememiz gereken birkaç
adet ek referans bulunmaktadır.Bunları ekleyerek işe hemen başlayalım:
- Presentation Core
- Presentation Framework
- UIAutomationProvider
-
WindowsBase
- WindowsFormsIntegration
Bu reference ları ekledikten
sonra önceden hazırladığımız bir WPF UserControl ü projeye Project->“Add
Existing Item...” ile ekleyelim

Ve ilgili dosyayı bulalım ve ekleyelim:

Şimdi yapacağımız işlem yukarıdaki Windows Kontrollerinde olduğu gibi Kontrol
yüklemek.
İlk önce Kontrolümüzün
bulunduğu namespace i projeye dahil ediyoruz.
using
WindowsFormsApplication1;
Bu WPF UserControlümüzün
namespace idir.Burayı sizin namespace iniz neyse ona göre
değiştirebilirsiniz...
WPF User Controlümüz ün
içerisinde bir WPF Combobox bulunmaktadır.Seçilen değere göre ekrana mesaj
göstermektedir.
Kod Dosyası:
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs
e)
{
ComboBoxItem
cbi = ((ComboBox)sender).SelectedItem as ComboBoxItem;
MessageBox.Show(cbi.Content.ToString());
}
XAML Dosyası:
<UserControl x:Class="WindowsFormsApplication1.Kontrol1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<ComboBox Height="23"
Margin="48,70,132,0"
Name="comboBox1" VerticalAlignment="Top"
SelectionChanged="comboBox1_SelectionChanged">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
<ComboBoxItem>4</ComboBoxItem>
</ComboBox>
</Grid>
</UserControl>
Kontrol1 kontrol11
= new Kontrol1();
Diyerek WPF User
Controlümüzü projemize dahil ediyoruz.
Ardından “Initialize()” fonksiyonunda
Kontrolümüzü çağırıyoruz...
protected override void
Initialize()
{
base.Initialize();
//ElementHostumuz
ElementHost
elementHost1 = new ElementHost();
elementHost1.Location = new System.Drawing.Point(308,
69);
elementHost1.Name = "elementHost1";
elementHost1.Size = new
System.Drawing.Size(350, 181);
elementHost1.TabIndex = 1;
elementHost1.Text = "elementHost1";
elementHost1.Child = this.kontrol11;
Control.FromHandle(Window.Handle).Controls.Add(elementHost1);
}
Yukarıdaki koddan da
anlaşılacağı üzere ElementHost kullanarak WPF User Controlümüzü XNA
uygulamamızın içine çağırdık.
Bu şekliyle çalıştıralım
bakalım.Ne olacak?

Evet doğru söylemektedir.Farklı UI elementleri kullanan uygulamalarda bu tarz
hatalarla karşılaşmanız çok mümkündür.Çünkü bizim yapmaya çalıştığımız uygulama
şu aşamada Multi-Thread gözükmektedir.Bizden bunu SingleThread yapmamız
istenmektedir.
Program.cs dosyamızı açarak:
using System;
namespace DemoTest
{
static class Program
{
static void Main(string[]
args)
{
using
(Game1 game = new
Game1())
{
game.Run();
}
}
}
}
Aşağıdaki gibi değiştirelim:
using System;
namespace DemoTest
{
static class Program
{
[STAThread]
static void Main(string[]
args)
{
using
(Game1 game = new
Game1())
{
game.Run();
}
}
}
}
[STAThread] kullanarak istenileni gerçekleştirdik.Şimdi uygulamamızı bir daha
çalıştıralım...

WPF Uygulamamız Arka Planı
Gri bir alanda görüntüleniyor gördüğünüz üzere..

WPF Uygulamasındaki Combobox larımız dan bir eleman seçiyoruz.ve

Bize seçtiğimiz elemana ait
bilgiyi gösteriyor.
XNA-WPF Uygulamasına ait kaynak kodlar...
using System;
using
System.Collections.Generic;
using
System.Linq;
using
Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Audio;
using
Microsoft.Xna.Framework.Content;
using
Microsoft.Xna.Framework.GamerServices;
using
Microsoft.Xna.Framework.Graphics;
using
Microsoft.Xna.Framework.Input;
using
Microsoft.Xna.Framework.Media;
using
Microsoft.Xna.Framework.Net;
using
Microsoft.Xna.Framework.Storage;
using
System.Windows.Forms;
using
System.Drawing;
using
System.Windows.Forms.Integration;
using
System.Threading;
using
WindowsFormsApplication1;
namespace DemoTest
{
public class Game1 :
Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager
graphics;
SpriteBatch
spriteBatch;
Kontrol1
kontrol11 = new Kontrol1();
public
Game1()
{
graphics = new
GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected
override void
Initialize()
{
base.Initialize();
//ElementHostumuz
ElementHost
elementHost1 = new ElementHost();
elementHost1.Location = new System.Drawing.Point(308,
69);
elementHost1.Name = "elementHost1";
elementHost1.Size = new System.Drawing.Size(350,
181);
elementHost1.TabIndex = 1;
elementHost1.Text = "elementHost1";
elementHost1.Child = this.kontrol11;
Control.FromHandle(Window.Handle).Controls.Add(elementHost1);
}
protected
override void
LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
}
protected
override void
UnloadContent()
{
}
protected
override void
Update(GameTime gameTime)
{
base.Update(gameTime);
}
protected
override void
Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.Draw(gameTime);
}
}
}
Bu makalemizde Windows
Kontrollerinden Textbox,Button,CheckBox ve ElementHost’u XNA Uygulamalarına
dahil ettik ve örnek uygulamalarla nasıl kullanabildiğimizi gördük.
Bu vesileyle XNA de Windows
Kontrolleri ve WPF Uygulamalarınında Entegrasyonu nu sağlamış olduk.
Bu makale den sonra XNA in sırf Windows,XBOX yada Zune tabanlı oyun geliştirme
de işe yaramadığını çok daha geniş alanlara da hitap edebileceğini,Windows
uygulamalarınızı “Zengin efektli XNA Uygulamaları”na dönüştürmenin sizin
elinizde olduğunu göreceksiniz.
İlerleyen makalelerimde
“Zengin Efektli XNA Uygulamaları” deyiminden ne demek istediğimi detaylı bir
şekilde anlatacağım.
XNA in saklı güzelliklerini anlatmaya devam edeceğim...
Beni takip etmenizi tavsiye
ediyorum ;)
İyi Günler Dilerim
İbrahim Ersoy