nutstore 发表于 2020-6-16 11:10:12

如何在 RangeChanged 中实现一些 canUndo 的操作

比如 RangeChanged 并且 info.action === Spread.Sheets.RangeChangedAction.clear 时,我将对应的 cell 的 backColor 都设置为 red。
此时用户 ctrl+z 了,那内容和 backColor 都应该同时变回去,如何实现?

Fiooona 发表于 2020-6-16 11:39:20

将需要同时撤销的操作 写到同一个命令里,用自定义命令来实现,这样撤销时会撤销整个命令:
自定义命令的学习指南:https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/features/worksheet/actions/custom-action/purejs

nutstore 发表于 2020-6-16 13:54:32

没法写到一起,因为内容是 clear 删除的,不是我删除的,我只能收到 RangeChanged 事件,得知内容被清除,然后我再操作 backColor

KevinChen 发表于 2020-6-16 15:57:24

在自定义command中,通常会有一个isUndo的参数来标记当前执行栈是execute还是undo的操作,那么在isUndo条件满足时,可以通过flag的方式来多撤销一步,如下代码所示:

command = {
                        canUndo: true,
                        execute: function (context, options, isUndo) {
                                Commands = GC.Spread.Sheets.Commands;
                                if (isUndo) {
                                        Commands.undoTransaction(context, options);
                                        if(flag){
                                                context.undoManager().undo()
                                                flag = false;
                                        }
                                        return true;
                                } else {
                                        Commands.startTransaction(context, options);
                                        var sheet = context.getSheetFromName(options.sheetName);
                                        sheet.frozenRowCount(options.rowCount);
                                        Commands.endTransaction(context, options);
                                        return true;
                                }
                        }
                };

nutstore 发表于 2020-6-16 16:29:12

KevinChen 发表于 2020-6-16 15:57
在自定义command中,通常会有一个isUndo的参数来标记当前执行栈是execute还是undo的操作,那么在isUndo条件 ...

我测试了下,在 RangeChanged 的处理函数里,commandManager.execute 执行一个命令,然后 ctrl + z,在 execute 的函数中输出 console.log('execute', options, isUndo),拿到了两次执行的 isUndo 都是 false。

是 bug 吗

KevinChen 发表于 2020-6-16 18:27:24

你好,这个问题原因找到了,是由于undo clear操作也会触发RangeChanged ,在RangeChanged 中无法判断是否为undo引发的,所以导致了两次执行isUndo都是false。

是否可以考虑用条件格式实现?当指定区域被clear为空时,某些区域显示为red即可。

nutstore 发表于 2020-6-17 09:09:41

本帖最后由 nutstore 于 2020-6-17 09:11 编辑

KevinChen 发表于 2020-6-16 18:27
你好,这个问题原因找到了,是由于undo clear操作也会触发RangeChanged ,在RangeChanged 中无法判断是否为 ...
呃,这里标记为 red 是一个例子,我实际上想做的事情是 setCellType 与 setHyperLink,有没有什么其他方法能够实现随着 RangeChanged 一起撤销?
这种需求应该是比较常见的,在 RangeChanged 里做一些事情,并希望它能随着撤销一起回归原样。

KevinChen 发表于 2020-6-17 10:01:47

可以尝试重写undo redo方法,来加如自己的undo和redo逻辑。参考附件示例。

nutstore 发表于 2020-6-17 11:38:18

本帖最后由 nutstore 于 2020-6-17 11:41 编辑

KevinChen 发表于 2020-6-17 10:01
可以尝试重写undo redo方法,来加如自己的undo和redo逻辑。参考附件示例。
这种写法感觉会有很多坑,因为 flag 的发布者有很多但无法确定,消费者只有 RangeChanged 中的处理函数,它无法得知这个 flag 是否是它应该消费的。

我目前用了另一种方式,在 RangeChanged 中 commandManager.execute 上,包一层 setTimeout,目前看起来可以拿到 isUndo: true 了,这样是否会有什么隐患?

KevinChen 发表于 2020-6-17 12:19:25

nutstore 发表于 2020-6-17 11:38
这种写法感觉会有很多坑,因为 flag 的发布者有很多但无法确定,消费者只有 RangeChanged 中的处理函数, ...

正常逻辑是这样,当RangeChanged触发时,实际上clear命令还没有执行完,那么RangeChanged回调执行完成时,命令栈里是先有我们调用的命令(例如设置red),才有clear,撤销时同理。
所以用setTimeout才能避免这个问题。
目前没什么太好的办法,我提个需求,让研发在RangeChanged中加个参数,标识一下是否Undo操作,像这个事件一样:
https://demo.grapecity.com.cn/spreadjs/help/latest/content/SpreadJS~GC.Spread.Sheets.Events~RowChanged_EV.html
页: [1] 2
查看完整版本: 如何在 RangeChanged 中实现一些 canUndo 的操作