重新设计了创建连线时的逻辑,能够预览连接成功后的外观样式

This commit is contained in:
fengjiayi
2025-01-04 22:20:01 +08:00
parent 665a722f68
commit 702af587f9
20 changed files with 1040 additions and 277 deletions

View File

@@ -15,6 +15,7 @@ namespace Serein.Workbench.Avalonia.Custom.Node.ViewModels
[ObservableProperty]
private SingleActionNode? nodeMoel;
internal override NodeModelBase NodeModelBase
{ get => NodeMoel ?? throw new NotImplementedException(); set => NodeMoel = (SingleActionNode)value; }

View File

@@ -1,5 +1,10 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Avalonia.Controls;
using Avalonia.Media;
using CommunityToolkit.Mvvm.ComponentModel;
using Serein.Library;
using Serein.Workbench.Avalonia.Api;
using Serein.Workbench.Avalonia.Custom.Node.Views;
using Serein.Workbench.Avalonia.Custom.Views;
using Serein.Workbench.Avalonia.ViewModels;
using System;
using System.Collections.Generic;
@@ -15,5 +20,117 @@ namespace Serein.Workbench.Avalonia.Custom.Node.ViewModels
internal abstract class NodeViewModelBase : ViewModelBase
{
internal abstract NodeModelBase NodeModelBase { get; set; }
private Canvas NodeCanvas;
/// <summary>
/// 如果该节点放置在了某个容器节点,就会记录这个容器节点
/// </summary>
private INodeContainerControl NodeContainerControl { get; }
public NodeModelBase NodeModel { get; set; }
/// <summary>
/// 记录与该节点控件有关的所有连接
/// </summary>
private readonly List<NodeConnectionLineView> connectionControls = new List<NodeConnectionLineView>();
//public NodeControlViewModelBase ViewModel { get; set; }
public void SetNodeModel(NodeModelBase nodeModel) => this.NodeModel = nodeModel;
/// <summary>
/// 添加与该节点有关的连接后,记录下来
/// </summary>
/// <param name="connection"></param>
public void AddCnnection(NodeConnectionLineView connection)
{
connectionControls.Add(connection);
}
/// <summary>
/// 删除了连接之后,还需要从节点中的记录移除
/// </summary>
/// <param name="connection"></param>
public void RemoveConnection(NodeConnectionLineView connection)
{
connectionControls.Remove(connection);
//connection.Remote();
}
/// <summary>
/// 删除所有连接
/// </summary>
public void RemoveAllConection()
{
foreach (var connection in this.connectionControls)
{
//connection.Remote();
}
}
/// <summary>
/// 更新与该节点有关的数据
/// </summary>
public void UpdateLocationConnections()
{
foreach (var connection in this.connectionControls)
{
//connection.RefreshLine(); // 主动更新连线位置
}
}
/// <summary>
/// 设置绑定:
/// Canvas.X and Y 画布位置
/// </summary>
public void SetBinding()
{
/* // 绑定 Canvas.Left
Binding leftBinding = new Binding("X")
{
Source = ViewModel.NodeModel.Position, // 如果 X 属性在当前 DataContext 中
Mode = BindingMode.TwoWay
};
BindingOperations.Apply(this, Canvas.LeftProperty, leftBinding);
// 绑定 Canvas.Top
Binding topBinding = new Binding("Y")
{
Source = ViewModel.NodeModel.Position, // 如果 Y 属性在当前 DataContext 中
Mode = BindingMode.TwoWay
};
BindingOperations.SetBinding(this, Canvas.TopProperty, topBinding);*/
}
/// <summary>
/// 穿透视觉树获取指定类型的第一个元素
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="parent"></param>
/// <returns></returns>
//protected T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
//{
// for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
// {
// var child = VisualTreeHelper.GetChild(parent, i);
// if (child is T typedChild)
// {
// return typedChild;
// }
// var childOfChild = FindVisualChild<T>(child);
// if (childOfChild != null)
// {
// return childOfChild;
// }
// }
// return null;
//}
}
}

View File

@@ -1,15 +1,16 @@
<UserControl xmlns="https://github.com/avaloniaui"
<local:NodeControlBase xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="100"
x:Class="Serein.Workbench.Avalonia.Custom.Node.Views.ActionNodeView"
xmlns:vm="clr-namespace:Serein.Workbench.Avalonia.Custom.Node.ViewModels"
xmlns:local="clr-namespace:Serein.Workbench.Avalonia.Custom.Node.Views"
xmlns:baselibrary="clr-namespace:Serein.Library;assembly=Serein.Library"
xmlns:cv="clr-namespace:Serein.Workbench.Avalonia.Custom.Views"
xmlns:dtp="using:Serein.Workbench.Avalonia.DataTemplates"
Background="#C6EEF7"
Background="#C6EEF7"
x:DataType="vm:ActionNodeViewModel">
<Design.DataContext>
<vm:ActionNodeViewModel />
@@ -17,7 +18,7 @@
<Border>
<Grid RowDefinitions="25,*,*,*,*">
<!--调用控制点,方法名称,下一个方法调用控制点-->
<Grid x:Name="HeaderGrid" Grid.Row="0" ColumnDefinitions="auto,*,auto" VerticalAlignment="Center">
<cv:NodeJunctionView Grid.Column="0" JunctionType="Execute" MyNode="{Binding NodeMoel}" Width="30" Height="15" Margin="4,0,2,0" />
@@ -42,8 +43,8 @@
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</Border>
</UserControl>
</local:NodeControlBase>

View File

@@ -2,25 +2,22 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Serein.Library;
using Serein.NodeFlow.Model;
using Serein.Workbench.Avalonia.Api;
using Serein.Workbench.Avalonia.Custom.Node.ViewModels;
namespace Serein.Workbench.Avalonia.Custom.Node.Views;
public partial class ActionNodeView : UserControl, INodeControl
public partial class ActionNodeView : NodeControlBase
{
private ActionNodeViewModel _vm;
public ActionNodeView()
{
InitializeComponent();
_vm = App.GetService<ActionNodeViewModel>();
DataContext = _vm;
//_vm = App.GetService<ActionNodeViewModel>();
//DataContext = _vm;
}
NodeModelBase INodeControl.NodeModelBase => _vm.NodeModelBase ?? throw new System.NotImplementedException(); // ¶¯×÷½Úµã
void INodeControl.SetNodeModel(NodeModelBase nodeModel) // ¶¯×÷½Úµã
{
_vm.NodeModelBase = nodeModel;
}
}

View File

@@ -0,0 +1,57 @@
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Media;
using Serein.Library;
using Serein.Workbench.Avalonia.Api;
using Serein.Workbench.Avalonia.Custom.Views;
using Serein.Workbench.Avalonia.Model;
using Serein.Workbench.Avalonia.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Workbench.Avalonia.Custom.Node.Views
{
public class NodeControlBase : UserControl
{
protected NodeControlBase()
{
this.Background = Brushes.Transparent;
}
/// <summary>
/// 放置在某个节点容器中
/// </summary>
public void PlaceToContainer(INodeContainerControl nodeContainerControl)
{
//this.nodeContainerControl = nodeContainerControl;
//NodeCanvas.Children.Remove(this); // 临时从画布上移除
//var result = nodeContainerControl.PlaceNode(this);
//if (!result) // 检查是否放置成功,如果不成功,需要重新添加回来
//{
// NodeCanvas.Children.Add(this); // 从画布上移除
//}
}
/// <summary>
/// 从某个节点容器取出
/// </summary>
public void TakeOutContainer()
{
//var result = nodeContainerControl.TakeOutNode(this); // 从控件取出
//if (result) // 移除成功时才添加到画布上
//{
// NodeCanvas.Children.Add(this); // 重新添加到画布上
// if (nodeContainerControl is NodeControlBase containerControl)
// {
// NodeModel.Position.X = NodeModel.Position.X + containerControl.Width + 10;
// NodeModel.Position.Y = NodeModel.Position.Y;
// }
//}
}
}
}