Ribbon

Öncelikle şunu söylemekte faydar var. VS, VSTO kodlaması adına birçok işi bizim yerimize yapmış olacak. Bizim bilmemiz gereken 3 temel şey var

  • Excel object model'e nasıl erişilir
  • .Net kodu nasıl yazılır
  • Ribbon yönetimi nasıl yapılır

Excel Object Modelle uğraşmayı bi önceki sayfada gördük.
.Net çok büyük bir dünya. Aynı anda hem VS'yu kullanmayı öğrenmeniz hem de c#(veya Vb.Net) kullanmayı öğrenmeniz gerekecek. Bu uzun bir yolculuk olacak. Ben başlangıç için gerekli olan kısmı bu sitede vereceğim, kendinizi daha ileri götürmek size kalmış.
Geriye bence en önemli kısım, çalışmanızın vitrini olan Ribbon yönetimi kalıyor. İşte bu sayfada bu konuya detaylarıyla(başka hiçbir kaynakta olmayan detaylarıyla) bakacağız.

Ribbon yaratımını ilk vsto addin sayfasında görmüştük. Kaldığımız yerden devam edelim. Yalnız devam etmeden önce küçük bir bilgilendirme yapmak isterim. Biz, ribbonumuzu Visual Designer modunda oluşturmuştuk ve bu yöntemin XML yöntemine göre daha basit bir fonksiyonalite sunduğundan bahsetmiştik. MSDN'de, üstatlardan Cindy Meister'ın verdiği cevapta detayları görebilirsiniz.

Sekmelerin konumu

Hatırlayacak olursak Ribbonumuz Add-in menüsüne yerleşmişti.

post-thumb

Halbuki ribbonun yerleşimi için daha şık olan iki seçenek daha var:

  • Bağımsız bir sekme. Ör:Excel menülerinden bambaşka bir fonksiyonaliteye sahipse, veya ticari amacı olan bir çalışma ise.
  • Mevcut sekmelerden birinin içine. Ör:Add-indeki kodlarımızı temsil eden ribbonumuz veri ağırlıklı bir çalışma ise Data menüsüne yerleştirebiliriz.

Şimdi VS ekranındaki halini tekrar bi hatırlayalım.

post-thumb

Gördüğünüz üzere ilk yaratımda TabAddIns(Built-In) şeklinde isimlendirildi. Bunu şöyle okumak lazım. Excel'in built -in tablarından(sekmelerinden) Add-in's sekmesi içinde görünecek. Şimdi toolboxtan yeni bir Tab elemanını ribbona sürüklersek bunda parantez içinde built-in yazmadığnı görürüz. Bu, yeni sekme ayrı bir sekme şeklinde görünecek demektir. Bakalım gerçekten öyle mi, projemizi çalıştıralım ve bakalım:

post-thumb

Bu şekilde, tab2 için yukarıdaki iki seçenekten ilkini uyarlamış olduk, yani bağımsız bir sekme yaptık. Şimdi diyelim ki biz bu sekmeyi Data menüsü içinde görmek istiyoruz. Bunun için ilgili sekmeyi seçtikten sonra Properties menüsünden ControlIdType değerini “Custom”dan “Office”e dönüştürelim.

tab2'nin ilk hali böyle iken,

post-thumb

Şimdi şöyle olur, bu arada OfficeId seçeneğine de hangi built-in menüde görüneckese onu yazarız; data için TabData.

post-thumb

Sonuçta designerda sekmelerimiz aşağıdaki gibi görünür.

post-thumb

Şimdi bunun içine bir Group kontrolü koyup, içine de bir iki buton koyalım ve çalıştırıp Excel'de nasıl göründüğne bakalım.

post-thumb

Gördüğünüz gibi, her ne kadar bu sekmenin adı tab2 idiyse de, tab2 ifadesini herhangi bir yerde görmüyorsunuz, zira bu sekmemiz Data sekmesi içine yedirilmiş oldu.

Built-in menüleri gizleme

Excel'in built-in menüleri görünmesin, sadece kendi yazdığımız ribbon sekmesi görünsün istiyosak, Ribbon nesnesinin StartFromScratch seçeneği True yapılır.

post-thumb

File menüsü

Çok ihtiyacınız olur mu bilemedim ancak istenirse File menüsüne bile bir buton ekleyebiliyorsunuz. Mesela aşağıdaki gibi genel ribbon ayarlarınızı içeren formu açan bir düğme koyabilirsiniz. Gerçi ben bunu ana sekmemin en sonuna koymayı tercih ederdim. Tercih sizin.

post-thumb

Ribbon Controlleri

Kapsayıcılar(Container elementler)

Ana kapsayıcımız Group controlüydü, bunu yukarıda gördük, tüm controlleri bunların içine koymak durumundayız. Bunun dışında bir de alt kapsayıcılar var, bunlar Group nesnesi içindeki contolleri gruplamaya yararlar. Özellikle mantıksal(logical) bir gruplama amacıyla kullanılırlar.

İki tür kapsayıcı kontrol var. Biri Buttongroup, diğeri Box. Buttongroup sadece button benzeri controlleri(button, toggle buton, split button) ve içine buton konulan popup menüleri(menü ve gallery) alır ve bunları dizerken, Box controlü ise her tür controlü içine alır ve hem yatay hem dikey hizalayabilir. Aşağıdakilerden kırmızı olan Buttongroup, mavi olanlar Box controlüdür. Box'ın BoxStyle propertysi ile yatay/dikey ayrımı belirlenir. Bu arada her ne kadar design görünümünde etraflarında bi border çizigisi varmış gibi görünse de derlendiğinde bu çizgiler görünmez, o yüzden bi alttaki separatorleri kullanmak gerekebilir.

post-thumb

Box nesnesinin Items adlı bir collectionı vardır. Bu demektir ki, içindeki controlleri döngüyle dolaşabilirsiniz. İhtiyacınız olur diye söylüyorum.

Seperator

Anlamı açık diye tahmin ediyorum. Kontroller arasına ayraç koyar. Böylece aynı group içindeki kontrollerin birbirine çok yaklaşması engellenmiş olur. Yalnız, bazen design görünümünde taşma v.s görünse bile proje derlendiğinde normal görünüm alabiliyor. O yüzden nihai görünümü, çalıştırmadan bilemezsiniz diyebiliriz.

post-thumb

Toggle button

VBA'den biliyorsunuz.

Label ve EditBox

Label'ı açıklamaya gerek yok, VBA'den biliyorsunuz. EditBox da bildiğimiz TextBox aslında. VBA'de add-in'ler ve menüler konusunda da bahsetmiştim, bir textboxın(editboxın) ribbonda/menüde olması çok pratik bi uygulama değil bence. O yüzden şimdilik es geçiyorum.

Checkbox

Checkbox da VBA'deki gibi, açıklamaya pek gerek yok, gerçi pratikte bir kullanımı olur mu ondan da emin değilim. Bu arada checkbox'lara benzeyen radiobutton'lar Ribbonlarda kullanılamıyor.

Pop-up menüler

Menü

Menülere VBA'den aşinayız ama yine de nasıl kullanılacağını bi görelim.

Bunun için burdan itibaren ilk tab'ımızı kullanmaya başlayalım. Buna yeni bir grup ekleyelim ve adına Dosyalar diyelim. Buraya sık kullandığımız bazı dosyaları koyacağız. Normalde zaten  Windows'un böyle bir özelliği var, mesela Excele sağ tıkladığınızda sık kulalndıklarınızı üst tarafa pinleyebiliyorsunuz ama biz böyle bir özellik olmadığını varsayalım ve sık kullanılan dosyalara ait bir menü yapalım. Bu arada buraya farklı dosya tiplerini de ekleyebilirsiniz(word, pdf, ppt v.s). Hatta ileride göreceğimiz gibi bunlar başka programları çalıştıran butonlar da olabilir.

post-thumb

Bunların click eventine de ilgili dosyaları açan kodu yazarız.


private void button13_Click(object sender, RibbonControlEventArgs e)
{
    string adres = @"E:\OneDrive\Dökümanlar\bütçem.xlsx";
    MyStatik.app.Workbooks.Open(adres);
}             

Menü içine farklı resim-yazı kombinasyonunda butonlar ve başka menüler de konabilir.

post-thumb

Burada karşımızda birkaç problem durabilir

  • 10 tane dosya varsa, 10'u için de ayrı ayrı mı click eventi gireceğiz.(Hayır tabiki, detaylar için Excelent proje incelemesinde)
  • Dosyaların bazısı Excel dosyası değilse?(Teoriği .Net işlemlerinde, pratiği Excelent projesinde)
  • Biz şuan sabit bir dosya listesi girdik, ya Kullanıcılar bunları kendi isteği gibi özelleştirmek isterse? (Aşağıda dialog launcher bölümünde settings işlemlerini yapmayı göreceğiz, açıklamalı örneği ise yine Excelent Projesinde göreceğiz)

ItemSize özelliği ile menünün içindeki elemanların boyutunun küçük mü büyük mü olacağı belirlenir. Diğer özellikleri aşağıdaki ortak özellikler içinde göreceğiz.

NOT: Bu arada butonlara atadığınız resimler/iconlar design modda görünmez. Bunların nasıl göründüğünü test etmek için projeyi çalıştırmanız gerekiyor. Ayrıca bazen buton orada olduğu halde yokmuş gibi de görünebiliyor. Bu tür durumlarda Ribbon'u kapatıp açın veya komple projeyi kapatıp açın.

Gallery

Menülere göre daha şık bir gruplama sağlarlar. Aşağıda Excel'in kendi menülerinden birinde Gallery kullanımı görüyoruz.

post-thumb

Gallery içine buton sürüklemek yerine, properties'ten Items collection'ına elemanlar ekliyoruz. Sonra da bunların resimleri için değer gireceğiz. Bunları az aşağıda ortak özellikler bölümünde göreceğiz. Biz şimdi resim eklemeden kodumuzu yazalım. Burada farklı butonlar olmadığı için aslında tek bir event var, o da gallerynin tıklanma eventi.

Yapacağımız şey, seçilen elemanını indeksine bakmak olacaktır.

private void gallery1_Click(object sender, RibbonControlEventArgs e)
{
    switch (this.gallery1.SelectedItemIndex)
    {
        case 0:
            MessageBox.Show("ilk item seçildi");
            break;
        case 1:
            MessageBox.Show("ikinci item sçeildi");
            break;
        default:
            MessageBox.Show("Buraya gelmemeli");
            break;
    }
}

Burada ayrıca switch-case yapısını da görmüş olduk. VBA'deki seleckt case yapısının aynısıdır. Kullanımındaki küçük ayrımı keşfetmeyi size bırakıyorum.

ItemImageSize özelliği ile itemların ebatları rakam verilerek belirtilir. Menülerde ise küçük/büyük seçenekleri vardı.

ComboBox ve DropDown

ComboBox'ların ne olduğunu biliyoruz. Dropdown'lar bunlara çok benzer; tek farkı, Dropdownlara tıkladığımızda metnin içini seç(e)meyiz, Combolarda ise metni seçmiş oluruz ve gerekirse elle bişeyler yazabiliriz. Ben dropdownları seviyorum, neresine tıklarsam tıklayayım seçenekler geliyor, comboda ise metinli bölgeye tıklarsanız oraya girmiş oluyorsunuz, seçimlerin açılması için illa yandaki oka tıklamak gerekiyor.

post-thumb

Bu anlamda dropdownlar gallery'lere benziyor. Aradaki fark, dropdowndakiler hep altalta bir liste şeklinde açılırken galeryde ise bi grid(ızgara) şeklinde yerleşim sözkonusu.

Splitbutton

ButtonType=Button atanırsa aşağıdakilerden ilki gibi, Toggle seçilirse ortadaki gibi görünür. Diğer popuplardan farkı şu: Diğerlerinde seçeneklerden birini seçmek için açılır kutuya basmamız gerekir, bunda ise görünen metnin kendisi de bir seçenektir, görünür metin default seçenek olup buraya genelde en olası seçenek yazılır, böylece hiç açılır kısmı açmadan doğrudan seçim yapılabilir. Diğer seçenekler için açılır kutuyu açmak gerekir. Dolayısıyla splitbuttonun ve içindeki butonların eventleri birbirinden ayrıdır(split ifadesi bundan dolayıdır).

 

post-thumb

Bu arada Excel'in built-in menülerinden örnek vermek gerekirse, Home menüsündeki Paste butonu bi Splitbuttondur. Doğrunda Paste'e tıkladığınızda bir seçimi olduğu gibi yapıştırır, altındaki açılır kutuya tıklayıp başka bir seçim de yapabilirsiniz.

Resource Ekleme

Gerek ribbondaki controllere, gerek formlarımızda kullanacağımız resimleri projenin içine dahil etmek istiyorsak aşağıdaki adımları ekleyerek ilerelyebilriz.

post-thumb

Buraya icon dosyaları(ico), ses ve video dosyaları da ekleyebiliyorsunuz.

Sonrasında, eklediğimiz dosyaları herhangi bir kontrolün Image properties'ine kolaylıkla ekleyebiliyoruz.

post-thumb

Hatta bu imajlara daha sonra runtime sırasında aşağıdaki gibi de ulaşabiliyoruz.

post-thumb

Bu arada ico uzantılı dosyaları Image porperty'sine atamak için aşağıdaki gibi bir kod yazmak gerekiyor. Resource'dan ico dosyasını(_0.ico) seçiyoruz, sonra onu Bitmap'e çeviriyoruz. Ben bunu Ribbon_Load eventine yazdım, böylece ribbon yüklenir yüklenmez imaj ataması yapılmış oluyor.


button20.Image = Properties.Resources._0.ToBitmap(); 

Vb.Net'te bu kısım biraz farklı yazılıyor.


button20.Image = My.Resources._0.ToBitmap()

Ortak Properties

Burda birçok nesnenin ortak property'sine bakacağız.

ControlSize

İlgili controlün küçük mü yoksa büyük mü görüneceğini belirler. Hali hazırda Excel'de iki türü de görüyorsunuz. Mesela Home menüsündeki Paste butonu Large bir controldür. Hemen yanındaki Cut ise Regular(küçük) bir controldür. Yalnız dikkat, bir control ButtonGroup veya bir Pop-up menü içindeyken bu özellik görünmez(erişilebilir değildir) ve mecburen küçük(regular) olur. Bu boyutu, ilgili kontrol için seçilen resmin pixelinden bağımsız olarak ekranda kapladığı alan olarak düşünün. Bu yüzden küçük ölçülerde boyutlanmış bir resim Large bir controlün Image property'sine atandığında pixel pixel(tabiri caizse Minecraft karakterleri gibi) görünürken, büyük boyutlu bir resim ise küçük(regular) bir controle atandığında buruşuk(pixellerin üstüste binmesinden dolayı) görünecektir.

Image, OfficeImageId, ShowImage, ShowLabel

Bu 4 özellik birbiriyle bağıntılı olduğu için bir arada aldım.

Bir control için görsel bir etiket istiyorsak, bunun için Image özelliği için bir resim seçip atarız veya OfficeImageId özelliğine bir değer atarız. OfficeImageId değerlerini internette bulabilirsiniz. Gerçi Microsoft'un kendi sitesindeki link hata veriyor, belki ileride düzeltirler diye ben yine de bu linki buraya koyuyorum. Alternatif siteler ise şöyle:

Bir şekilde hem Image hem OfficeImageId belirlediyseniz Image baz alınır.

ShowLabel: Controlün etiketi görünecek mi görünmeyecek mi, bunu belirler.  ControlSize, Large set edilmişken False atanamıyor.

ShowImage:Control'e atanmış resmin gösterilp gösterilmeyeceği belirlenir. ControlSize'da olduğu gibi, bir control bir buttongroup veya menü içindeyken bu özellik erişlebilir durumda değildir.

Pop-up menülerin bir de ShowItemLabel ve ShowItemImage özellikleri var ki, bunlar içindeki elemanlar için geçerlidir.

Image değeri verilmişken ShowImage=False denirse resim görünmez. OfficeImageID vermişseniz ShowImage=False yapamazsınız. Bunlarla oynayıp denemeniz gerek. Çeşitli kombinasyonlar çıkabiliyor, resimli-yazısız, resimli-yazılı, resimsiz-yazılı, küçük resimli, büyük resimli v.s

Aşağıda benim çeşitli denemelerimi görebilrisiniz.

post-thumb

Screentip ve Supertip

Sırayla, bir controlün üstüne gelindiğindeki başlık ve detay bilgileri verdiğiniz propertylerdir.

post-thumb

Gallery itemlarında bunlar her item için ayrı ayrı ayarlanabiliyor.

Bu arada bu screentip içine resim de eklenebiliyor ancak bunu yapmak için ribbonu Visual Designer ile değil Xml olarak yaratmamız lazımdı. Aradaki fark için en başta yazdığım açıklamaya tekrar bakın.

Dialog Launcher ekleme

Aşağıdaki Home menüsünün köşesindeki gibi küçük butonlara Dialog Launcher deniliyor. Bunlara tıklandığında ya bir dialog kutusu çıkar veya bir Taskpane, ve bunlarda çeşitli ayarlar yapılır. Bu ayarların bir kısmı tek seferliktir, bir kısmı ise File>Options'taki gibi kalıcı ayarlardır. Şimdi bunlar nasıl yaplır, ona bakaczğız.

post-thumb

Ribbonumuzda tab2 sekmemizinde ilk group nesnesini(group2) seçtikten sonra properties'ten aşağıdaki gibi Add DialogLauncher diyelim.

post-thumb

Buna tıklayınca group nesnesinin köşesine bu butoncuk eklenir. Şimdi sıra, buna tıklandığında ne yapılacağını belirlemeye geldi. Aşağıdaki gibi yıldırım butonuna tıklayarak açılan eventler kısmı boşken, çift tıklayınca otomatik bir event handler yaratılır ve kod sayfasında bunu size gösterir.

post-thumb

Nasıl göründüğüne bakalım:

post-thumb

Şimdi frmSettings1 adında bir form oluşturalım ve dialog eventimize aşağıdaki kodu yazalım


private void group2_DialogLauncherClick(object sender, RibbonControlEventArgs e)
{
    frmSetting1 f = new frmSetting1();
    f.Show();
}   

Settings formları olşuturma

Dialog Launcher'da açtığımız settings formunu düzenleyeceğiz.

Solution Explorer'da Properties'e çift tıklayalım.(VB.Net'te MyProject) ve açılan pencerede Settings'e gelelim. Şimdi iki ayar gireceğiz. Bunlardan biri bazı makrolar için kullancıdan kullanıcıya değişebilecek klasor adresi girmek, bir diğeri de yeni bir dosya açıldığında kaç sayfa açılacak, bunu kullanıcının belirlemesine izin vermek, bunu taibiki Files>Options'tan da yapabiliyoruz ancak maksat pratik olsun. Bu arada VBA'de iken bu tür ayarları txt dosyalarına yazıp okuyarak hallediyorduk, VSTO'da ise bu şekilde hem daha pratik hallediyoruz hem de şifre tarzı bilgileri de güvenlik altına almış oluyoruz.

Şimdi aşağıdaki iki ayarı girelim.(İlki için siz de uygun klasörü girin)

post-thumb

Şimdi Settings formumuz açılıdığnda ayarlarda kayıtlı ne varsa onu form içindeki textboxlarda gösterelim. Bunun için formda iki kutu yaratalım.

post-thumb

Bu formun Load eventine aşağıdaki kodu yazarak ayarları alıyoruz.


private void frmSetting1_Load(object sender, EventArgs e)
{
    this.txtKlasor.Text = Properties.Settings.Default.Anaklasor;
    this.txtSheetAded.Text = Properties.Settings.Default.YeniWbSheetAdedi.ToString();
}  

Kullanıcı ayarları değiştirip kaydetmek isteyecektir. Bunun için bir kaydet butonu yaratmak yerine tüm MS Office uygulamlarının da yaptığı gibi, form kapandığında otomatik kayıt yapma mantığıyla hareket edelim. O yüzden formun eventlerine gidip FormClasing'e çift tıklayarak ilgili event handlerı oluşturuyoruz ve aşağıdaki kodu yazıyoruz.


private void frmSetting1_FormClosing(object sender, FormClosingEventArgs e)
{
    Properties.Settings.Default.Anaklasor = this.txtKlasor.Text;
    Properties.Settings.Default.YeniWbSheetAdedi = int.Parse(this.txtSheetAded.Text); //parsing, string bir ifadeden sayısal metin çıkarma işlemidir
    Properties.Settings.Default.Save(); //bunu yazmazsak ayarlar kaydolmaz
}

Kodumuzu çalıştıralım, dialog launcherı çalıştıralım, çıkan pencerede değerleri değiştirip, tekrar açtığımızda değişmiş olduğunu görüyüoruz.

post-thumb

Settings kontrollerini özelleştirme

Bu arada bazı kutuların ise ayarlara kaydolmasını istemez ama kullanıcının yine de ilgili oturum içinde bunların içeriğini değiştirebilmesine izin vermek istersiniz. Kalıcı olmayan bu bilgilerle kalıcı yaptığınız ayarlı olanların birbirinden farklılaşması için ayarlı textboxların kırmızı fontlu olmasını sağlayabilirsiniz. Bunun için her ayarlı kutu için tek tek uğraşmak yerine TextBox sınıfından türetilmiş RenkliTextBox sınıfını yaratabiliriz. Bu kavrama Inheritance(Kalıtım) denir. Çok fazla örneğini görmeyeceğiz ancak özetle mantığı şu: Bir sınıfı baz alarak başka bir sınıf tanımlıyoruz. Böylece o sınıfın bütün özellikleri yeni sınıfımızda hazır olarak bulunuyor, biz sadece değiştirmek istediğimiz kısımları değiştiriyoruz veya eklemeler yapıyoruz. Hadi gelin şimdi de ona bakalım.

Projemize Add>New item diyerek UserControl ekliyoruz, adına RenkliTextBox diyelim. Açılan pencerede controlün içine bir tane textbox sürükleyelim. Sonraki kod sayfasına geçip constrcutor metod içindeki InitializeComponent satırını altına renklendirme kodumuzu yazalım.


public RenkliTextBox() //constructor metod
{
    InitializeComponent();
    this.textBox1.ForeColor = Color.Red;
}            

Projeyi Rebuild edelim ve controlümüzün Toolboxa geldiğini görelim.(Rebuild= Clean + Build. Bazı işlemler için Rebuild gereklidir, yeni eklenen controllerin toolboxa eklenmesi de onlardan biri)

post-thumb

Bakalım istediğimiz gibi çalışıyor mu?

post-thumb

 

Sekmeler arası geçişler

Çalışmanızda birden fazla sekme yaratmış olabilirsiniz. Böyle bir durumda hepsini tek seferde göstermek yerine, ilk açılışta ana sekmeyi açıp, butonlar aracılığı ile de diğer sekmeleri açıp kapatabilirsiniz.

Mesela ana sekmemiz olan tab1'e koyacağımız bir toggle_buton'a aşağıdaki gibi kod yazabiliriz. Bunun için bir sekme daha yaratmanız gerekiyor, yani tab3. Butona tıklıyken tab3 görünecek ve aktif olacak, butona tıklı değilken tab3 gizlenecek.


private void toggleButton1_Click(object sender, RibbonControlEventArgs e)
{
    Globals.Ribbons.Ribbon1.tab3.Visible = toggleButton1.Checked; //ribbonu görünür kılıyoruz
    if (toggleButton1.Checked)
    {
        Globals.Ribbons.Ribbon1.RibbonUI.ActivateTab("tab3");//sonra da aktif hale getiriyoruz            
    }            
}        

Ribbonu kaldırma

Bir üstte, Ribbon sekmelerini nasıl gösterip gizlediğimizi gördük. Ancak bazen komple Ribbonu kaldırmak isteyebiliriz. Mesela belli bir tarihe geldiğinizde Add-in'in kullanıcılardan kalkmasını isteyebilirsiniz. Bunun için Trial Version'u olan bir proje yapmak da çözümdür ancak bunun daha karmaşık olduğu aşikardır, onun yerine Ribbon'u kaldırarak kullanıcının arayüze dolayıyısla add-ine erişimini engellemiş olursunuz. Aşağıdaki kodu Ribbon_Load veya ThisAddIn_Startup içine yazabilirsiniz.


if (DateTime.Today>Convert.ToDateTime("31.12.2019"))
{
    MessageBox.Show("Add'in in süresi dolmuştur.");
    Globals.Ribbons.Ribbon1.Dispose();
}