Bu siteye giriş yaparak Çerez kullanımını kabul etmiş oluyorsunuz. İşbu sitede; çerez olarak, sadece son giriş tarihiniz ve eğer üye olursanız oturum statünüz tutulacaktır. Bunlar dışında başka hiçbir bilgi tutulmamaktadır. Çerezler için detaylı bilgi için buraya tıklayınız.
ANLADIM

DUYURULAR

Yeni eklenen ve/veya güncellenen sayfaları görmek için buraya tıklayınız.

Güncel ödev ve test listesini görmek için buraya tıklayınız.

Sitede yapılan iyileştirmeAer ve hata düzeltmelerine ait tüm bilgilendirmeleri görmek içinburaya tıklayınız.

Baş
Udemy
Konular
Son
Konular
ExcelNesneModeli
CoreVSTO
VSTO
VSTOGörsel Araçlar2

Excel ile çalışmak

Excel obje modelini ve 4 temel nesneyi iyi bildiğinizi varsayarak başlıyorum. Bilmiyorsanız önce bu linklere bakın, zira bu sayfada bunların ne anlama geldiği açıklanmayacak.

Temel kaynağınız: Understanding the Excel Object Model from a .NET Developer's Perspective dokümanı ama içindeki bazı bilgiler eski, özellikle c#'ın desteklemediğini söylediği şeylerin çoğu artık destekleniyor. O yüzden bu linki bi yere kaydedin ve benim sitedeki okumalarınızı bitirdikten ve biraz pratik yaptıktan sonra mutlaka bu linke tekrar bakın ve konuyu içselleştirin.

Şimdi .Net dünyasında Excel ile çalışırken iki yolumuz bulunmakta. Bunlar;

  • Excel API'si kullanmak. Bunun için bir VSTO projesinde(Excel Add-in) hazır olarak gelen Microsoft.Office.Interop.Excel kütüphanesi kullanılır.(Bir de Office.Tools.Excel var ama bunu hiç kullanmayacağız)
  • 3rd Party kütüphanelerin kullanımı.

Biz burada ağırlıklı olarak ilk yöntemi kullanacağız. Ama ikinci yöntem hayat kolaylaştırıcı yöntemdir, o yüzden bunlara da değineceğiz. Bu kütüphaneler o kadar güçlüdür ki, Excel'iniz kapalıyken de işlem yaparlar, hatta Excel kurulu olmasa dahi excel dosyaları yaratabilirler. Hayat kolaylaştırıcılıkları ise 1.yöntemde belli işler için uzun uzun yazdığınız kodlar yerine tek satırlık kodlarla işinizi halletmenizi sağlamasındandır.

NOT: Şimdilik kodları sadece takip edin. Sonraki sayfadaki İlk VSTO Add-inimizi yaparken uygun yerlere bunları kendiniz de koyup deneyebileceksiniz.

Excel API'si(Office.Interop)

Bu yöntemde Excel nesneleriyle çalışabilmemiz için kodunuzun tepedeki using directivelerinin olduğu kısımda şu satırın yazması gerekir.

using Excel = Microsoft.Office.Interop.Excel;

Vb.Net'te Imports kısmında aynısını yapabileceğiniz gibi, MyProject>References içinde aşağıdaki gibi ekleyerek de bunu yapabilirsiniz.

Bu arada VBA'de kullandığımız MsgBox, InputBox gibi fonksiyonlar VB.Net'te yine kullanılabilir durumdadır. Ancak bir şekilde c#'ta da bunları kullanmak isterseniz, projenize Microsoft.VisualBasic kütüphanesini eklemek gerekecektir. Özellikle InputBox kullanımı için bu kütüphaneye başvuracağız, zira c#'ta böyle bir fonksiyon(metod) yok.

Globals sınıfı

Bir sonraki sayfada göreceğimiz gibi, bir Add-in projesi yarattığımızda VS'nin bazı sınıfları otomatik oluşturacaktır. Bunlardan biri de Globals sınıfıdır. Bu sınıf ThisAddIn.Designer.cs dosyası içinde yer alır. Kod bloğunun içinde ne yazdığını bilmemize gerek yok. Bu sınıfla ilgili bilmemiz gereken şey şu: Bunun sayesinde aşağıdaki nesnelere erişim sağlayabiliyoruz.

  • Document Level projelerde ThisWorkbook ve Sheetn sınıflarına. Ör: Globals.ThisWorkbook
  • Application level projelerde ThisAddin sınıfı. Globals.ThisAddin
  • Ribbon Designerda tasarladığımız Ribbonlara. Globals.Ribbons.Ribbon1

Bu, şu demek oluyor. VBA'de doğrudan kullandığımız ActiveCell veya ActiveSheet gibi nesneler vardı. Document Level bir projede ThisWorkbook sınıfı dışından, Application Level bir projede de ThisAddin sınıfı dışından bunlara direkt ulaşamazsınız. Mesela bir Ribbondan (veya bir başka sınıf içinden) ulaşmak için bunlara Globals sınıfı üzerinden erişmeniz gerekir. Aşağıda çeşitli örnekler var(basitlik adına şuan için conversion yapmıyorum)

//Doc level proje ThisWorkbook içi
ThisWorkbook.ActiveSheet //veya this.ActiveSheet
ThisApplication.... //veya this.Application

//Doc level proje Ribbon
Glboals.ThisWorkbook.ActiveSheet....
Globals.ThisWorkbook.Application

//App level proje ThisAddin içi
this.Application.ActiveCell....

//App level proje Form1 sınıfı
Globals.ThisAddIn.Application.ActiveCell....

4 Temel Sınıf/Nesne

Application

Yukarıda  gördüğümüz gibi Application nesnesine Globals sınıfı üzerinden ulaşacağız. Size tavsiyem, her defasında Application'ı bu şekilde uzun uzun yazmak yerine bunu ilgili sınıfta public variable(Ör:app) olarak tanımlayıp sonra bunu kullanmanızdır. Veya çok fazla sınıfı olan bir uygulamanız olacaksa her sınıfta ayrı ayrı değişkenler tanımlamak yerine static bir sınıf oluşturun ve bu sınıfın içine bir kez tanımlayın ve her defasında bunu çağırın. Vb.Net'te çalışıyorsanız "genel modül" ismini vereceğiniz bir modülde de yapabilirsiniz. Burada Vb.Net'in küçük bi avantajı var; bu değişkenin önünde modül adı gibi birşey belirtmeye gerek olmuyor.

Statik sınıf detaylarını ve neden static sınıf kullandığımızı şuradan görebilirsiniz. (static detayını bilenler bu parantezli kısmı geçebilir. Özetlemek gerekirse statik sınıflardan biz nesne yaratmayız, ona ait metod ve propertyleri doğrudan kullanabiliriz. En bilinen örneği Math sınıfıdır. Çeşitli matematik fonksiyonlarının bulunduğu bu sınıfı kullanmak için bu sınıftan bi nesne yaratmanın bi esprisi yok, sınıfı doğrudan kullanabilmeliyizdir. Halbuki form gibi bir nesnede ise, Form sınıfından bir nesne yaratıyor(aslında Form sınıfını inherit eden Form1 veya başak bir isim verdiğiniz bir form sınıfı), sonra bu nesnenin Show metodunu kullanıyorduk, doğrudan Form(Form1) sınıfını kullanamıyorduk. Bizim örneğimizde de bi utility sınıf oalrak MyStatik adında bi sınıf yaratacağız ve bundaki app değişkenini kullanacağız)

//Statik sınıfı ve değişkeni tanımlama
using Excel = Microsoft.Office.Interop.Excel;
            
namespace VSTOcsharp
{
    static class MyStatik
    {
        public static Excel.Application app = Globals.ThisAddIn.Application;
    }
}

//projede herhangi bir yerde kullanımı
MyStatik.app.ScreenUpdating=false; //Statik sınıf adını da öne koyuyoruz

VB.Net tarafında yukarıdaki kullanıma ek olarak aşağıdaki modül kullanımına bakalım.

'Genel modül içi
Public app As Excel.Application = Globals.ThisAddIn.Application

'projede herhangi bir yerde kullanımı
app.ScreenUpdating=False 'Modül adını öne koymaya gerek yok

Workbook

Buradan itibaren yukarıdaki app değişkenini kullanacağız. VBA'de buna ihtiyacımız yoktu, zira Application nesnesi default nesneydi. VSTO'da ise işler değişiyor. Ancak bir kez app nesnesi elimizdeyken wb ve ws nesnelerine erişim kolay olacaktır.

Yeni bir dosya açıp bunu bi değişkene atayalım. Bunu tek satırda yapabileceğimizi biliyorsunuz artık.

Excel.Workbook wb = app.Workbooks.Add();

VBA'de bunu şöyle yapardık

Dim wb As Workbook
Set wb = Workbooks.Add

VSTO'daki farkı özetleyecek olursak

  • Tek satırda değişken tanımlayıp atama yaptık
  • Set ifadesi kullanmadık, zaten bu ifade artık yok. Ayrı satırlarda yapsaydık bile kullanmazdık
  • Add metodu sonunda parantez kullandık
  • Workbooks collectionu önünde app nesnesini kullandık.

Bir dosyayı açmak için;

MyStatik.app.Workbooks.Open(@"E:\OneDrive\Uygulama Geliştirme\web sitelerim\Yeni Efendi\Ornek_dosyalar\CF.xlsx");

NOT: Buradaki @ işareti, klasör ayracı olan \ işaretini bir kez kullanmamızı sağlar, aksi halde \\ yazmak lazımdı. Zira c#'ta \ işareti özel bir karekter(‘escape character’ denir) olup takip eden başka karakterlere özel anlam katar. Örneğin \n satırbaşı anlamında, \t tab sekmesi anlamındadır. O yüzden gerçekten \ işaretini kullanmak istediğimizde önüne bir \ daha koyarak onun gerçek \ işareti olduğunu vurgularız. Ama bu çok zahmetli olabileceği için @ karakteri ile bu zahmetten kurtuluruz. Vb.Net'te ise buna gerek yoktur, VBA'de olduğu gibi normal bir şekilde \ kullanımı yapılabilir.

Şimdi bir de c# 4.0 öncesinde, optional parametrelerin desteklenmediği döneme bakalım; korkmayın, artık bu kabus bitti :)

MyStatik.app.Workbooks.Open(@"E:\OneDrive\Uygulama Geliştirme\web sitelerim\Yeni Efendi\Ornek_dosyalar\CF.xlsx",
    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
    Type.Missing, Type.Missing, Type.Missing, Type.Missing,
    Type.Missing, Type.Missing);

Worksheet

app nesnesini elde edikten sonra worksheet kullanımı da kolaydır.

Excel.Worksheet ws = MyStatik.app.Worksheets[1]; //index'e dikkat
MessageBox.Show(ws.Name); 

Ancak worksheets collection'ının dönüş tipi Sheets olup, Sheets'in de dönüş tipi VBA'den bildiğimiz üzere object olduğundan eğer bir değişkene atama yapmadıysak doğrudan kullanımda takip eden üyelerini hemen göstermez. Yani aşağıdaki gibi kullanırken [1] yazıp noktaya basınca intellisense çıkmaz, çünkü tipi henüz belli değil, worksheet mi charts mı bilinmiyor.

MessageBox.Show(MyStatik.app.Worksheets[1].Name); 

Bu aslında garip bir durum, zira her ne kadar Worksheets(Sheets değil) collection'ınını kullanmış olsak bile dönüş tipini Sheets yapmışlar. Gerçi bu, VSTO'ya özgü bir durum değil, VBA'de çalışırken de aynı durum sözkonusudur. Neyse bunun sebebine takılmayalım. Intellisense çıkmasını istiyorsanız bunu değişkene atamanızda fayda var. Ama diyelim ki bunu bi değişkene atamak istemiyorsunuz, zira bu nesneyi başka bir yerde kullanmayacaksınız, sadece bir kereliğine bir özelliğine erişeceksiniz, ama yine de intellisensin de çıkmasını istiyorsunuz. Bu da mümkün, ama bu örneği Range nesnesinde göreceğiz, oradaki ilgili açıklama worksheet'te (ve tüm diğer nesnelerde de) aynen geçerlidir.

Range

Workbook ve Worksheet biraz kolaydı. Range'de bazen casting yapmak durumunda kalacağız. Şimdi ilk olarak basit bir örnekle başlayalım.

Mesela aktif hücrenin adresini ve değerini öğrenmek istiyoruz. Bunun için yazacağımız kod aşağıdaki gibi olabilir.

Excel.Range hucre = MyStatik.app.ActiveCell;
double deger = hucre.Value2;
MessageBox.Show(hucre.Address + " adresindeki hucrenin değeri:" + deger.ToString());

Bu kodda çok kompleks birşey yok aslında. İlk satırda statik sınıfımızdaki app değişkeni üzerinden ActiveCell'e ulaşıyoruz, ikinci satır gayet açık. Son satırdaki MessageBox.Show yazabilmek için de tepede using System.Windows.Forms olması gerektiği aşikar.

Şimdi biraz daha şık bir kod nasıl yazılır, ona bakalım. Üstelik biraz daha teferruatlı konulara da girelim. Böylece hem biraz daha c# pratiği hem de VSTO pratiği yapmış olalım.

Öncelikle, bir hata bloğu koyacağız, ki bir hücre seçilmemişken uyarı versin, ayrıca seçilen hücre nümerik bişey içermediğinde de farklı bi uyarı versin, yani aslında iki hata bloğumuz olacak. Bir de, ölçeceğimiz değerin tipini integer yapalım istiyoruz.

Bu sefer farklı olarak Activecell yerine Selection nesnesini kullanacağız ve kodların nasıl değiştiğini göreceğiz.

try
{                
    Excel.Range hucre = MyStatik.app.Selection; //castinge gerek yok, çünkü zaten değişkenin tipini belirtiyoruz
    int deger = (int)(hucre.Value2); //double'dan integera dönüşüm
    MessageBox.Show(hucre.Address + " adresindeki hucrenin değeri:" + deger.ToString());
    //değişken atamasız durum
    MessageBox.Show(MyStatik.app.Selection.Value2.ToString()); //casting yapmadığımız için intellisense çıkmaz
    MessageBox.Show(((Excel.Range)MyStatik.app.Selection).Value2.ToString()); //intellisense çıkar
}
catch (NullReferenceException)
{
    MessageBox.Show("Seçili bir hücre yok, lütfen bir hücre seçip tekrar deneyin.");
}      
catch (Exception ex)
{
    if (ex.HResult==-2146233088)
    {
        MessageBox.Show("Şuan nümerik değeri olan bir hücrede bulunmuyorsunuz.");
        MessageBox.Show(String.Format("HRresult:{0},\n\nMesaj:{1}", ex.HResult.ToString(), ex.Message));
    }
    else
    {
        MessageBox.Show(String.Format("HRresult:{0},\n\nMesaj:{1}", ex.HResult.ToString(), ex.Message));
    }                
}

 Şimdi de burayı inceleyelim

  • Selection'ın dönüş tipi Range değildir(Peki object mi? Birazdan göreceğiz). Bunun için yapılabilecek 3 şey var. Aslında bu yazdıklarımı 2010'dan önce yazsaydım farklı bişeyler yazacaktım, şimdi yazdığımda ise durum farklı, bunun sebebi dillerin zaman değişiyor olması
    • İlk olarak herhangi bir farklılığın olmadığı case, burada hücre değişkeninin tipini zaten Excel.Range belirlediğim için ilave bir işleme gerek yok
    • Casting işlemi: (Excel.Range) ifadesini kullanarak casting yapıyoruz. Böylece compliera diyoruz ki  "MyStatik.app.Selection"'dan dönen şey bir objedir ama aslında bu bir Range nesnesidir, hadi bunu Range nesnesine dönüştür. Casting detayı için  için .Net dilleri sayfasına bakın, özellikle orada link verdiğim wordpress sayfasına da bakın. Bu arada bunun Vb.Net karşılığı CType(app.Selection, Excel.Range) olur. Biz bunu yaparak ilgili nesneyi Range'e döndürdüğümüz için range nesnesinin tüm üyelerine erişebiliriz.
    • Gelelim 2010 öncesi ve sonrası duruma: 2010'dan önce Cast etmeden kullanamıyorduk, ancak 2010'dan sonra castinge gerek olmadan da kullanabiliyoruz. Peki neden ve farkı ne? 2010'da c# 4.0 geldikten sonra, dynamic veri tipi diye birşey çıktı. Detayına girmeyeceğiz ancak, bu özellik object tipli bir nesnenin gerçek nesneye dönüştürülmeden de kullanılabilmesi imkanı verdi ve bunu da tipinin runtime sırasında compiler tarafından otomatikman belirlenmesiyle yapmaya başladı. İşte bu Selection nesnesinin dönüş tipi de artık dynamictir. 2010'dan önce object idi ve mutlaka cast edilmesi gerekiyordu. Özetle castinge gerek olmadan kullanabilirsiniz ama bunu tavsiye etmem, hem compilerı yormuş olursunuz, hem de intellisenseden faydalanamazsınız. Bununla birlikte dynamic veri tipinin çok faydalı olduğu yerler de vardır, bunları zaman içinde göreceğiz.
  • Gelelim ikinci satırdaki deger değişkenine. Bunu int tanımladık. Şimdi eğer ilk satırda elde ettiğimiz hucre değişkeni olmasaydı ikinci satırdaki kodu "int deger=((Excel.Range)MyStatik.app.Selection).Value2;" şeklinde yazardık. Kırmızı parantezler içinde yazan kısım zaten bizim hucre değişkeni içn yazdığımızın aynısı. Kırmızı parentez içine alarak bunu ayrı bir nesne haline getiriyoruz. İşte bundan sonra bunun üyelerine ulaşabiliyoruz. Bu kırmızı paranteze almayıp doğrudan Selection'dan sonra Value2 yazsaydık, c# derleyicisi bunu şöyle anlayacaktı: "MyStatik.app.ActiveCell.Selection.Value2.ToString() değerini Range'e dönüştür", ve hata verecekti.
  • 2. catch bloğunda String formatlama da kullandık, bunu kendiniz yorumlamaya çalışın. Bu arada else bloğuna gelecek bir örnek bulamadığım için if kısmına da yazdım, sonucunu görün diye.

Cells collectionı

Cells, collection olarak kullanıldığında dönüş tipi Range olup herhangi bir şekilde castinge gerek yoktur. Ancak parametreli kullanıldığında, yani satır ve sütun verilerek bir hücre elde edilmeye çalışıldığında bunun dönüş tipi dynamic(2010'dan önce object) dönüş tipli olduğu için intellisense çıkmaz, çıkması için (Excel.Range) ile cast edilmelidir, tabi eğer değişkene atama yapılmadan kullanılacaksa. Değişken ataması yapıldığında ise ayrı bir castinge bunda da gerek yoktur, zira zaten değişkenin tipini belirliyoruzdur.

MessageBox.Show(((Excel.Range)MyStatik.app.Cells[1, 1]).Value);

3rd Party Kütüphaneler

İlk projemize başlamadan daha fazla kod örneği ile sizi boğmak istemedim. Normalde konu bütünlüğü adına burada koymayı tercih ederdim ama sizi bir an önce ilk projenizle de buluşturmak istiyorum. Bu konuya hem VSTO ile hem c# ile haşır neşir olduktan sonra şurada gireceğiz.

Sonraki sayfada görüşmek üzere...

TEST SORULARI

Son Sorumuz şuymuş:Bir metindeki tüm noktaları yoketmek istiyorsunuz. Hangi fonksiyonu kullanırdınız?
Soru:

A şıkkı:

B şıkkı:

C şıkkı:

D şıkkı:

Doğru Cevap Etiketler

İlişkili konuyu seç

109164

Label
* Sorulara verilen yanlış cevaplardaki esprili yorumlarım için hoşgörünüze sığınıyorum.
* Test ve Ödevlerdeki bazı detaylar burada anlatılmamış olabilir. Bunları kendiniz araştırıp bulmalısınız.
* Birden çok konuya ait içeriği olan ödevler var. Algoritmik açıdan bakıldığında o an en uygun konuya adreslenmiştir.
Dikkat! Bir soruya cevap verdikten sonra geri dönemezsiniz.
0
0
0
0

SoruID:... Şu an için bu konu için soru bulunmamaktadır. İletişim menüsünden örnek sorularınızı bana iletebilirsiniz.




ÖDEVLER

0
0
ÖdevNo:... Şu an için bu konu için ödev bulunmamaktadır. İletişim menüsünden örnek ödev sorularını bana iletebilirsin.
Çözüme bakın(Başka türlü de çözülebilir tabi, bu benim çözümüm.)




=YORUMLAR ve SORULAR=


DEVİR UYARISI

Herkese merhaba. Hosting maliyetlerinin aşırı artması yüzünden sitemi yakın zamanda(en geç Mayıs 2023) kapatmaya karar vermiştim. Ancak, siteyi yakından takip eden bir arkadaş siteyi devralmak istemiştir. Siteyi, Mayıs ayında kendisine devir etmeye karar verdim. Üyelik bilgilerini bana güvenerek girdiğiniz için, hepsini silmiş bulunuyorum, yani mail adreslerinizi kimseyle paylaşmamış olacağım. Bilginizi rica ederim.