Excel dosyalarından veri okumak, özellikle iş uygulamalarında kullanıcılara kolaylık sağlayan ve zaman kazandıran bir özelliktir ve kullanıldığı yere göre uygulamamızı geliştirerek bir adım ileriye götürebilir. Büyük Excel dosyalarından istediğimiz verileri çekerek bu verileri görselleştirmek, birden çok Excel dosyasındaki verileri dinamik olarak karşılaştırmak ya da bir sisteme tek tek kullanıcı kaydetmektense kullanıcı bilgilerini bir Excel dosyasından çekerek toplu halde kaydetmek gibi çeşitli senaryolarda işimize yarayabilecek bu özelliği, bu yazımda birlikte bir Silverlight uygulaması içinde kullanacağız.
Öncelikle bir Excel dosyasının (.xlsx) yapısından bahsederek başlayalım. Bir .xlsx dosyası, aslında bir .zip ya da .rar dosyası gibi birden çok dosyayı içeren bir pakettir. Hatta .xlsx uzantısını .zip yapıp dosyayı açarsanız, aşağıdaki gibi içinde çeşitli klasörler ve dosyalar olduğunu görürsünüz. Verilerimiz, işte bu klasörlerin içindeki XML uzantılı dosyalarda tutulur. Eğer biraz araştırırsanız verilerin bu XML dosyaları içinde nasıl tutulduğunu öğrenebilir ve kendi .xlsx okuyucunuzu bile yazabilirsiniz. 🙂
Biz .xlsx dosyasını okumak için bu kadar alt seviye işlemlere inmeden, AutomationFactory sınıfını kullanacağız.
O halde yavaştan uygulamamızı oluşturmaya başlayalım. Uygulamamız, yukarıda verdiğimiz örneklerden biri olan toplu kullanıcı kaydını yapsın. Visual Studio içinden yeni bir Silverlight projesi açalım. Bu arada not olarak, Visual Studio 2012 ve Silverlight 5 kullanıyorum.
Silverlight uygulamamızın bir Web sitesi içinde host edilmesi seçeneğini seçelim.
Boş projemiz açılarak önümüze geldikten sonra, aşağıda gördüğünüz gibi bir DataGrid ve Button yerleştirerek uygulamamızın altyapısını oluşturalım.
Ayrıca, uygulamamızda okumak için bir Excel dosyası oluşturarak içine çeşitli bilgiler girelim.
Artık kod yazmaya geçebiliriz. İlk olarak, DataGrid’e kullanıcıları ekleyebilmek için Excel’deki verilere karşılık gelen bir “Kullanici” sınıfını MainPage.xaml içinde oluşturalım.
public class Kullanici { public string Ad { get; set; } public string Soyad { get; set; } public string Telefon { get; set; } public int Yas { get; set; } }
Sonra da bir Kullanici listesi oluşturalım, ve uygulamamız açıldığında initialize edelim.
public partial class MainPage : UserControl { List<Kullanici> kullaniciList; public MainPage() { InitializeComponent(); kullaniciList = new List<Kullanici>(); } }
Son olarak System.Runtime.InteropServices.Automation kitaplığını using ile projemize ekleyerek, ve References’a birazdan kullanacağımız “dynamic” değişkenler için gerekli olan Microsoft.CSharp kitaplığını ekleyerek hazırlıklarımızı tamamlayalım.
using System.Runtime.InteropServices.Automation;
Şimdi uygulamamızın can alıcı noktasına geldik. Yerleştirdiğimiz düğmeye çift tıklayarak (ya da Properties panelinin events kısmından Click event’ine çift tıklayarak) düğmemize tıklandığında çalışacak metodu oluşturup açalım. Bu metodun içine sırasıyla aşağıdaki kod bloklarını gireceğiz.
Aşağıdaki kod bloğu ile Excel dosyasını seçeceğimiz “File Picker” penceresini açıyoruz.
OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "Excel Files(*.xlsx)|*.xlsx"; bool fileSelected = (bool)fileDialog.ShowDialog(); if (fileSelected) { //Dosyayı oku }
Aşağıdaki kodu “if” ifadesinin içine ekliyoruz.
string fileName = fileDialog.File.Name; dynamic objExcel = AutomationFactory.CreateObject("Excel.Application"); dynamic objExcelWorkbook = objExcel.Workbooks.Open(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\" + fileName); dynamic objActiveWorksheet = objExcelWorkbook.ActiveSheet();
Buradaki değişkenlerin türü gördüğünüz üzere “dynamic”. Yani işlemleri çalışma zamanında çözülerek belirlenecek. Bunun bizim için şu şekilde kötü bir anlamı var ki, dynamic bir değişken ile kod yazarken IntelliSense desteği kayboluyor. Yani tam olarak ne yazdığımızı bilmek zorundayız.
objExcel değişkeni, Excel uygulaması değişkenimiz. objExcelWorkbook değişkeni ise, seçtiğimiz Excel dosyasını, yani Workbook’u temsil ediyor. En son objActiveWorksheet değişkeni ise Excel dosyamız içindeki etkin olan Sheet.
Aşağıdaki kodu “if” ifadesi içine eklemeye devam ederek uygulamamızın kod kısmını tamamlıyoruz.
dynamic objCell1Ad; dynamic objCell2Soyad; dynamic objCell3Telefon; dynamic objCell4Yas; for (int i = 2; i < 14; i++) { objCell1Ad = objActiveWorksheet.Cells[i, 1]; objCell2Soyad = objActiveWorksheet.Cells[i, 2]; objCell3Telefon = objActiveWorksheet.Cells[i, 3]; objCell4Yas = objActiveWorksheet.Cells[i, 4]; Kullanici tempKullanici = new Kullanici(); tempKullanici.Ad = objCell1Ad.Value.ToString(); tempKullanici.Soyad = objCell2Soyad.Value.ToString(); tempKullanici.Telefon = objCell3Telefon.Value.ToString(); tempKullanici.Yas = Int32.Parse(objCell4Yas.Value.ToString()); kullaniciList.Add(tempKullanici); } objExcelWorkbook.Close(false); excelDataGrid.ItemsSource = kullaniciList;
Bu adımda pek çok şey gerçekleştirdik. Öncelikle, en üstteki 4 “dynamic” nesnemiz tek bir Excel hücresini (cell) temsil ediyor. Alttaki döngü, 2’den 14’e kadar (oluşturduğumuz Excel dosyası içindeki verilerimiz 2’den başlayarak 14’te bittiği için) bu hücrelerin değerlerini satır ve sütun belirleyerek dynamic değişkenlerimize atıyor, ve ardından bu değişkenlerdeki değerleri geçici bir Kullanici sınıfı içine attıktan sonra kullanıcı listemize ekliyor. Döngü tamamlandıktan sonra da Workbook’u, yani Excel dosyamızı, kapatarak kullanıcı bilgilerimizi DataGrid içine atıyoruz.
Burada dikkatinizi çekmek istediğim üç nokta var.
Birincisi, verileri kaç satır alacağımızı bilerek çektik. Bu sayının dinamik olarak değiştiği durumlarda, yani kaç satır okuyacağımız belirli değilken nasıl bir yol izlememiz gerektiği ile ilgili kesin bir bilgim yok. Bu durumda şu an tüm Excel dosyasını tarayıp boş bir satıra ulaştığım satır sayısını belirlemek gibi bir yol izliyorum, ancak bu hatalara sebep olabiliyor ve okuma süresini çok uzatıyor. Bu konuda bir bilgisi olup bana ileten olursa çözümü buraya büyük bir zevkle koyarım. 🙂
İkincisi, ad, soyad ve telefon string oldukları için doğrudan okundular, ancak yaş bir integer olduğu için Int32.Parse metodunu kullanmamız gerekti. Bu bir deneme uygulaması olduğu için sorun olmaz, ancak o hücrede integer olamayacak bir değer olursa uygulamamız çalışma zamanında çöker. Bu nedenle, veri okurken mutlaka doğrulama yapmamız gerekli.
Üçüncüsü, işiniz bittikten sonra Workbook’u kapatmayı mutlaka unutmayın. Eğer kapatılmazsa, arkaplanda bir Excel process’i çalışmaya devam ediyor ve dosyayı yazmaya kilitliyor. Sonuç olarak görev yöneticisinden elle kapatmanız gerekiyor.
Uygulamamızı çalıştırmadan önce yapmamız gereken son işlem ise, uygulamamızı Out-of-Browser ve elevated trust modlarında çalışacak şekilde ayarlamamız. AutomationFactory güvenlik sebeplerinden dolayı yalnızca yüksek güvenlikte ve out-of-browser modunda çalışabiliyor. Araştırdığım kadarıyla browser içinde de elevated trust modunda çalıştırmak mümkün, ancak bunun için Group Policy ayarları gerekli.
Out-of-Browser ve elevated trust modlarını açmak için, projemize sağ tıklayarak Properties bölümüne giriyoruz. “Enable running application out of the browser” seçeneğini işaretledikten sonra, Out-of-Browser Settings’e tıklayarak, açılan pencereden “Require elevated trust when running out of browser” seçeneğini seçiyoruz.
Artık uygulamamızı çalıştırmaya hazırız. 🙂 Çalıştırmadan önce son bir not, Excel dosyası okunurken uygulamamız takılıp kilitlenecek. Bunun sebebi, okuma işlemini ayrı bir thread içinde yapmadığımız için UI thread’in kullanılacak olması ve işlem esnasında arayüzün cevap vermemesi.
Eğer düğmeye basıp hazırladığımız Excel dosyasını seçerseniz, karşınıza aşağıdaki görüntü çıkacak. 🙂
Bu seferki uzun bir yazı oldu. 🙂
Uygulamanın kaynak koduna (ve Excel dosyasına) buradan ulaşabilirsiniz.
Gelecek yazılarımda görüşmek üzere. 🙂
teşekkürler çok işime yaradı bildiğin hayat kurtardı allah razı olsun