Bazı zamanlarda programımızda bir word çıktısı ihtiyacı kaçınılmazdır. Ancak her zaman müşterimizin spesifik çıktı işlemleri için programımıza bir word yada excel export eklememiz gerekmeyebilir. Konuyu şöyle anlatacak olursak, örneğin elinizde çalışan büyük bir programınız var ve yüzlerce kullanıcı bu programı kullanmakta. Ancak A departmanı gelip sizden programa ait verileri içeren bir adet word çıktısı isteyebilir. Bu durumda ilk akla gelen programın A departmanı ile ilgili arayüzüne yeni bir sayfa yada form ekleyip kullanıcının isteğini gerçekleştirmek. Ancak bu hem zaman alır, hemde çalışan programa müdahale etme gereksinimi doğurur. Deployment yapmadan önce daha detaylı testler gerektirir vs vs.
Diğer bir yöntem ise önceden hazırlanmış belirli bir word dökümanına eklenti yazmak olabilir. Bunun için visual studio bize oldukça kolay kullanımlı araçlar sunuyor.
İsterseniz benim de daha önce çalıştığım bir kurumda karşılaştığım bir ihtiyaç üzerinden bir örnekle devam edelim. Gerçek hayat örnekleri bence her zaman daha kolay anlaşılıyor 🙂
Çalıştığım kurumun binlerce kredi müşterisi bulunmaktaydı ve kredi ödemelerini takip eden departmandan şöyle bir istek geldi. “Bizim elimizde müşterilere gecikme durumunda idari takip olacağını belirten sabit formatta bir word dokumanımız var ve programın ekranından müşteri bilgilerine bakarak belli gün gecikmesi olan müşterilere mektup hazırlıyoruz ve gönderiyoruz. Ancak bu çok vaktimizi alıyor. Çözüm üretir misiniz?” İstek bu şekildeydi. Ofisin içinde yer alan adres mektup birleştirme yöntemini kullanarak çözemiyorlardı çünkü istemiş oldukları bilgiler bir excel yada access listesinde değildi. Ancak geliştirici olarak ben de müşteri takip programımıza müdahale etmek istemiyordum. Gelin şimdi bunun için bir çözüm üretelim.
İlk önce Visual Studio’nuzda bir adet Office Word Document Projesi oluşturunuz.
Ben projeye “GecikmeMektubuApp” adını verdim.
Daha sonra ekranda size Yeni Bir Word dokümanı mı oluşturmak istiyorsunuz yoksa mevcut bir tanesini mi seçmek istiyorsunuz diye soracak. Senaryo gereği zaten ilgili departman mektubu önceden hazırladığı için ben yeni bir döküman oluşturmuyorum.
Ok’e bastıktan sonra dikkat ederseniz Visual Studio içerisinde Office Word açıldı. Bu pek alışık olmadığımız durum bize çok büyük kolaylık sağlamakta. Seçmiş olduğum mektubun metni de aynen ekranda yer almakta. Solution Explorer’a bakarsanız bir adet docx (muhtemelen seçtiğiniz döküman isminde) ve bu docx dosyası altında yer alan “ThisDocument.cs” dosyasını göreceksiniz. ThisDocument.cs mevcut dökümanınızla ilgili global işlemleri yapmanıza yaracak.
Aşağıdaki ekranda görüneceği üzere ben mektubumda değişken olacak yerleri belirledim. Şimdi burda önemli nokta sadece benim değişkenleri belirlemem değil bunların değişken olacağını programıma da söylemem. Bunun için değişken olacak kelime yada kelime grubunu seçin ve daha sonra Toolbox’ınızda yer alan “Word Controls” grubu içinden “Bookmark” tutup seçili kelime grubunuz üzerine sürükleyin. Çıkan bilgilendirme mesajına ok diyip kapatın. Şu anda sayfamızın içine bir adet bookmark koyduk ve muhtemelen adı “bookmark1” gibi bir şey olmalı. Bookmarkınızın üzerine imleci koyup visiual studio’da yer alan properties pencerisine bakacak olursanız bookmark adını görebilirsiniz. Bunu anlamlı bir isimle değiştirin. Örneğin “bmMusteriAdi” gibi.
Bütün değişkenlere bookmark koyduysanız artık word dökümanımızla işlemimiz bitti ve bir arama ekranı tasarlamamız gerekmektedir. Arama ekranında çalışan gecikme gün sayısını girecek ve girdiği sayıya eşit ve büyük olan sonuçları ekrana getirecek. Peki word içerisinde kendimize ait bir pencere nasıl oluşturacağız.
Bunun için Solution Explorer’da projenizi sağ tıklayıp Add >> New Item diyerek yeni bir Action Pane Control ekleyin. Ben ismine “apCreditSearch” dedim. Dikkat ederseniz action pane windows form uygulamalarında yer alan user control gibi düz, pencere kontrolleri olmayan bir panel gibi görünüyor. Bunun içine ben bir adet textbox, bir adet button ve bir adat datagridview kontrolü koydum ve ekran aşağıdaki gibi oldu.
Bu bizim arama ekranımız ve artık c# kodları yazabiliriz. İki adet event’im var. Birincisi tabiki Button Click eventi diğeri ise grid view’e ait selection change eventi. Örnek uygulama olduğu için verileri mi bir veri tabanı yerine bir listeden çektim. O yüzden action pane control’üm ilk oluşturulduğunda veri listemi dolduruyorum. Action Pane’e ait kodlar aşağıdaki gibidir.
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace GecikmeMektubuApp { partial class apCreditSearch : UserControl { //Data kaynağım List<KrediBilgisi> datalar = new List<KrediBilgisi>(); public apCreditSearch() { InitializeComponent(); //Daya kaynağımı dolduruyorum. DataListesiniDoldur(); } private void btnBul_Click(object sender, EventArgs e) { //Ara butonu ile arama işlemini yapıyor ve grid kontrolümü dolduruyorum. grdResult.DataSource = DatalariGetir(Convert.ToInt16(txtGun.Text)); grdResult.Columns[2].Visible = false; grdResult.Columns[4].Visible = false; grdResult.Columns[5].Visible = false; } //Data kaynağını gecikme gün sayısına göre filtreliyorum. public List<KrediBilgisi> DatalariGetir(int gecikmeGunSayisi) { return datalar.Where(x => x.GecikmeGun >= gecikmeGunSayisi).ToList(); } public void DataListesiniDoldur() { for (int i = 0; i < 15; i++) { KrediBilgisi item = new KrediBilgisi() { GecikmeGun = i, KrediNo = 8234596 + i, KrediTutari = 12 * i, Musteri = "Deneme Müşterisi_" + i.ToString(), OdemeGunu = DateTime.Today.AddMonths(-i), TaksitNo = i }; datalar.Add(item); } } private void grdResult_SelectionChanged(object sender, EventArgs e) { if (grdResult.SelectedRows.Count > 0) { KrediBilgisi seciliKredi = (KrediBilgisi)grdResult.SelectedRows[0].DataBoundItem; //Dokümanıma koymuş olduğum bookmark'ları güncelliyorum. Globals.ThisDocument.bmGecikmeGun.Text = seciliKredi.GecikmeGun.ToString(); Globals.ThisDocument.bmKrediNo.Text = seciliKredi.KrediNo.ToString(); Globals.ThisDocument.bmKrediTutari.Text = seciliKredi.KrediTutari.ToString("f2"); Globals.ThisDocument.bmMusteriAdi.Text = seciliKredi.Musteri; Globals.ThisDocument.bmTaksitNo.Text = seciliKredi.TaksitNo.ToString(); Globals.ThisDocument.bmTaksitTarihi.Text = seciliKredi.OdemeGunu.ToShortDateString(); } } } //Örnek nesnem public class KrediBilgisi { public string Musteri { get; set; } public int KrediNo { get; set; } public decimal KrediTutari { get; set; } public int GecikmeGun { get; set; } public int TaksitNo { get; set; } public DateTime OdemeGunu { get; set; } } }
Artık arama işlemi de bitti. Burada dikkat edilmesi gereken husus Action Pane Control’ümden word dökümanı içerisinde yerleştirmiş olduğum bir bookmark’a erişme şekli. Dikkat ederseniz Globals.ThisDocument diyerek thisdocument içerisinde yer alan nesnelere erişebiliyorum.
Şimdi sadece yapmamız gereken bu word dokümanı çalıştığında ekranda Action Pane Control’ümüzü göstermek bunun için ThisDocument.cs de yer alan “ThisDocument_Startup” olayını kullanıyoruz. Adından da anlaşılacağı üzere word dokümanı ilk çalıştırıldığı zaman bu olay çalışacak.
ThisDocument.cs
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml.Linq; using Microsoft.Office.Tools.Word; using Microsoft.VisualStudio.Tools.Applications.Runtime; using Office = Microsoft.Office.Core; using Word = Microsoft.Office.Interop.Word; namespace GecikmeMektubuApp { public partial class ThisDocument { //ActionPane kontrolümüzün bir örneğini oluşturuyoruz. private apCreditSearch apSearch = new apCreditSearch(); private void ThisDocument_Startup(object sender, System.EventArgs e) { //Ekranda ActionPane kontrolümüzü gösteriyoruz. this.ActionsPane.Controls.Add(apSearch); } private void ThisDocument_Shutdown(object sender, System.EventArgs e) { } #region VSTO Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(ThisDocument_Startup); this.Shutdown += new System.EventHandler(ThisDocument_Shutdown); } #endregion } }
Uygulamamız bitti ve çalıştırdığımızda aşağıdaki gibi bir ekran görünecektir. İlk başta tabiki gridview boş olacak kullanıcı arama bölümüne bir sayı girdiğinde grid dolacak ve grid’de herhangi bir kişiyi seçtiğinde mektup güncellenecek.
Eğer Solition Explorerda projenizi sağ tıklayıp Publish ederseniz bir adet setup dosyası ve bir adet word dokümanı oluşturacak. Kullanıcı bilgisayarına setup dosyasını kurmasanız bile word dokümanını çalıştırdığınız ilk seferde gerekli kurulumları otomatik yapacak. Sonra kullanıcının her mektup üretmek istediğinde sadece elindeki word dokümanını çalıştırması yeterli olacaktır.
Böylece ayrı bir uygulama yazmadan, mevcut uygulamamıza dokunmadan kullanıcı isteğini gerçekleştirmiş olduk.
Proje doyası: http://yadi.sk/d/eOxwODIwAFpRj
Herkes İyi Çalışmalar,