2010-02-22 5 views
7

ile tek tek hücrelerin biçimi nasıl belirtilir Bir tabloyu bir excel çalışma sayfasına yazdığımda, tek tek hücrelere yazmak yerine tam aralıklarla çalışmayı biliyorum. Ancak, Excel'e vereceğim diziyi doldururken formatı belirtmenin bir yolu var mı?Excel.Range.set_Value()

İşte şimdi böyle yapar:

object MissingValue = System.Reflection.Missing.Value; 
Excel.Application excel = new Excel.Application(); 
int rows = 5; 
int cols = 5; 
int someVal; 

Excel.Worksheet sheet = (Excel.Worksheet)excel.Workbooks.Add(MissingValue).Sheets[1]; 
Excel.Range range = sheet.Range("A1", sheet.Cells(rows,cols)); 
object[,] rangeData = new object[rows,cols]; 
for(int r = 0; r < rows; r++) 
{ 
    for(int c = 0; c < cols; c++) 
    { 
     someVal = r + c; 
     rangeData[r,c] = someVal.ToString(); 
    } 
} 
range.set_Value(MissingValue, rangeData); 

Şimdi o sayıların bazı yüzdeleri olarak biçimlendirilmesi gerektiğini varsayalım. Hücre bazında geri dönebileceğimi ve formatı değiştirebileceğimi biliyorum, ancak tek bir Range.set_Value() çağrısı kullanmanın tüm amacını yenmek gibi görünüyor. Ben rangeData [,] yapısını formatlama bilgisi dahil edebilir miyim, böylece set_Value() dediğimde, hücreler istediğim şekilde biçimlendirilir mi?

Netleştirmek gerekirse, Excel.Range nesnesinin tümünün biçimini ayarlayabildiğimi biliyorum. İstediğim, iç döngüde belirtilen her hücre için farklı bir biçime sahip olmak.

cevap

2

Buraya kadar bulduğum en iyi "çözüm". Aradığım nirvanna değil, ama her bir hücrenin formatını ayrı ayrı ayarlamaktan çok daha hızlı.

// 0-based indexes 
static string RcToA1(int row, int col) 
{ 
    string toRet = ""; 
    int mag = 0; 
    while(col >= Math.Pow(26, mag+1)){mag++;} 
    while (mag>0) 
    { 
     toRet += System.Convert.ToChar(64 + (byte)Math.Truncate((double)(col/(Math.Pow(26,mag))))); 
     col -= (int)Math.Truncate((double)Math.Pow(26, mag--)); 
    } 
    toRet += System.Convert.ToChar(65 + col); 
    return toRet + (row + 1).ToString(); 
} 

static Random rand = new Random(DateTime.Now.Millisecond); 
static string RandomExcelFormat() 
{ 
    switch ((int)Math.Round(rand.NextDouble(),0)) 
    { 
     case 0: return "0.00%"; 
     default: return "0.00"; 
    } 
} 


struct ExcelFormatSpecifier 
{ 
    public object NumberFormat; 
    public string RangeAddress; 
} 

static void DoWork() 
{ 
    List<ExcelFormatSpecifier> NumberFormatList = new List<ExcelFormatSpecifier>(0); 

    object[,] rangeData = new object[rows,cols]; 
    for(int r = 0; r < rows; r++) 
    { 
     for(int c = 0; c < cols; c++) 
     { 
      someVal = r + c; 
      rangeData[r,c] = someVal.ToString(); 
      NumberFormatList.Add(new ExcelFormatSpecifier 
       { 
        NumberFormat = RandomExcelFormat(), 
        RangeAddress = RcToA1(rowIndex, colIndex) 
       }); 
     } 
    } 
    range.set_Value(MissingValue, rangeData); 

    int max_format = 50; 
    foreach (string formatSpecifier in NumberFormatList.Select(p => p.NumberFormat).Distinct()) 
    { 
     List<string> addresses = NumberFormatList.Where(p => p.NumberFormat == formatSpecifier).Select(p => p.RangeAddress).ToList(); 
     while (addresses.Count > 0) 
     { 
      string addressSpecifier = string.Join(",",  addresses.Take(max_format).ToArray()); 
      range.get_Range(addressSpecifier, MissingValue).NumberFormat = formatSpecifier; 
      addresses = addresses.Skip(max_format).ToList(); 
     } 
    } 
} 

Temelde ne oluyor ben (her eleman ayrıca uygulanır aralığın A1-stili adresini tutan) NumberFormatList her hücre için biçim bilgilerin bir listesini tutmak olmasıdır. Özgün fikir, çalışma sayfasındaki her bir farklı format için, sadece bu hücrelerden oluşan bir Excel.Range yapabilmem ve bu aralığı tek bir çağrıda bu formata uygulayabilmem gerektiğiydi. Bu, NumberFormat'a olan erişim sayısını (potansiyel olarak) binlerce kişiden sadece birkaçına indirir (ancak sahip olduğunuz birçok farklı biçim).

Bir soruna rastladım, çünkü görünüşte, uzun bir hücre listesinden bir aralık oluşturamıyorsunuz. Bazı testlerden sonra, sınırın keyfi bir aralığı tanımlamak için kullanılabilen 50 ve 100 hücre arasında bir yer olduğunu buldum (range.get_Range ("A1, B1, C1, A2, AA5, .....") Bu nedenle, bir biçimi uygulamak için tüm hücrelerin listesini aldığımda, bir defada bu hücrelerin 50'sine biçimi uygulayan bir final while() döngüsü var.

Bu ideal değil, ancak NumberFormat'a erişim sayısını 50'ye kadar olan bir katma kadar azaltıyor. E-tabloyu herhangi bir format bilgisi olmadan (sadece range.set_Value() kullanarak) oluşturmak yaklaşık 3 saniye sürüyor. Bir süre, yaklaşık 10 saniyeye uzatılmış bir biçimdir. Biçim bilgisini her bir hücreye tek tek uygularken, elektronik sayfanın oluşturulmasını bitirmek için 2 dakikanızı alır.

+0

Kendi cevabımı kabul etmeme rağmen, karar verdiğim dosya yazmak için Excel otomasyonunun kullanılması kötü bir plan. İleriye doğru yazmak için ExcelPackage kütüphanesini kullanıyorum.xlsx dosyaları –

+0

+ güzel bir kod parçası olduğu için;) Bir hücre dizisini ayarlamak için formatSpecifier kullanabileceğinizi bilmiyordum. –

2

Sen poligonunda biçimlendirmeyi uygulamak ve sonra object[,] dizide sende biçimlendirme belirleyemezsiniz değerlerle doldurabilirsiniz

0

Sen

for(int r = 0; r < rows; r++) 
{ 
    for(int c = 0; c < cols; c++) 
    { 
     Excel.Range r2 = sheet.Cells(r, c); 
     r2.xxxx = ""; 
    } 
} 
yoluyla iç döngü içinde her hücreye biçimlendirmeyi uygulamak

r2'a sahip olduğunuzda, hücre formatını istediğiniz gibi değiştirebilirsiniz.

+0

İş bitti, ama Excel Interop içine çağrıların sayısını mutlak bir minimum tutmaya çalışıyorum. İç döngüde biçimlendirme uygulamak işe yarayacak, ama köpek yavaş olacaktır. –