用Wpf做一个Block编程画板(续5-Diagram画板,仿Scratch)

发布时间 2023-07-02 12:17:04作者: 竹天笑

先上一张效果动图,本次更新主要仿照Scratch,目前仅完成拖拽部分,逻辑部分后续完善。

同样老规矩,先上源码地址:https://gitee.com/akwkevin/aistudio.-wpf.-diagram

本次扩展主要内容: 1.Block模块,入口在文件新建下。 2.简易Block的使用: 3.仿Scratch的Block的使用(完成图鉴,准备编写逻辑):

核心逻辑在源码的BlockDesignerItemViewModelHelper中:

 public static void FinishNearBlock(this IBlockDiagramViewModel diagramViewModel, List<BlockDesignerItemViewModel> blocks)
{
    if (diagramViewModel == null)
        return;

    if (blocks.Any())
    {
        var links = BlockDesignerItemTempLink.Build(blocks);

        blocks.ToList().ForEach(p => {
            p.ZIndex = diagramViewModel.Items.Where(q => q.ZIndex != int.MaxValue).Any() ? diagramViewModel.Items.Where(q => q.ZIndex != int.MaxValue).Max(r => r.ZIndex) + 1 : 0;
        });

        foreach (BlockDesignerItemTempLink item in links)
        {
            var container = diagramViewModel.FindNearContainerToAttachTo(item);
            if (container != null)
            {
                int index = 0;
                var child = container.Children.FirstOrDefault(p => p.Connectors.Any(q => q.BeAttachTo == true));
                if (child != null)
                {
                    index = container.Children.IndexOf(child);
                    if (child.RightConnector?.BeAttachTo == true || child.BottomConnector?.BeAttachTo == true)
                    {
                        index++;
                    }
                }
                diagramViewModel.InsertChildCommand.Execute(new BlockContainerPara() { Item = container.DataItem, Child = item.Items.FirstOrDefault(), Container = container, Index = index });
                continue;
            }

            var portTuple = diagramViewModel.FindNearPortToAttachTo(item);
            var portParent = portTuple.Item1;
            var portNext = portTuple.Item2;

            if (portParent != null)
            {
                diagramViewModel.AddNextCommand.Execute(new BlockNextPara() { Item = portParent.DataItem as BlockDesignerItemViewModel, Next = item.Items.FirstOrDefault() });
                portParent.BeAttachTo = false;
                portParent.DisableAttachTo = false;
            }
            else
            {
                if (item.Items.FirstOrDefault().Parent != null)
                {
                    diagramViewModel.RemoveNextCommand.Execute(new BlockNextPara() { Item = item.Items.FirstOrDefault().Parent as BlockDesignerItemViewModel, Next = (item.Items.FirstOrDefault().Parent as BlockDesignerItemViewModel)?.Next });
                }
            }

            if (portNext != null)
            {
                diagramViewModel.AddNextCommand.Execute(new BlockNextPara() { Item = item.Items.LastOrDefault(), Next = portNext.DataItem as BlockDesignerItemViewModel });
                portNext.BeAttachTo = false;
                portNext.DisableAttachTo = false;
            }
            else
            {
                if (item.Items.LastOrDefault().Next != null)
                {
                    diagramViewModel.RemoveNextCommand.Execute(new BlockNextPara() { Item = item.Items.LastOrDefault(), Next = item.Items.LastOrDefault()?.Next });
                }
            }
        }

        diagramViewModel.ClearAttachTo();
    }
}

大致原理是:判断Block是否被拖入某个容器,如果没有,是否挨着另外一个Block块。

后续更新:后续会完善Block的逻辑部分,尽情期待。