WPF下的Richtextbox中实现表格合并,添加删除行列等功能
.Net中已有现在的方法实现这些功能,不过可能是由于未完善,未把方法公开出来。只能用反射的方法去调用它。
详细信息可以查看.Net Framework 的源代码
http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRangeEditTables.cs
http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRange.cs
实现了以下功能:
- 合并选中的单元格
- 拆分已合并的单元格(这功能有点坑,有bug)
- 插入指定行列的表格
- 添加删除选中行
- 添加删除选中列
把调用方法封装到一个类用
using System;
using System.Linq;
using System.Reflection;
using System.Windows.Documents; namespace WPFMergeTable
{
/// <summary>
/// 表格相关操作
/// </summary>
public class TextRangeEditTables
{
//-------------------------------------------------------------------------------------------------\\
//
// 通过反射获取到表格操作方法,并调用之
//
// 详细请查看.NET Framwork WPF RichTextBox 相关源代码
// http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRangeEditTables.cs
// http://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Documents/TextRange.cs
//
//-------------------------------------------------------------------------------------------------// #region 表格相关操作 /// <summary>
/// 获取选中单元格的第一个(左上角)和最后一个(右下角)单元格
/// </summary>
/// <param name="selection">RichTextBox.Section</param>
/// <param name="startCell"></param>
/// <param name="endCell"></param>
/// <returns></returns>
public static bool GetSelectedCells(TextSelection selection, out TableCell startCell, out TableCell endCell)
{
startCell = null;
endCell = null; #region 函数原型
/********************************************************************************************\
/// <summary>
/// From two text positions finds out table elements involved
/// into building potential table range.
/// </summary>
/// <param name="anchorPosition">
/// Position where selection starts. The cell at this position (if any)
/// must be included into a range unconditionally.
/// </param>
/// <param name="movingPosition">
/// A position opposite to an anchorPosition.
/// </param>
/// <param name="includeCellAtMovingPosition">
/// <see ref="TextRangeEditTables.BuildTableRange"/>
/// </param>
/// <param name="anchorCell">
/// The cell at anchor position. Returns not null only if a range is not crossing table
/// boundary. Returns null if the range does not cross any TableCell boundary at all
/// or if cells crossed belong to a table whose boundary is crossed by a range.
/// In other words, anchorCell and movingCell are either both nulls or both non-nulls.
/// </param>
/// <param name="movingCell">
/// The cell at the movingPosition. Returns not null only if a range is not crossing table
/// boundary. Returns null if the range does not cross any TableCell boundary at all
/// or if cells crossed belong to a table whose boundary is crossed by a range.
/// In other words, anchorCell and movingCell are either both nulls or both non-nulls.
/// </param>
/// <param name="anchorRow"></param>
/// <param name="movingRow"></param>
/// <param name="anchorRowGroup"></param>
/// <param name="movingRowGroup"></param>
/// <param name="anchorTable"></param>
/// <param name="movingTable"></param>
/// <returns>
/// True if at least one structural unit was found.
/// False if no structural units were crossed by either startPosition or endPosition
/// (up to their commin ancestor element).
/// </returns>
private static bool IdentifyTableElements(
TextPointer anchorPosition, TextPointer movingPosition,
bool includeCellAtMovingPosition,
out TableCell anchorCell, out TableCell movingCell,
out TableRow anchorRow, out TableRow movingRow,
out TableRowGroup anchorRowGroup, out TableRowGroup movingRowGroup,
out Table anchorTable, out Table movingTable)
\********************************************************************************************/
#endregion //System.Windows.Documents.TextRangeEditTables
Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from type in asm.GetTypes()
where type.IsClass
&& asm.ManifestModule.Name == "PresentationFramework.dll"
&& type.Name == "TextRangeEditTables"
select type).Single();
//MethodInfo info = objectType.GetMethod("IdentifyTableElements", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo info = getNonPublicMethodInfo(objectType, "IdentifyTableElements");
if (info != null)
{
object[] param = new object[];
param[] = selection.Start;
param[] = selection.End;
param[] = false; object result = info.Invoke(null, param);
startCell = param[] as TableCell;
endCell = param[] as TableCell;
return (bool)result;
}
return false;
} /// <summary>
/// 选中单元格是否能合并
/// </summary>
/// <param name="selection">RichTextBox.Section</param>
/// <returns></returns>
public static bool CanMergeCellRange(TextSelection selection)
{
TableCell startCell = null;
TableCell endCell = null;
Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from type in asm.GetTypes()
where type.IsClass
&& asm.ManifestModule.Name == "PresentationFramework.dll"
&& type.Name == "TextRangeEditTables"
select type).Single();
//MethodInfo info = objectType.GetMethod("CanMergeCellRange", BindingFlags.NonPublic | BindingFlags.Static);
MethodInfo info = getNonPublicMethodInfo(objectType, "CanMergeCellRange");
if (info != null)
{
GetSelectedCells(selection, out startCell, out endCell);
if (startCell != null && endCell != null)
{
int startColumnIndex = (int)getPrivateProperty<TableCell>(startCell, "ColumnIndex");
int endColumnIndex = (int)getPrivateProperty<TableCell>(endCell, "ColumnIndex");
int startRowIndex = (int)getPrivateProperty<TableCell>(startCell, "RowIndex");
int endRowIndex = (int)getPrivateProperty<TableCell>(endCell, "RowIndex");
TableRowGroup rowGroup = getPrivateProperty<TableRow>(startCell.Parent, "RowGroup") as TableRowGroup;
return (bool)info.Invoke(null, new object[] {
rowGroup, // RowGroup
startRowIndex, // topRow
endRowIndex + endCell.RowSpan - , // bottomRow
startColumnIndex, // leftColumn
endColumnIndex + endCell.ColumnSpan - // rightColumn
});
}
}
return false;
} /// <summary>
/// 合并选中表格
/// </summary>
/// <param name="selection"></param>
/// <returns></returns>
public static TextRange MergeCells(TextRange selection)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("MergeCells");
if (mInfo != null)
{
return mInfo.Invoke(selection, null) as TextRange;
}
return null;
} /// <summary>
/// 拆分表格(好像还有问题。。。)
/// </summary>
/// <param name="selection"></param>
/// <param name="splitCountHorizontal"></param>
/// <param name="splitCountVertical"></param>
/// <returns></returns>
public static TextRange SplitCell(TextRange selection, int splitCountHorizontal, int splitCountVertical)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("SplitCell");
if (mInfo != null)
{
return mInfo.Invoke(selection, new object[] { splitCountHorizontal, splitCountVertical }) as TextRange;
}
return null;
} /// <summary>
/// 插入表格
/// </summary>
/// <param name="selection"></param>
/// <param name="rowCount">行数</param>
/// <param name="columnCount">列数</param>
/// <returns></returns>
public static TextRange InsertTable(TextRange selection, int rowCount, int columnCount)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertTable");
if (mInfo != null)
{
return mInfo.Invoke(selection, new object[] { rowCount, columnCount }) as TextRange;
}
return null;
} /// <summary>
/// 在光标下插入行
/// </summary>
/// <param name="selection"></param>
/// <param name="rowCount">行数</param>
/// <returns></returns>
public static TextRange InsertRows(TextRange selection, int rowCount)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertRows");
if (mInfo != null)
{
return mInfo.Invoke(selection, new object[] { rowCount }) as TextRange;
}
return null;
} /// <summary>
/// 删除选中行
/// </summary>
/// <param name="selection"></param>
/// <returns></returns>
public static bool DeleteRows(TextRange selection)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("DeleteRows");
if (mInfo != null)
{
return (bool)mInfo.Invoke(selection, null);
}
return false;
} /// <summary>
/// 在光标右边插入列
/// </summary>
/// <param name="selection"></param>
/// <param name="columnCount">列数</param>
/// <returns></returns>
public static TextRange InsertColumns(TextRange selection, int columnCount)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("InsertColumns");
if (mInfo != null)
{
return mInfo.Invoke(selection, new object[] { columnCount }) as TextRange;
}
return null;
} /// <summary>
/// 删除选中列
/// </summary>
/// <param name="selection"></param>
/// <returns></returns>
public static bool DeleteColumns(TextRange selection)
{
MethodInfo mInfo = getNonPublicMethodInfo<TextRange>("DeleteColumns");
if (mInfo != null)
{
return (bool)mInfo.Invoke(selection, null);
}
return false;
} /// <summary>
/// 获取类中私有方法
/// </summary>
/// <param name="type"></param>
/// <param name="methodName"></param>
/// <returns></returns>
private static MethodInfo getNonPublicMethodInfo(Type type, string methodName)
{
MethodInfo mInfo = type
.GetMethod(methodName,
BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.Instance);
return mInfo;
} /// <summary>
/// 获取类中私有方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
private static MethodInfo getNonPublicMethodInfo<T>(string methodName)
where T : class
{
return getNonPublicMethodInfo(typeof(T), methodName);
} /// <summary>
/// 获取私有属性
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="instance"></param>
/// <param name="propertyName"></param>
/// <returns></returns>
private static object getPrivateProperty<T>(object instance, string propertyName)
where T : class
{
object result = null;
PropertyInfo pInfo = typeof(T).GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance);
if (pInfo != null)
{
result = pInfo.GetValue(instance, null);
}
return result;
} #endregion
}
}
WPF下的Richtextbox中实现表格合并,添加删除行列等功能的更多相关文章
- js 表格操作----添加删除
js 表格操作----添加删除 书名:<input type="text" id="name"> 价格:<input type="t ...
- [转载]EasyUI中数据表格DataGrid添加排序功能
我们这里演示的是EasyUI数据表格DataGrid从服务器端排序功能,因为觉的本地数据排序没有多大的作用,一般我们DataGrid不会读取全部数据,只会读取当前页的数据,所以本地数据排序也只是对当前 ...
- 编辑 Ext 表格(一)——— 动态添加删除行列
一.动态增删行 在 ext 表格中,动态添加行主要和表格绑定的 store 有关, 通过对 store 数据集进行添加或删除,就能实现表格行的动态添加删除. (1) 动态添加表格的行 gridS ...
- vue+element项目中动态表格合并
需求:elementui里的table虽然有合并函数(:span-method),单基本都是设置固定值合并.现在有一个树型结构的数据,要求我们将里面的某个list和其他属性一起展开展示,并且list中 ...
- ant design 中实现表格头部可删除和添加
我是用antd pro做一个项目.有一个小需求是表格头部栏可操作.具体是表头的每一项都带一个"x"按钮,当不想展示这一栏的时候,直接点"x",这一栏就不展示了. ...
- Javascript中DataGrid表格纵线添加数据
接之前写的一篇博客http://www.cnblogs.com/Liu30/p/7229641.html,生成一个6*24的表格之后,添加数据 表格数据一般都是按行添加,我所做的这个表格是想添加一天2 ...
- ios中tableview的移动添加删除
// // MJViewController.m // UITableView-编辑模式 // // Created by mj on 13-4-11. // Copyright (c) 2013年 ...
- File类中的一些属性 添加删除文件夹
import java.io.File; import java.io.IOException; public class FileD { public static void main(String ...
- Mac OS X中Launchpad的图标添加删除方法(添加方法别试了,和Linux很大区别)
说明:在Mac下的Launchpad图标添加和删除都与应用程序的app文件有关,如果单纯的只想在Launchpad添加自定义的图标,然后指定要某条命令运行时,建议不要这么干,Launchpad的图标管 ...
随机推荐
- 虚函数的使用 以及虚函数与重载的关系, 空虚函数的作用,纯虚函数->抽象类,基类虚析构函数使释放对象更彻底
为了访问公有派生类的特定成员,可以通过讲基类指针显示转换为派生类指针. 也可以将基类的非静态成员函数定义为虚函数(在函数前加上virtual) #include<iostream> usi ...
- Entity Framework 使用Mysql的配置文件
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSec ...
- 网络第一节——NSURLConnection
一.NSURLConnection的常用类 (1)NSURL:请求地址 (2)NSURLRequest:封装一个请求,保存发给服务器的全部数据,包括一个NSURL对象,请求方法.请求头.请求体.... ...
- 码云以及git使用
码云的使用方法以及git的连用 创建公钥的方法 打开码云,点击个人资料---->SSH公钥---->点击怎样生成公钥 SSH Keys ssh keys可以让你在你的电脑和Git@OSC知 ...
- js 中的快速排序算法简单实现
对于快速排序,最早是在c++中看到,它是利用指针来交换顺序,其实无论哪种语言,原理 和 思想都是一样,然而真正用起来的时候就特别容易忽略一些事实,导致实现失败.废话少说,下面用js实现一下快速排序: ...
- [原创]zepto打造一款移动端划屏插件
最近忙着将项目内的jquery 2换成zepto 因为不想引用过多的zepto包,所以花了点时间 zepto真的精简了许多,源代码看着真舒服 正好项目内需要一个划屏插件,就用zepto写了一个 逻辑其 ...
- 转载请注明出处: https://github.com/qiu-deqing/FE-interview
转载请注明出处: https://github.com/qiu-deqing/FE-interview Table of Contents generated with DocToc FE-inter ...
- 为什么要用base64编码
1.需求 了解为什么要使用base64对数据编码 2.理由 因为传输二进制数据的时候,网络中间的有些路由会把ascii码中的不可见字符删了,导致数据不一致.一般也会对url进行base64编码 Whe ...
- PHP代码获取客户端IP地址经纬度及所在城市
echo $_SERVER['HTTP_HOST'];//echo $_SERVER['REQUEST_URI'];$getIp=$_SERVER["REMOTE_ADDR"];e ...
- iOS sqlite数据库图像化查看
问题描述:在xocde上用sqlite数据库的时候,因为没有图形化界面,有些时候很难看出自己设计的数据库是否有问题,比如我刚上手sqlite数据库设计id为自增长时,很自然的用了identify(1, ...