• WPF下的Richtextbox中实现表格合并,添加删除行列等功能


      .Net中已有现在的方法实现这些功能,不过可能是由于未完善,未把方法公开出来。只能用反射的方法去调用它。

    详细信息可以查看.Net Framework 的源代码

    实现了以下功能:

    • 合并选中的单元格
    • 拆分已合并的单元格(这功能有点坑,有bug)
    • 插入指定行列的表格
    • 添加删除选中行
    • 添加删除选中列

    把调用方法封装到一个类用

      1 using System;
      2 using System.Linq;
      3 using System.Reflection;
      4 using System.Windows.Documents;
      5 
      6 namespace WPFMergeTable
      7 {
      8     /// <summary>
      9     /// 表格相关操作
     10     /// </summary>
     11     public class TextRangeEditTables
     12     {
     13         //-------------------------------------------------------------------------------------------------\
     14         //  
     15         //  通过反射获取到表格操作方法,并调用之
     16         //  
     17         //  详细请查看.NET Framwork WPF RichTextBox 相关源代码
     18         //  http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRangeEditTables.cs
     19         //  http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRange.cs
     20         //
     21         //-------------------------------------------------------------------------------------------------//
     22 
     23         #region 表格相关操作
     24 
     25         /// <summary>
     26         /// 获取选中单元格的第一个(左上角)和最后一个(右下角)单元格
     27         /// </summary>
     28         /// <param name="selection">RichTextBox.Section</param>
     29         /// <param name="startCell"></param>
     30         /// <param name="endCell"></param>
     31         /// <returns></returns>
     32         public static bool GetSelectedCells(TextSelection selection, out TableCell startCell, out TableCell endCell)
     33         {
     34             startCell = null;
     35             endCell = null;
     36 
     37             #region 函数原型
     38             /********************************************************************************************
     39             /// <summary>
     40             /// From two text positions finds out table elements involved
     41             /// into building potential table range.
     42             /// </summary>
     43             /// <param name="anchorPosition">
     44             /// Position where selection starts. The cell at this position (if any)
     45             /// must be included into a range unconditionally.
     46             /// </param>
     47             /// <param name="movingPosition">
     48             /// A position opposite to an anchorPosition.
     49             /// </param>
     50             /// <param name="includeCellAtMovingPosition">
     51             /// <see ref="TextRangeEditTables.BuildTableRange"/>
     52             /// </param>
     53             /// <param name="anchorCell">
     54             /// The cell at anchor position. Returns not null only if a range is not crossing table
     55             /// boundary. Returns null if the range does not cross any TableCell boundary at all
     56             /// or if cells crossed belong to a table whose boundary is crossed by a range.
     57             /// In other words, anchorCell and movingCell are either both nulls or both non-nulls.
     58             /// </param>
     59             /// <param name="movingCell">
     60             /// The cell at the movingPosition.  Returns not null only if a range is not crossing table
     61             /// boundary. Returns null if the range does not cross any TableCell boundary at all
     62             /// or if cells crossed belong to a table whose boundary is crossed by a range.
     63             /// In other words, anchorCell and movingCell are either both nulls or both non-nulls.
     64             /// </param>
     65             /// <param name="anchorRow"></param>
     66             /// <param name="movingRow"></param>
     67             /// <param name="anchorRowGroup"></param>
     68             /// <param name="movingRowGroup"></param>
     69             /// <param name="anchorTable"></param>
     70             /// <param name="movingTable"></param>
     71             /// <returns>
     72             /// True if at least one structural unit was found.
     73             /// False if no structural units were crossed by either startPosition or endPosition
     74             /// (up to their commin ancestor element).
     75             /// </returns>
     76             private static bool IdentifyTableElements(
     77                 TextPointer anchorPosition, TextPointer movingPosition, 
     78                 bool includeCellAtMovingPosition, 
     79                 out TableCell anchorCell, out TableCell movingCell, 
     80                 out TableRow anchorRow, out TableRow movingRow, 
     81                 out TableRowGroup anchorRowGroup, out TableRowGroup movingRowGroup, 
     82                 out Table anchorTable, out Table movingTable)
     83              ********************************************************************************************/
     84             #endregion
     85 
     86             //System.Windows.Documents.TextRangeEditTables
     87             Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
     88                                from type in asm.GetTypes()
     89                                where type.IsClass
     90                                && asm.ManifestModule.Name == "PresentationFramework.dll"
     91                                && type.Name == "TextRangeEditTables"
     92                                select type).Single();
     93             //MethodInfo info = objectType.GetMethod("IdentifyTableElements", BindingFlags.NonPublic | BindingFlags.Static);
     94             MethodInfo info = getNonPublicMethodInfo(objectType, "IdentifyTableElements");
     95             if (info != null)
     96             {
     97                 object[] param = new object[11];
     98                 param[0] = selection.Start;
     99                 param[1] = selection.End;
    100                 param[2] = false;
    101 
    102                 object result = info.Invoke(null, param);
    103                 startCell = param[3] as TableCell;
    104                 endCell = param[4] as TableCell;
    105                 return (bool)result;
    106             }
    107             return false;
    108         }
    109 
    110         /// <summary>
    111         /// 选中单元格是否能合并
    112         /// </summary>
    113         /// <param name="selection">RichTextBox.Section</param>
    114         /// <returns></returns>
    115         public static bool CanMergeCellRange(TextSelection selection)
    116         {
    117             TableCell startCell = null;
    118             TableCell endCell = null;
    119             Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
    120                                from type in asm.GetTypes()
    121                                where type.IsClass
    122                                && asm.ManifestModule.Name == "PresentationFramework.dll"
    123                                && type.Name == "TextRangeEditTables"
    124                                select type).Single();
    125             //MethodInfo info = objectType.GetMethod("CanMergeCellRange", BindingFlags.NonPublic | BindingFlags.Static);
    126             MethodInfo info = getNonPublicMethodInfo(objectType, "CanMergeCellRange");
    127             if (info != null)
    128             {
    129                 GetSelectedCells(selection, out startCell, out endCell);
    130                 if (startCell != null && endCell != null)
    131                 {
    132                     int startColumnIndex = (int)getPrivateProperty<TableCell>(startCell, "ColumnIndex");
    133                     int endColumnIndex = (int)getPrivateProperty<TableCell>(endCell, "ColumnIndex");
    134                     int startRowIndex = (int)getPrivateProperty<TableCell>(startCell, "RowIndex");
    135                     int endRowIndex = (int)getPrivateProperty<TableCell>(endCell, "RowIndex");
    136                     TableRowGroup rowGroup = getPrivateProperty<TableRow>(startCell.Parent, "RowGroup") as TableRowGroup;
    137                     return (bool)info.Invoke(null, new object[] { 
    138                         rowGroup,                               // RowGroup
    139                         startRowIndex,                          // topRow
    140                         endRowIndex + endCell.RowSpan - 1,      // bottomRow
    141                         startColumnIndex,                       // leftColumn
    142                         endColumnIndex + endCell.ColumnSpan - 1 // rightColumn
    143                      });
    144                 }
    145             }
    146             return false;
    147         }
    148 
    149         /// <summary>
    150         /// 合并选中表格
    151         /// </summary>
    152         /// <param name="selection"></param>
    153         /// <returns></returns>
    154         public static TextRange MergeCells(TextRange selection)
    155         {
    156             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("MergeCells");
    157             if (mInfo != null)
    158             {
    159                 return mInfo.Invoke(selection, null) as TextRange;
    160             }
    161             return null;
    162         }
    163 
    164         /// <summary>
    165         /// 拆分表格(好像还有问题。。。)
    166         /// </summary>
    167         /// <param name="selection"></param>
    168         /// <param name="splitCountHorizontal"></param>
    169         /// <param name="splitCountVertical"></param>
    170         /// <returns></returns>
    171         public static TextRange SplitCell(TextRange selection, int splitCountHorizontal, int splitCountVertical)
    172         {
    173             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("SplitCell");
    174             if (mInfo != null)
    175             {
    176                 return mInfo.Invoke(selection, new object[] { splitCountHorizontal, splitCountVertical }) as TextRange;
    177             }
    178             return null;
    179         }
    180 
    181         /// <summary>
    182         /// 插入表格
    183         /// </summary>
    184         /// <param name="selection"></param>
    185         /// <param name="rowCount">行数</param>
    186         /// <param name="columnCount">列数</param>
    187         /// <returns></returns>
    188         public static TextRange InsertTable(TextRange selection, int rowCount, int columnCount)
    189         {
    190             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertTable");
    191             if (mInfo != null)
    192             {
    193                 return mInfo.Invoke(selection, new object[] { rowCount, columnCount }) as TextRange;
    194             }
    195             return null;
    196         }
    197 
    198         /// <summary>
    199         /// 在光标下插入行
    200         /// </summary>
    201         /// <param name="selection"></param>
    202         /// <param name="rowCount">行数</param>
    203         /// <returns></returns>
    204         public static TextRange InsertRows(TextRange selection, int rowCount)
    205         {
    206             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertRows");
    207             if (mInfo != null)
    208             {
    209                 return mInfo.Invoke(selection, new object[] { rowCount }) as TextRange;
    210             }
    211             return null;
    212         }
    213 
    214         /// <summary>
    215         /// 删除选中行
    216         /// </summary>
    217         /// <param name="selection"></param>
    218         /// <returns></returns>
    219         public static bool DeleteRows(TextRange selection)
    220         {
    221             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("DeleteRows");
    222             if (mInfo != null)
    223             {
    224                 return (bool)mInfo.Invoke(selection, null);
    225             }
    226             return false;
    227         }
    228 
    229         /// <summary>
    230         /// 在光标右边插入列
    231         /// </summary>
    232         /// <param name="selection"></param>
    233         /// <param name="columnCount">列数</param>
    234         /// <returns></returns>
    235         public static TextRange InsertColumns(TextRange selection, int columnCount)
    236         {
    237             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertColumns");
    238             if (mInfo != null)
    239             {
    240                 return mInfo.Invoke(selection, new object[] { columnCount }) as TextRange;
    241             }
    242             return null;
    243         }
    244 
    245         /// <summary>
    246         /// 删除选中列
    247         /// </summary>
    248         /// <param name="selection"></param>
    249         /// <returns></returns>
    250         public static bool DeleteColumns(TextRange selection)
    251         {
    252             MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("DeleteColumns");
    253             if (mInfo != null)
    254             {
    255                 return (bool)mInfo.Invoke(selection, null);
    256             }
    257             return false;
    258         }
    259 
    260         /// <summary>
    261         /// 获取类中私有方法
    262         /// </summary>
    263         /// <param name="type"></param>
    264         /// <param name="methodName"></param>
    265         /// <returns></returns>
    266         private static MethodInfo getNonPublicMethodInfo(Type type, string methodName)
    267         {
    268             MethodInfo mInfo = type
    269                 .GetMethod(methodName,
    270                 BindingFlags.NonPublic
    271                 | BindingFlags.Static
    272                 | BindingFlags.Instance);
    273             return mInfo;
    274         }
    275 
    276         /// <summary>
    277         /// 获取类中私有方法
    278         /// </summary>
    279         /// <typeparam name="T"></typeparam>
    280         /// <param name="methodName"></param>
    281         /// <returns></returns>
    282         private static MethodInfo getNonPublicMethodInfo<T>(string methodName)
    283             where T : class
    284         {
    285             return getNonPublicMethodInfo(typeof(T), methodName);
    286         }
    287 
    288         /// <summary>
    289         /// 获取私有属性
    290         /// </summary>
    291         /// <typeparam name="T"></typeparam>
    292         /// <param name="instance"></param>
    293         /// <param name="propertyName"></param>
    294         /// <returns></returns>
    295         private static object getPrivateProperty<T>(object instance, string propertyName)
    296             where T : class
    297         {
    298             object result = null;
    299             PropertyInfo pInfo = typeof(T).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
    300             if (pInfo != null)
    301             {
    302                 result = pInfo.GetValue(instance, null);
    303             }
    304             return result;
    305         }
    306 
    307         #endregion
    308     }
    309 }
    View Code
  • 相关阅读:
    mysql导出csv文件
    httpclient设置proxy与proxyselector
    91删除数据
    使用RestTemplate post方式提交表单数据
    bootstrap获取总条目数
    获取字符串已utf-8表示的字节数
    mongo批量更新
    重庆大学计算机917考研分析(定期更新考研信息)
    卷积
    LaTeX中自定义enumerate的编号格式
  • 原文地址:https://www.cnblogs.com/datous/p/TextRangeEditTables.html
Copyright © 2020-2023  润新知