瀏覽代碼

mxg:添加获取合并单元格的值

mengxiangge 6 年之前
父節點
當前提交
b54f13292d

+ 313 - 0
MBI/SAGA.DotNetUtils/NPOI/ExcelExtension.cs

@@ -0,0 +1,313 @@
+/* ==============================================================================
+ * 功能描述:ExcelExtension  
+ * 创 建 者:Garrett
+ * 创建日期:2019/1/14 10:16:40
+ * ==============================================================================*/
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using NPOI.SS.UserModel;
+using NPOI.SS.Util;
+
+namespace SAGA.DotNetUtils.NPOI
+{
+    /// <summary>
+    /// 表示单元格的维度,通常用于表达合并单元格的维度
+    /// </summary>
+    public struct Dimension
+    {
+        /// <summary>
+        /// 含有数据的单元格(通常表示合并单元格的第一个跨度行第一个跨度列),该字段可能为null
+        /// </summary>
+        public ICell DataCell;
+
+        /// <summary>
+        /// 行跨度(跨越了多少行)
+        /// </summary>
+        public int RowSpan;
+
+        /// <summary>
+        /// 列跨度(跨越了多少列)
+        /// </summary>
+        public int ColumnSpan;
+
+        /// <summary>
+        /// 合并单元格的起始行索引
+        /// </summary>
+        public int FirstRowIndex;
+
+        /// <summary>
+        /// 合并单元格的结束行索引
+        /// </summary>
+        public int LastRowIndex;
+
+        /// <summary>
+        /// 合并单元格的起始列索引
+        /// </summary>
+        public int FirstColumnIndex;
+
+        /// <summary>
+        /// 合并单元格的结束列索引
+        /// </summary>
+        public int LastColumnIndex;
+    }
+
+    public static class ExcelExtension
+    {
+        /// <summary>
+        /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的维度
+        /// </summary>
+        /// <param name="sheet">Excel工作表</param>
+        /// <param name="rowIndex">行索引,从0开始</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <param name="dimension">单元格维度</param>
+        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
+        public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out Dimension dimension)
+        {
+            dimension = new Dimension
+            {
+                DataCell = null,
+                RowSpan = 1,
+                ColumnSpan = 1,
+                FirstRowIndex = rowIndex,
+                LastRowIndex = rowIndex,
+                FirstColumnIndex = columnIndex,
+                LastColumnIndex = columnIndex
+            };
+
+            for (int i = 0; i < sheet.NumMergedRegions; i++)
+            {
+                CellRangeAddress range = sheet.GetMergedRegion(i);
+                sheet.IsMergedRegion(range);
+
+                //这种算法只有当指定行列索引刚好是合并单元格的第一个跨度行第一个跨度列时才能取得合并单元格的跨度
+                //if (range.FirstRow == rowIndex && range.FirstColumn == columnIndex)
+                //{
+                //    dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn);
+                //    dimension.RowSpan = range.LastRow - range.FirstRow + 1;
+                //    dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1;
+                //    dimension.FirstRowIndex = range.FirstRow;
+                //    dimension.LastRowIndex = range.LastRow;
+                //    dimension.FirstColumnIndex = range.FirstColumn;
+                //    dimension.LastColumnIndex = range.LastColumn;
+                //    break;
+                //}
+
+                if ((rowIndex >= range.FirstRow && range.LastRow >= rowIndex) && (columnIndex >= range.FirstColumn && range.LastColumn >= columnIndex))
+                {
+                    dimension.DataCell = sheet.GetRow(range.FirstRow).GetCell(range.FirstColumn);
+                    dimension.RowSpan = range.LastRow - range.FirstRow + 1;
+                    dimension.ColumnSpan = range.LastColumn - range.FirstColumn + 1;
+                    dimension.FirstRowIndex = range.FirstRow;
+                    dimension.LastRowIndex = range.LastRow;
+                    dimension.FirstColumnIndex = range.FirstColumn;
+                    dimension.LastColumnIndex = range.LastColumn;
+                    break;
+                }
+            }
+
+            bool result;
+            if (rowIndex >= 0 && sheet.LastRowNum > rowIndex)
+            {
+                IRow row = sheet.GetRow(rowIndex);
+                if (columnIndex >= 0 && row.LastCellNum > columnIndex)
+                {
+                    ICell cell = row.GetCell(columnIndex);
+                    result = cell.IsMergedCell;
+
+                    if (dimension.DataCell == null)
+                    {
+                        dimension.DataCell = cell;
+                    }
+                }
+                else
+                {
+                    result = false;
+                }
+            }
+            else
+            {
+                result = false;
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// 判断指定行列所在的单元格是否为合并单元格,并且输出该单元格的行列跨度
+        /// </summary>
+        /// <param name="sheet">Excel工作表</param>
+        /// <param name="rowIndex">行索引,从0开始</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param>
+        /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param>
+        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
+        public static bool IsMergeCell(this ISheet sheet, int rowIndex, int columnIndex, out int rowSpan, out int columnSpan)
+        {
+            Dimension dimension;
+            bool result = sheet.IsMergeCell(rowIndex, columnIndex, out dimension);
+
+            rowSpan = dimension.RowSpan;
+            columnSpan = dimension.ColumnSpan;
+
+            return result;
+        }
+
+        /// <summary>
+        /// 判断指定单元格是否为合并单元格,并且输出该单元格的维度
+        /// </summary>
+        /// <param name="cell">单元格</param>
+        /// <param name="dimension">单元格维度</param>
+        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
+        public static bool IsMergeCell(this ICell cell, out Dimension dimension)
+        {
+            return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out dimension);
+        }
+
+        /// <summary>
+        /// 判断指定单元格是否为合并单元格,并且输出该单元格的行列跨度
+        /// </summary>
+        /// <param name="cell">单元格</param>
+        /// <param name="rowSpan">行跨度,返回值最小为1,同时表示没有行合并</param>
+        /// <param name="columnSpan">列跨度,返回值最小为1,同时表示没有列合并</param>
+        /// <returns>返回是否为合并单元格的布尔(Boolean)值</returns>
+        public static bool IsMergeCell(this ICell cell, out int rowSpan, out int columnSpan)
+        {
+            return cell.Sheet.IsMergeCell(cell.RowIndex, cell.ColumnIndex, out rowSpan, out columnSpan);
+        }
+
+        /// <summary>
+        /// 返回上一个跨度行,如果rowIndex为第一行,则返回null
+        /// </summary>
+        /// <param name="sheet">Excel工作表</param>
+        /// <param name="rowIndex">行索引,从0开始</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <returns>返回上一个跨度行</returns>
+        public static IRow PrevSpanRow(this ISheet sheet, int rowIndex, int columnIndex)
+        {
+            return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) =>
+            {
+                //上一个单元格维度
+                Dimension prevDimension;
+                sheet.IsMergeCell(currentDimension.FirstRowIndex - 1, columnIndex, out prevDimension);
+                return prevDimension.DataCell.Row;
+            });
+        }
+
+        /// <summary>
+        /// 返回下一个跨度行,如果rowIndex为最后一行,则返回null
+        /// </summary>
+        /// <param name="sheet">Excel工作表</param>
+        /// <param name="rowIndex">行索引,从0开始</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <returns>返回下一个跨度行</returns>
+        public static IRow NextSpanRow(this ISheet sheet, int rowIndex, int columnIndex)
+        {
+            return sheet.FuncSheet(rowIndex, columnIndex, (currentDimension, isMerge) =>
+                isMerge ? sheet.GetRow(currentDimension.FirstRowIndex + currentDimension.RowSpan) : sheet.GetRow(rowIndex));
+        }
+
+        /// <summary>
+        /// 返回上一个跨度行,如果row为第一行,则返回null
+        /// </summary>
+        /// <param name="row">行</param>
+        /// <returns>返回上一个跨度行</returns>
+        public static IRow PrevSpanRow(this IRow row)
+        {
+            return row.Sheet.PrevSpanRow(row.RowNum, row.FirstCellNum);
+        }
+
+        /// <summary>
+        /// 返回下一个跨度行,如果row为最后一行,则返回null
+        /// </summary>
+        /// <param name="row">行</param>
+        /// <returns>返回下一个跨度行</returns>
+        public static IRow NextSpanRow(this IRow row)
+        {
+            return row.Sheet.NextSpanRow(row.RowNum, row.FirstCellNum);
+        }
+
+        /// <summary>
+        /// 返回上一个跨度列,如果columnIndex为第一列,则返回null
+        /// </summary>
+        /// <param name="row">行</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <returns>返回上一个跨度列</returns>
+        public static ICell PrevSpanCell(this IRow row, int columnIndex)
+        {
+            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) =>
+            {
+                //上一个单元格维度
+                Dimension prevDimension;
+                row.Sheet.IsMergeCell(row.RowNum, currentDimension.FirstColumnIndex - 1, out prevDimension);
+                return prevDimension.DataCell;
+            });
+        }
+
+        /// <summary>
+        /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null
+        /// </summary>
+        /// <param name="row">行</param>
+        /// <param name="columnIndex">列索引,从0开始</param>
+        /// <returns>返回下一个跨度列</returns>
+        public static ICell NextSpanCell(this IRow row, int columnIndex)
+        {
+            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) =>
+                row.GetCell(currentDimension.FirstColumnIndex + currentDimension.ColumnSpan));
+        }
+
+        /// <summary>
+        /// 返回上一个跨度列,如果cell为第一列,则返回null
+        /// </summary>
+        /// <param name="cell">单元格</param>
+        /// <returns>返回上一个跨度列</returns>
+        public static ICell PrevSpanCell(this ICell cell)
+        {
+            return cell.Row.PrevSpanCell(cell.ColumnIndex);
+        }
+
+        /// <summary>
+        /// 返回下一个跨度列,如果columnIndex为最后一列,则返回null
+        /// </summary>
+        /// <param name="cell">单元格</param>
+        /// <returns>返回下一个跨度列</returns>
+        public static ICell NextSpanCell(this ICell cell)
+        {
+            return cell.Row.NextSpanCell(cell.ColumnIndex);
+        }
+
+        /// <summary>
+        /// 返回指定行索引所在的合并单元格(区域)中的第一行(通常是含有数据的行)
+        /// </summary>
+        /// <param name="sheet">Excel工作表</param>
+        /// <param name="rowIndex">行索引,从0开始</param>
+        /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行</returns>
+        public static IRow GetDataRow(this ISheet sheet, int rowIndex)
+        {
+            return sheet.FuncSheet(rowIndex, 0, (currentDimension, isMerge) => sheet.GetRow(currentDimension.FirstRowIndex));
+        }
+
+        /// <summary>
+        /// 返回指定列索引所在的合并单元格(区域)中的第一行第一列(通常是含有数据的单元格)
+        /// </summary>
+        /// <param name="row">行</param>
+        /// <param name="columnIndex">列索引</param>
+        /// <returns>返回指定列索引所在的合并单元格(区域)中的第一行第一列</returns>
+        public static ICell GetDataCell(this IRow row, int columnIndex)
+        {
+            return row.Sheet.FuncSheet(row.RowNum, columnIndex, (currentDimension, isMerge) => currentDimension.DataCell);
+        }
+
+        private static T FuncSheet<T>(this ISheet sheet, int rowIndex, int columnIndex, Func<Dimension, bool, T> func)
+        {
+            //当前单元格维度
+            Dimension currentDimension;
+            //是否为合并单元格
+            bool isMerge = sheet.IsMergeCell(rowIndex, columnIndex, out currentDimension);
+
+            return func(currentDimension, isMerge);
+        }
+    }
+}

+ 18 - 6
MBI/SAGA.DotNetUtils/NPOI/NPOIHelper.cs

@@ -240,7 +240,7 @@ namespace SAGA.DotNetUtils.NPOI
 
             IRow headerRow = sheet.GetRow(0);
             if (headerRow == null) return dt;
-            if (headerRow.Cells.Count==0)
+            if (headerRow.Cells.Count == 0)
             {
                 headerRow = sheet.GetRow(1);
             }
@@ -255,7 +255,7 @@ namespace SAGA.DotNetUtils.NPOI
             for (int i = (sheet.FirstRowNum + 1); i <= sheet.LastRowNum; i++)
             {
                 IRow row = sheet.GetRow(i);
-                if(row==null)continue;
+                if (row == null) continue;
                 DataRow dataRow = dt.NewRow();
 
                 for (int j = row.FirstCellNum; j < cellCount; j++)
@@ -324,7 +324,7 @@ namespace SAGA.DotNetUtils.NPOI
                 ISheet sheet = sheetInfo.SheetName == "" ? workbook.GetSheetAt(0) : workbook.GetSheet(sheetInfo.SheetName);
 
                 IRow row;
-               // List<int> showIndex = new List<int> { 1, 2, 3, 4 };
+                // List<int> showIndex = new List<int> { 1, 2, 3, 4 };
 
                 for (int i = sheetInfo.RowStartIndex; i < sheet.LastRowNum; i++)
                 {
@@ -341,6 +341,7 @@ namespace SAGA.DotNetUtils.NPOI
         }
         /// <summary>
         /// C#反射遍历对象属性
+        /// 
         /// </summary>
         /// <typeparam name="T">对象类型</typeparam>
         /// <param name="model">对象</param>
@@ -351,12 +352,23 @@ namespace SAGA.DotNetUtils.NPOI
             PropertyInfo[] PropertyList = t.GetProperties();
             foreach (PropertyInfo item in PropertyList)
             {
-                var index = item.GetCustomAttribute<CellIndexAttribute>()?.Index;
-                string name = item.Name;
-                item.SetValue(model, row.GetCell(index ?? 0) + "");
+                var index = item.GetCustomAttribute<CellIndexAttribute>()?.Index ?? 0;
+                string value = "";
+                if (index != 0)
+                {
+                    value = row.GetCell(index)?.StringCellValue;
+                    //如果读取到的值为null,则判断是否为合并单元格,读取合并单元格的值
+                    if (value.IsNullOrEmpty())
+                    {
+                        value = row.GetDataCell(index)?.StringCellValue;
+                    }
+                }
+
+                item.SetValue(model, value);
             }
             return model;
         }
+
     }
     public class SheetInfoAttribute : Attribute
     {

+ 1 - 0
MBI/SAGA.DotNetUtils/SAGA.DotNetUtils.csproj

@@ -289,6 +289,7 @@
     <Compile Include="Logger\SystemLogger.cs" />
     <Compile Include="Logger\WriteHandler.cs" />
     <Compile Include="MBI\OutReachConst.cs" />
+    <Compile Include="NPOI\ExcelExtension.cs" />
     <Compile Include="NPOI\NPOIHelper.cs" />
     <Compile Include="Others\AppBaseInfo.cs" />
     <Compile Include="Others\ApplicationDecrypt.cs" />

+ 3 - 0
MBI/SAGA.MBI/ToolsData/ModeCheck/DataCheckRule.cs

@@ -61,6 +61,9 @@ namespace SAGA.MBI.ToolsData.ModeCheck
     {
         [CellIndex(0)]
         public string Name { get; set; }
+
+        [CellIndex(1)]
+        public string Discription { get; set; }
     }
     /// <summary>
     /// 参考-revit分类

+ 3 - 1
MBI/SAGA.MBI/ToolsData/ModeCheck/DocumentQueue.cs

@@ -1,5 +1,7 @@
 /* ==============================================================================
- * 功能描述:Document队列
+ * 功能描述:Document队列,
+ * 1,按使用频率,使用频率低的优先关闭。使用频率如何统计;
+ * 2,按文件大小,小文件优化关闭。
  * 创 建 者:Garrett
  * 创建日期:2018/11/16 9:34:39
  * ==============================================================================*/

+ 15 - 11
MBI/SAGA.MBI/ToolsData/ModeCheck/EquipmentLocationCenterComparer.cs

@@ -25,7 +25,7 @@ namespace SAGA.MBI.ToolsData.ModeCheck
     {
         public EquipmentLocationCenterComparer()
         {
-            Name = "设备中心点检查";
+            Name = "设备定位点检查";
         }
         [DataCheckProcessAspect]
         public override bool Check()
@@ -84,8 +84,8 @@ namespace SAGA.MBI.ToolsData.ModeCheck
                 result.IsRight = false;
                 result.RMessage = "定位点和中心点不重合,请检查";
             }
-            result.LocationXYZ = location.ToString2();
-            result.CenterXYZ = origin.ToString();
+            result.LocationXYZ = location.ToString2D();
+            result.CenterXYZ = origin.ToString2D();
             return result;
         }
         //[DataCheckProcessAspect]
@@ -108,6 +108,8 @@ namespace SAGA.MBI.ToolsData.ModeCheck
                 //row4.AddCell(2, "文件地址", DataCheckNPOIStyle.Title);
                 //row4.AddCell(3, "族名称", DataCheckNPOIStyle.Title);
                 //row4.AddCell(4, "ID", DataCheckNPOIStyle.Title);
+                //row4.AddCell(4, "定位点", DataCheckNPOIStyle.Title);
+                //row4.AddCell(4, "中心点", DataCheckNPOIStyle.Title);
                 //row4.AddCell(5, "通过", DataCheckNPOIStyle.Title);
                 //row4.AddCell(6, "备注(失败原因)", DataCheckNPOIStyle.Title);
                 foreach (EquipmentPartRefEqCheckResult result in Results)
@@ -118,15 +120,17 @@ namespace SAGA.MBI.ToolsData.ModeCheck
                     index++;
                     IRow rowN = sheet.CreateRow(index);
                     DataCheckNPOIStyle style = result.IsRight ? DataCheckNPOIStyle.Content : DataCheckNPOIStyle.Error;
-
-                    rowN.AddCell(0, rbase.RFloorName, style);
-                    rowN.AddCell(1, rbase.RFileName, style);
-                    rowN.AddCell(2, rbase.RPath, style);
-                    rowN.AddCell(3, result.FamilyName, style);
-                    rowN.AddCell(4, result.Id, style);
+                    int i = 0;
+                    rowN.AddCell(i++, rbase.RFloorName, style);
+                    rowN.AddCell(i++, rbase.RFileName, style);
+                    rowN.AddCell(i++, rbase.RPath, style);
+                    rowN.AddCell(i++, result.FamilyName, style);
+                    rowN.AddCell(i++, result.Id, style);
+                    rowN.AddCell(i++, result.LocationXYZ, style);
+                    rowN.AddCell(i++, result.CenterXYZ, style);
                     string rowN4 = result.IsRight ? "通过" : "不通过";
-                    rowN.AddCell(5, rowN4, style);
-                    rowN.AddCell(6, result.RMessage, style);
+                    rowN.AddCell(i++, rowN4, style);
+                    rowN.AddCell(i++, result.RMessage, style);
                 }
 
                 #endregion