alielie
2025-10-13 e3868d4d61ded0e76fc8fe3fdacdd9e6d9113cf1
Plugin.TestBuilder/TestBuilder.xaml.cs
@@ -1,14 +1,153 @@
using HMI.Base;
using GongSolutions.Wpf.DragDrop;
using GongSolutions.Wpf.DragDrop.Utilities;
using HMI.Base;
using HMI.UI;
using Plugin.TestBuilder.Entity;
using Plugin.TestBuilder.UI;
using Plugin.TestBuilder.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Data;
namespace Plugin.TestBuilder
{
    public class TestHandler : DefaultDropHandler
    {
        /// <summary>
        /// Test the specified drop information for the right data.
        /// </summary>
        /// <param name="dropInfo">The drop information.</param>
        private bool CanDrop(IDropInfo dropInfo)
        {
            if (dropInfo?.DragInfo == null)
            {
                return false;
            }
            if (!dropInfo.IsSameDragDropContextAsSource)
            {
                return false;
            }
            // do not drop on itself
            var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter)
                                 && dropInfo.VisualTargetItem is TreeViewItem;
            if (isTreeViewItem && dropInfo.VisualTargetItem == dropInfo.DragInfo.VisualSourceItem)
            {
                return false;
            }
            if (dropInfo.TargetCollection is null)
            {
                return false;
            }
            if (ReferenceEquals(dropInfo.DragInfo.SourceCollection, dropInfo.TargetCollection))
            {
                var dragData = dropInfo.DragInfo?.Data as TreeItemData;
                var dropData = dropInfo.Data as TreeItemData;
                if (dragData == null || dropData == null)
                {
                    return false;
                }
                if (dropData.ParentItem != dragData.ParentItem)
                {
                    return false;
                }
                var targetList = dropInfo.TargetCollection.TryGetList();
                return targetList != null;
            }
            if (TestCompatibleTypes(dropInfo.TargetCollection, dropInfo.Data))
            {
                var isChildOf = IsChildOf(dropInfo.VisualTargetItem, dropInfo.DragInfo.VisualSourceItem);
                return !isChildOf;
            }
            return false;
        }
        public bool CanConvert(IDropInfo dropInfo)
        {
            bool InterfaceFilter(Type t, object o) => (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>));
            Type[] enumerableInterfaces = dropInfo.TargetCollection.GetType().FindInterfaces(InterfaceFilter, null);
            var enumerableTypes = from i in enumerableInterfaces
                                  select i.GetGenericArguments().Single();
            if (enumerableTypes.Any())
            {
                Type dataType = TypeUtilities.GetCommonBaseClass(ExtractData(dropInfo.Data));
                return dataType == typeof(FuncModel) && enumerableTypes.Any(t => t == typeof(Step));
            }
            return false;
        }
        public Step ConvertFunc2Step(FuncModel func)
        {
            return new Step
            {
                Name = func.Name
            };
        }
        public override void DragOver(IDropInfo dropInfo)
        {
            if (CanAcceptData(dropInfo))
            {
                base.DragOver(dropInfo);
            }
            else if (CanConvert(dropInfo))
            {
                // 固定Copy
                dropInfo.Effects = DragDropEffects.Copy;
                var isTreeViewItem = dropInfo.InsertPosition.HasFlag(RelativeInsertPosition.TargetItemCenter) && dropInfo.VisualTargetItem is TreeViewItem;
                dropInfo.DropTargetAdorner = isTreeViewItem ? DropTargetAdorners.Highlight : DropTargetAdorners.Insert;
            }
        }
        public override void Drop(IDropInfo dropInfo)
        {
            if (CanDrop(dropInfo))
            {
                base.Drop(dropInfo);
            }
            else if (CanConvert(dropInfo))
            {
                int insertIndex = GetInsertIndex(dropInfo);
                var destinationList = dropInfo.TargetCollection.TryGetList();
                var data = ExtractData(dropInfo.Data).OfType<object>().ToList();
                if (destinationList != null)
                {
                    var objects2Insert = new List<object>();
                    foreach (var o in data)
                    {
                        var obj2Insert = ConvertFunc2Step(o as FuncModel);
                        objects2Insert.Add(obj2Insert);
                        destinationList.Insert(insertIndex++, obj2Insert);
                        // 下方对象如果实现了 IDragItemSource 接口,会在这里调用 ItemDropped 方法,算是后置处理
                        if (obj2Insert is IDragItemSource dragItemSource)
                        {
                            dragItemSource.ItemDropped(dropInfo);
                        }
                    }
                    SelectDroppedItems(dropInfo, objects2Insert);
                }
            }
        }
    }
    /// <summary>
    /// WorkControl.xaml 的交互逻辑
    /// </summary>
@@ -16,178 +155,49 @@
    {
        public TestBuilder()
        {
            DataContext = this;
            InitializeComponent();
            Loaded += UserControl_Loaded;
        }
        public IDropTarget dropHandler { get; set; } = new TestHandler();
        private List<CanvasPosition> InitGridSize()
        private ObservableCollection<SeqData> datasource = new ObservableCollection<SeqData>() {
            new SeqData{ Name="test",Children = new ObservableCollection<SeqData>{
                new SeqData{ Name="CCC"}
            } }
        };
        public ObservableCollection<SeqData> Datasource
        {
            List<CanvasPosition> result = new List<CanvasPosition>();
            result.Add(new CanvasPosition
            {
                Left = 0,
                Top = 0,
                Width = 0.1 * ActualWidth - 2,
                Height = 0.5 * ActualHeight - 2
            });
            result.Add(new CanvasPosition
            {
                Left = 0.1 * ActualWidth + 2,
                Top = 0,
                Width = 0.5 * ActualWidth - 4,
                Height = ActualHeight,
            });
            get => datasource;
            set { Set(ref datasource, value); }
        }
            result.Add(new CanvasPosition
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Button btn = sender as Button;
            switch (btn.Name)
            {
                Left = 0.6 * ActualWidth + 2,
                Top = 0,
                Width = 0.4 * ActualWidth - 2,
                Height = 0.5 * ActualHeight - 2
            });
                case "addBtn":
                    Datasource.Add(new SeqData());
                    break;
                case "sda":
                    DataGridRow s = (DataGridRow)btn.DataContext;
                    SeqData data = s.Item as SeqData;
                    data.Children.Add(new SeqData { Name = "CCC" });
            result.Add(new CanvasPosition
            {
                Left = 0,
                Top = 0.5 * ActualHeight + 2,
                Width = 0.1 * ActualWidth - 2,
                Height = 0.5 * ActualHeight - 2
            });
            result.Add(new CanvasPosition
            {
                Left = 0.6 * ActualWidth + 2,
                Top = 0.5 * ActualHeight + 2,
                Width = 0.4 * ActualWidth - 2,
                Height = 0.5 * ActualHeight - 2
            });
            return result;
                    s.DetailsVisibility =
                        s.DetailsVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
                    break;
                default:
                    break;
            }
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            List<CanvasPosition> pos = InitGridSize();
            ProgramList programList = new ProgramList();
            InnerWindow p = new InnerWindow(pos[0])
            {
                Title = "程序列表",
                Content = programList
            };
            HandleInnerWindow(p);
            InnerWindow p1 = new InnerWindow(pos[1])
            {
                Title = "图片"
            };
            HandleInnerWindow(p1);
            SequnceList sequnceList = new SequnceList();
            programList.ProgramChanged += sequnceList.Selected_Program_Changed;
            InnerWindow p2 = new InnerWindow(pos[2])
            {
                Title = "序列",
                Content = sequnceList
            };
            HandleInnerWindow(p2);
            FunctionSetting functionSetting = new FunctionSetting();
            InnerWindow p3 = new InnerWindow(pos[3])
            {
                Title = "函数",
                Content = functionSetting
            };
            HandleInnerWindow(p3);
            StepSetting stepSetting = new StepSetting();
            InnerWindow p4 = new InnerWindow(pos[4])
            {
                Title = "单步设置",
                Content = stepSetting
            };
            HandleInnerWindow(p4);
            SizeChanged += WorkControl_SizeChanged;
            Loaded -= UserControl_Loaded;
        }
        public int CanvasChildrenCount { get; private set; } = 0;
        #region InnerWindow操作逻辑
        /// <summary>
        /// 设置InnerWindow
        /// </summary>
        /// <param name="inner"></param>
        private void HandleInnerWindow(InnerWindow inner)
        {
            inner.MinEvent += InnerWindowMin;
            inner.MaxEvent += InnerWindowMax;
            inner.ZIndexEvent += Inner_ZIndexEvent;
            inner.GotFocus += Inner_GotFocus;
            inner.AttachToCanvas(WorkArea);
            inner.Zindex = CanvasChildrenCount++;
        }
        /// <summary>
        /// InnerWindow焦点事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Inner_GotFocus(object sender, RoutedEventArgs e)
        {
            CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow));
        }
        /// <summary>
        /// InnerWindow ZIndex切换事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Inner_ZIndexEvent(object sender, EventArgs e)
        {
            CanvasHelper.SetTopZIndex(sender as InnerWindow, WorkArea, typeof(InnerWindow));
        }
        /// <summary>
        /// InnerWindow最小化事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void InnerWindowMin(object sender, System.EventArgs e)
        {
            InnerWindow inner = sender as InnerWindow;
            inner.Visibility = Visibility.Collapsed;
            HandleMinInnerWindow(inner);
        }
        /// <summary>
        /// InnerWindow最大化事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void InnerWindowMax(object sender, System.EventArgs e)
        {
            InnerWindow inner = sender as InnerWindow;
            if (inner.WindowState == WindowState.Maximized)
            {
                Canvas.SetLeft(inner, inner.canvasPosition.Left);
                Canvas.SetTop(inner, inner.canvasPosition.Top);
                inner.Width = inner.canvasPosition.Width;
                inner.Height = inner.canvasPosition.Height;
                inner.WindowState = WindowState.Normal;
            }
            else
            {
                Canvas.SetLeft(inner, 0);
                Canvas.SetTop(inner, 0);
                inner.Width = WorkArea.ActualWidth;
                inner.Height = WorkArea.ActualHeight;
                inner.WindowState = WindowState.Maximized;
            }
        }
        /// <summary>
@@ -197,70 +207,31 @@
        /// <param name="e"></param>
        private void WorkControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Size newSize = e.NewSize;
            Size previousSize = e.PreviousSize;
            double xRate = newSize.Width / previousSize.Width;
            double yRate = newSize.Height / previousSize.Height;
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(WorkArea); i++)
            {
                UIElement child = VisualTreeHelper.GetChild(WorkArea, i) as UIElement;
                Canvas.SetLeft(child, Canvas.GetLeft(child) * xRate);
                Canvas.SetTop(child, Canvas.GetTop(child) * yRate);
            }
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(WorkArea); i++)
            {
                UIElement child = VisualTreeHelper.GetChild(WorkArea, i) as UIElement;
                if (Canvas.GetLeft(child) >= newSize.Width)
                {
                    Canvas.SetLeft(child, Canvas.GetLeft(child) + newSize.Width - previousSize.Width);
                }
                if (Canvas.GetTop(child) >= newSize.Height)
                {
                    Canvas.SetTop(child, Canvas.GetTop(child) + newSize.Height - previousSize.Height);
                }
            }
        }
        #endregion
        #region 底部MinInnerWindow相关
        /// <summary>
        /// 底部MinInnerWindow处理
        /// </summary>
        /// <param name="inner"></param>
        private void HandleMinInnerWindow(InnerWindow inner)
        {
            MinInnerWindow min = new MinInnerWindow(inner);
            min.MaxEvent += MinInnerWindowMax;
            min.CloseEvent += MinInnerWindowClose;
            BottomBar.AddMinWindow(min);
        }
        /// <summary>
        /// 底部MinInnerWindow展开
        /// 树数据展示过滤
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MinInnerWindowMax(object sender, System.EventArgs e)
        private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
        {
            MinInnerWindow min = sender as MinInnerWindow;
            min.Inner.Visibility = Visibility.Visible;
            CanvasHelper.SetTopZIndex(min.Inner, WorkArea, typeof(InnerWindow));
            BottomBar.RemoveMinWindow(min);
            if (e.Item is TreeItemData data)
            {
                e.Accepted = data.IsVisible;
            }
        }
        /// <summary>
        /// 底部MinInnerWin关闭
        /// 树展开/关闭事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MinInnerWindowClose(object sender, System.EventArgs e)
        private void treeDataGrid_ExpandedChange(object sender, bool e)
        {
            MinInnerWindow min = sender as MinInnerWindow;
            BottomBar.RemoveMinWindow(min);
            CollectionViewSource cvs = this.Resources["TreeGridFilter"] as CollectionViewSource;
            cvs?.View.Refresh();
        }
        #endregion
    }
}