![](/img/trans.png)
[英]Excel VSTO - accessing AutoFilter's Array Criteria throws exceptions
[英]VSTO - Excel - AutoFilter - Trying to get Date filter criteria (year, month or day) throws exception
我正在嘗試獲取表的過濾器,以便在進行一些修改后重新應用它們。 一切正常,但是當過濾器位於“日期”列上時,麻煩就開始了。 這就是我的做法:
for (int i = 1; i <= filters.Count; i++)
{
FilterTemp f = new FilterTemp();
f.On = filters[i].On;
if (f.On)
{
f.Field = i;
try
{
f.Criteria1 = filters[i].Criteria1;
}
catch { }
f.Operator = (int)filters[i].Operator;
try
{
f.Criteria2 = filters[i].Criteria2;
}
catch { }
}
fs.Add(f);
}
當過濾器位於text或number列上時,一切正常,但是當按年,月或日過濾日期列時,嘗試獲取“ Criteria1”時在第5行出現異常。
我試圖將運算符更改為xlFilterDynamic,如對此MSDN帖子的答案所述: https ://social.msdn.microsoft.com/Forums/vstudio/en-US/15ec8d69-3e6f-450d-82c0-ca53e63c8f64/getting 論壇列表對象過濾器的數據?論壇= vsto
像這樣:
for (int i = 1; i <= filters.Count; i++)
{
FilterCache f = new FilterCache();
f.On = filters[i].On;
if (f.On)
{
f.Field = i;
try
{
f.Criteria1 = filters[i].Criteria1;
}
catch
{
filters[i].Operator = XlAutoFilterOperator.xlFilterDynamic;
f.Criteria1 = filters[i].Criteria1;
}
f.Operator = (int)filters[i].Operator;
if (f.Operator == 0)
f.Operator = (int)XlAutoFilterOperator.xlAnd;
try
{
f.Criteria2 = filters[i].Criteria2;
}
catch { }
}
fs.Add(f);
}
沒有成功 現在filter [i] .Criteria1永遠返回1,我在該日期列上使用的過濾器都沒有關系。
為了模擬此問題,有必要在Excel工作表上創建一個表,然后將一些隨機日期放在一列中。 然后,過濾此列,至少選擇3個不同的日期。 運行代碼。
在stackoverflow上已經有關於此的帖子: Excel VSTO-訪問AutoFilter的數組條件會引發異常
同樣在: https : //social.msdn.microsoft.com/Forums/office/en-US/281fdbc5-6535-497f-b427-f69f4b092e24/excel-vsto-accessing-autofilters-array-criteria-throws-exceptions
...但是沒有令人滿意的答案,或者可能很難理解這個問題。
FilterTemp類:
public class FilterTemp
{
public bool On;
public object Field;
public object Criteria1;
public int Operator;
public object Criteria2;
}
因此,這只是一個主意 。最終目標是將日期返回給客戶端,以便可以通過AutoFilter重新應用該日期,如下所示
string[] FilterList = new string[] { "10/31/2013", "5/4/2013" };
visibleCells.AutoFilter(1, FilterList.Length > 0 ? FilterList.ToArray() : Type.Missing, Excel.XlAutoFilterOperator.xlFilterValues, Type.Missing, true);
希望這會給您提示如何繼續。 我將有一天嘗試完成。 GitHub上所有帶有示例的代碼
using System;
using System.Collections.Generic;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using Excel = Microsoft.Office.Interop.Excel;
using System.IO;
namespace AutoFilterRetriever
{
/// <summary>
/// An example class how to get AutoFilter criteria from internal XML representation
/// </summary>
public class CriteriaFilterRetriever : IDisposable
{
private readonly Excel.Worksheet wks;
private readonly string filePath;
private Stream docStream;
private SpreadsheetDocument openXmlDoc;
private WorkbookPart wkb;
public CriteriaFilterRetriever(Excel.Worksheet sheet)
{
wks = sheet;
filePath = sheet.Application.ActiveWorkbook.FullName;
if (!filePath.Contains("\\"))
{
throw new FileLoadException("Save the file in order to get autofilter criteria");
}
}
/// <summary>
/// This can be changed to a complex object instead of just list of strings
/// </summary>
public List<string> FilterCriteria { get; private set; }
public void GetFilterCriteria()
{
if (!OpenFile()) throw new FileLoadException($"Couldn't open the file - {filePath}");
if (wks.AutoFilter == null) return;
// here we get sheet in the workbook.xml (Equals don't work here)
var sheetInWkb = wkb.Workbook.Descendants<Sheet>().Where(s => s.Name == wks.Name).FirstOrDefault();
// get a reference to the worksheet part. Imagine part as the folder in the zip structure
WorksheetPart wsPart = (WorksheetPart)(wkb.GetPartById(sheetInWkb.Id));
// finally get the xml file e.g. sheet1.xml
var sheet = wsPart.Worksheet;
// there should be just one autofilter per sheet
var filter = sheet.Descendants<AutoFilter>().First();
if (filter == null) throw new InvalidOperationException($"Couldn't get autofilter data from the {wks.Name} sheet.");
ManageFilterData(filter);
}
private void ManageFilterData(AutoFilter filter)
{
FilterCriteria = new List<string>();
// this is always the first element in AutoFilter
foreach (FilterColumn filterCol in filter)
{
// here we get the filters data
var filters = filterCol.FirstChild;
if (filters is Filters)
{
foreach (var item in filters)
{
if (item is DateGroupItem)
{
FilterCriteria.Add(GetDateFilterCriteria(item as DateGroupItem));
}
else if (item is Filter)
{
FilterCriteria.Add(((Filter)item).Val);
}
else
{
throw new Exception("Not sure what to do here");
}
}
}
else if (filters is CustomFilters)
{
// if custom filter is applied (more than one criteria it falls to this category
foreach (var item in filters)
{
if (item is CustomFilter)
{
var tmp = item as CustomFilter;
FilterCriteria.Add($"{tmp.Operator}, {tmp.Val}");
}
else
{
throw new Exception("Not sure what to do here");
}
}
}
}
}
private string GetDateFilterCriteria(DateGroupItem criteria)
{
if (criteria.DateTimeGrouping == DateTimeGroupingValues.Year)
{
return criteria.Year.ToString();
}
else if (criteria.DateTimeGrouping == DateTimeGroupingValues.Month)
{
return $"{criteria.Year.ToString()}-{criteria.Month.ToString()}";
}
else if (criteria.DateTimeGrouping == DateTimeGroupingValues.Day)
{
return $"{criteria.Year.ToString()}-{criteria.Month.ToString()}-{criteria.Day.ToString()}";
}
else if (criteria.DateTimeGrouping == DateTimeGroupingValues.Hour)
{
return $"{criteria.Year.ToString()}-{criteria.Month.ToString()}-{criteria.Day.ToString()} {criteria.Hour.ToString()}:00:00";
}
else if (criteria.DateTimeGrouping == DateTimeGroupingValues.Minute)
{
return $"{criteria.Year.ToString()}-{criteria.Month.ToString()}-{criteria.Day.ToString()} {criteria.Hour.ToString()}:{criteria.Minute.ToString()}:00";
}
else
{
return $"{criteria.Year.ToString()}-{criteria.Month.ToString()}-{criteria.Day.ToString()} " +
$"{criteria.Hour.ToString()}:{criteria.Minute.ToString()}:{criteria.Second.ToString()}";
}
}
/// <summary> Opens the given file via the DocumentFormat package </summary>
/// <returns></returns>
private bool OpenFile()
{
try
{
docStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
openXmlDoc = SpreadsheetDocument.Open(docStream, false);
wkb = openXmlDoc.WorkbookPart;
return true;
}
catch (Exception)
{
return false;
}
}
public void Dispose()
{
openXmlDoc?.Close();
docStream?.Close();
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.