前言
我认为 Diagram
是 Syncfusion
中首屈一指的优秀控件!最近在写一个工作流引擎,前端界面就用的是Diagram
,接下来就来看一看。
Diagram的事件
查看 SfDiagram的属性,如果想实现什么事件,就看这些Command结尾的。
这里,我想看看 双击Diagram中的一个节点,能触发什么事件。
于是,我找到了,ItemDoubleTappedCommand!
我使用 prism 的方式 进行绑定:
ItemDoubleTappedCommand="{Binding ItemDoubleTappedCmd}"
其实这个并不是一个事件(并不能双击一下自动产生一个事件),而是封装好的命令,就是给mvvm用的, 看看源码就知道:
//
// 摘要:
// Gets or sets the itemdoubletappedcommand to invoke when double
// click on the diagram
// or diagram elements.
public ICommand ItemDoubleTappedCommand
{
get
{
return (ICommand)GetValue(ItemDoubleTappedCommandProperty);
}
set
{
SetValue(ItemDoubleTappedCommandProperty, value);
}
}
注意,这个命令,不管是双击,diagram或者是其中的元素,都会触发该事件。并且双击节点的不同位置,触发传递的参数还会有所不同,后面介绍。
ItemDoubleTappedCmd = new DelegateCommand<ItemDoubleTappedEventArgs>((args) => {
try
{
//注意这里点的位置不同,返回的参数不一样,但是都可以获取到Node!
VisualNode node = args.OriginalSource as VisualNode;
if (node == null)
{
node = args.Item as VisualNode;
if (node == null)
{
return;
}
}
});
后台实现命令如上。
如果点击在节点的说明上,args的值如下:
此时,node的相关信息包含在,OriginalSource里面。
如果点击没在节点的说明上(说明的周边),args的值如下:
此时,node的相关信息包含在,Item里面。
如果此时你没点任何节点,而是双击在了空白处!
此时 Item里面包含的是 Diagram 对象。
这里讲的是 ItemDoubleTappedCommand 双击的事件,那么其他的,请自行测试!
如何通过node拿到Diagram
通过上面那个事件,我们可以拿到当前被双击的Node对象,那么如何通过Node拿到Diagram 对象呢?
//双击触发节点
ItemDoubleTappedCmd = new DelegateCommand<ItemDoubleTappedEventArgs>(async(args) => {
try
{
//注意这里点的位置不同,返回的参数不一样,但是都可以获取到Node!
VisualNode node = args.OriginalSource as VisualNode;
if (node == null)
{
node = args.Item as VisualNode;
if (node == null)
{
return;
}
}
#region 这里开始拿对象
//-- 这里演示了,如何通过node得到diagramcontrol!!!!
var a = node.Info as IGroupableInfo;
var manager = a.Graph.CommandManager;
var diagramcontrol = manager.View as SfDiagram;
#endregion
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
});
通过Node拿到Diagram确实废了我一番功夫,有很多类是对外隐藏的,所以没办法直接进行强制转换,Diagram的相关代码中有很多,先转为接口,才能拿到某些属性的例子。
比如
public NodeViewModel FindNextNode(NodeViewModel node)
{
var out_nodes = (node.Info as INodeInfo).OutNeighbors as IEnumerable<object>;
if (out_nodes != null && (out_nodes).Count() > 0)
{
foreach (NodeViewModel outnode in out_nodes)
{
if (node != outnode)
{
return outnode;
}
}
}
return null;
}
我们需要多熟悉他们的数据结构,并熟悉这种写法。
命令取消
Diagram 封装了很多自带的命令,比如对齐,旋转,复制,剪切,撤回,全选,等等,一个48个,如下图:,
这些命令都是开箱即用的,非常方便! 但是有的额时候,我确是想去掉某些命令。
比如,它自带的编辑命令,当我们双击的时候,会触发编辑命令,节点会进入编辑状态,这个是我不想要的,(我想实现弹窗)
那如何取消呢?我们继续完成代码!
//双击触发节点
ItemDoubleTappedCmd = new DelegateCommand<ItemDoubleTappedEventArgs>(async(args) => {
try
{
//注意这里点的位置不同,返回的参数不一样,但是都可以获取到Node!
VisualNode node = args.OriginalSource as VisualNode;
if (node == null)
{
node = args.Item as VisualNode;
if (node == null)
{
return;
}
}
#region 这里用来取消双击导致的编辑这个副作用, Cancel命令是一个多功能命令,可以根据上下文执行不同的操作,如停止编辑注释并接受当前的编辑结果,或者清除图表元素的选择和键盘焦点。
await Task.Delay(50);
//-- 这里演示了,如何通过node得到diagramcontrol!!!!
var a = node.Info as IGroupableInfo;
var manager = a.Graph.CommandManager;
var diagramcontrol = manager.View as SfDiagram;
// 得到graphinfo
IGraphInfo graphinfo = diagramcontrol.Info as IGraphInfo;
// 命令取消!
graphinfo.Commands.Cancel.Execute(null);
#endregion
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
});
那效果如下,明显有个取消的过程:
这里,你会不会好奇,代码里面为啥,加了一个异步?await Task.Delay(50);
你可以尝试把这个异步去掉,你会发现没有效果!
其实这段代码必须,写道//双击触发节点
ItemDoubleTappedCmd = new DelegateCommand(async(args) => {
这个函数外面才会有效,就是如果这个函数没退出,直接取消是没有用的!
我遇到过,很多情况都是这样。
不过,我发现了一个更优雅的写法,就是这个异步。
主线程,遇到这个await Task.Delay(50); 其实就会挑走,从而出了这个函数。
当50毫秒时间一到,就会又调回来,这样就和写道外面是一样的了,于是就生效了!!!!
是不是又学了一招呢?(手动狗头~~)