using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using AIStudio.Wpf.DiagramDesigner; using AIStudio.Wpf.DiagramDesigner.Algorithms; using AIStudio.Wpf.DiagramDesigner.Geometrys; using AIStudio.Wpf.DiagramDesigner.Helpers; using AIStudio.Wpf.DiagramDesigner.Models; using AIStudio.Wpf.Mind.Helpers; namespace AIStudio.Wpf.Mind.ViewModels { public class MindNode : DesignerItemViewModelBase { public MindNode(NodeLevel nodeLevel, MindType mindType = MindType.Mind) : this(null, nodeLevel, mindType) { } public MindNode(IDiagramViewModel root, NodeLevel nodeLevel, MindType mindType = MindType.Mind) : base(root) { NodeLevel = nodeLevel; MindType = mindType; InitLayout(); MindLayout.Appearance(this); } public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer) { InitLayout(); } public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType) { InitLayout(); } protected override void Init(IDiagramViewModel root) { base.Init(root); EnabledForConnection = false; AddChildCommand = new SimpleCommand(Command_Enable, ExecuteAddChildCommand); AddParentCommand = new SimpleCommand(Level_Enable, ExecuteAddParentCommand); AddPeerCommand = new SimpleCommand(Level_Enable, ExecuteAddPeerCommand); DeleteCommand = new SimpleCommand(Level_Enable, ExecuteDeleteCommand); MoveForwardCommand = new SimpleCommand(Command_Enable, ExecuteMoveForwardCommand); MoveBackCommand = new SimpleCommand(Command_Enable, ExecuteMoveBackCommand); BuildMenuOptions(); this.PropertyChanged += this.Item_PropertyChanged; } protected void InitLayout() { var layout = GlobalType.AllTypes.Where(p => typeof(IMindLayout).IsAssignableFrom(p)).FirstOrDefault(p => p.Name == MindType.ToString() + "Layout"); MindLayout = layout != null ? (System.Activator.CreateInstance(layout) as IMindLayout) : new MindLayout(); } private bool Level_Enable(object obj) { if (Command_Enable(obj) == false) return false; return NodeLevel != NodeLevel.Level1; } #region 属性 public IMindLayout MindLayout { get;set; } [Browsable(false)] private NodeLevel _nodeLevel; public NodeLevel NodeLevel { get { return _nodeLevel; } set { SetProperty(ref _nodeLevel, value); } } private MindType _mindType; public MindType MindType { get { return _mindType; } set { SetProperty(ref _mindType, value); } } private CornerRadius _cornerRadius = new CornerRadius(3); public CornerRadius CornerRadius { get { return _cornerRadius; } set { SetProperty(ref _cornerRadius, value); } } private Thickness _borderThickness = new Thickness(1); public Thickness BorderThickness { get { return _borderThickness; } set { SetProperty(ref _borderThickness, value); } } private bool _isExpanded = true; public bool IsExpanded { get { return _isExpanded; } set { SetProperty(ref _isExpanded, value); } } public SizeBase Spacing { get; set; } = new SizeBase(15, 15); private ObservableCollection _children = new ObservableCollection(); public ObservableCollection Children { get { return _children; } set { SetProperty(ref _children, value); } } public SizeBase SizeWithSpacing { get { return this.Size.Add(Spacing.Width * 2, Spacing.Height * 2); } } public SizeBase DesiredSize { get; set; } public PointBase DesiredPosition { get; set; } public PointBase Offset { get; set; } private ConnectorOrientation _connectorOrientation = ConnectorOrientation.Left; public ConnectorOrientation ConnectorOrientation { get { return _connectorOrientation; } set { SetProperty(ref _connectorOrientation, value); } } public bool LayoutUpdating { get;set; } #endregion #region 附加信息属性 private LinkInfo _linkInfo; public LinkInfo LinkInfo { get { return _linkInfo; } set { SetProperty(ref _linkInfo, value); } } private ImageInfo _imageInfo; public ImageInfo ImageInfo { get { return _imageInfo; } set { SetProperty(ref _imageInfo, value); } } private string _remark; public string Remark { get { return _remark; } set { SetProperty(ref _remark, value); } } private string _grade; public string Grade { get { return _grade; } set { SetProperty(ref _grade, value); } } private double _completionRate; public double CompletionRate { get { return _completionRate; } set { SetProperty(ref _completionRate, value); } } private ObservableCollection _tags; public ObservableCollection Tags { get { return _tags; } set { SetProperty(ref _tags, value); } } #endregion #region 命令 public SimpleCommand AddParentCommand { get; private set; } public SimpleCommand AddChildCommand { get; private set; } public SimpleCommand AddPeerCommand { get; private set; } public SimpleCommand DeleteCommand { get; private set; } public SimpleCommand MoveForwardCommand { get; private set; } public SimpleCommand MoveBackCommand { get; private set; } #endregion #region 菜单 private void BuildMenuOptions() { menuOptions = new ObservableCollection(); CinchMenuItem menuItem = new CinchMenuItem(); menuItem.Text = "下级"; menuItem.Command = AddChildCommand; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "同级"; menuItem.Command = AddPeerCommand; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "上级"; menuItem.Command = AddParentCommand; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "前移"; menuItem.Command = MoveForwardCommand; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "后移"; menuItem.Command = MoveBackCommand; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "删除"; menuItem.Command = DeleteCommand; menuOptions.Add(menuItem); } #endregion #region 操作 public void ExecuteAddChildCommand(object obj) { if (obj is MindNode node) { } else { node = new MindNode(Root, NodeLevel + 1, this.MindType) { Text = "分支主题" }; } AddChild(node); LayoutUpdated(); } public void ExecuteAddParentCommand(object obj) { if (Parent is MindNode parent) { if (obj is MindNode node) { } else { if (NodeLevel == NodeLevel.Level1) { return; } else if (NodeLevel == NodeLevel.Level2) node = new MindNode(Root, NodeLevel.Level2, this.MindType) { Text = "分支主题" }; else node = new MindNode(Root, NodeLevel.Level3, this.MindType) { Text = "分支主题" }; } parent.RemoveChild(this); int index = parent.Children.IndexOf(this); parent.AddChild(node, index + 1); node.AddChild(this); LayoutUpdated(); } } public void ExecuteAddPeerCommand(object obj) { if (Parent is MindNode parent) { if (obj is MindNode node) { } else { if (NodeLevel == NodeLevel.Level1) { return; } else if (NodeLevel == NodeLevel.Level2) node = new MindNode(Root, NodeLevel.Level2, this.MindType) { Text = "分支主题" }; else node = new MindNode(Root, NodeLevel.Level3, this.MindType) { Text = "分支主题" }; } int index = parent.Children.IndexOf(this); parent.AddChild(node, index + 1); LayoutUpdated(); } } private void ExecuteMoveBackCommand(object obj) { if (Parent is MindNode parent) { int index = parent.Children.IndexOf(this); if (index < parent.Children.Count - 1) { parent.RemoveChild(this); parent.AddChild(this, index + 1); LayoutUpdated(); } } } private void ExecuteMoveForwardCommand(object obj) { if (Parent is MindNode parent) { int index = parent.Children.IndexOf(this); if (index > 0) { parent.RemoveChild(this); parent.AddChild(this, index - 1); LayoutUpdated(); } } } private void ExecuteDeleteCommand(object obj) { if (Parent is MindNode parent) { parent.RemoveChild(this, true); LayoutUpdated(); } } public void AddChild(MindNode item, int index = -1) { if (this.NodeLevel == NodeLevel.Level1) { item.NodeLevel = NodeLevel.Level2; } else { item.NodeLevel = NodeLevel.Level3; } if (index >= 0) { this.Children.Insert(index, item); } else { this.Children.Add(item); } item.Parent = this; Root?.DirectAddItemCommand.Execute(item); ConnectionViewModel connector = MindLayout?.GetConnectionViewModel(this, item); Root?.DirectAddItemCommand.Execute(connector); Root?.ClearSelectedItemsCommand.Execute(new SelectableDesignerItemViewModelBase[] { connector }); Root?.BringForwardCommand.Execute(new DesignerItemViewModelBase[] { item }); } public void RemoveChild(MindNode item, bool removeall = false) { item.PropertyChanged -= Item_PropertyChanged; this.Children.Remove(item); var connectors = Root?.Items.OfType().Where(p => p.SinkConnectorInfoFully?.DataItem == item).ToList(); Root?.DirectRemoveItemCommand.Execute(item); Root?.DirectRemoveItemCommand.Execute(connectors); if (removeall) { if (item.Children?.Count > 0) { foreach (var child in item.Children.ToList()) { item.RemoveChild(child); } } } } #endregion private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (GetLevel1Node()?.LayoutUpdating == true) return; switch (e.PropertyName) { case nameof(IsExpanded): case nameof(ItemWidth): case nameof(ItemHeight): { LayoutUpdated(); break; } case nameof(NodeLevel): MindLayout?.Appearance(this); break; //case nameof(MindType): // if (NodeLevel == NodeLevel.Level1) // { // MindLayout?.Appearance(this); // LayoutUpdated(); // } // else // { // GetLevel1Node().MindType = MindType; // } // break; case nameof(Left): { if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs) { if (NodeLevel == NodeLevel.Level1) { LayoutUpdated(); } else { UpdateOffsetX((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue); LayoutUpdated(); } } break; } case nameof(Top): { if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs) { if (NodeLevel == NodeLevel.Level1) { LayoutUpdated(); } else { UpdateOffsetY((double)valuePropertyChangedEventArgs.OldValue, (double)valuePropertyChangedEventArgs.NewValue); LayoutUpdated(); } } break; } case nameof(Text): { ItemWidth = Math.Max(ItemWidth, GetTextDisplayWidthHelper.GetTextDisplayWidth(Text, new FontFamily(FontViewModel.FontFamily), FontViewModel.FontStyle, FontViewModel.FontWeight, FontViewModel.FontStretch, FontViewModel.FontSize) + 30); break; } } } #region 布局相关 public MindNode GetLevel1Node() { var node = this; while (node.Parent is MindNode mindNode) { node = mindNode; } return node; } public MindNode GetLevel2Node() { var node = this; while (node.Parent is MindNode mindNode && mindNode.NodeLevel == NodeLevel.Level2) { node = mindNode; } return node; } protected void UpdateOffsetX(double oldvalue, double newvalue) { Offset += new VectorBase(newvalue - oldvalue, 0); } protected void UpdateOffsetY(double oldvalue, double newvalue) { Offset += new VectorBase(0, newvalue - oldvalue); } public void LayoutUpdated() { MindLayout?.LayoutUpdated(GetLevel1Node()); } #endregion } public class LinkInfo : BindableBase { private string _url; public string Url { get { return _url; } set { SetProperty(ref _url, value); } } private string _text; public string Text { get { return _text; } set { SetProperty(ref _text, value); } } } public class ImageInfo : BindableBase { private string _url; public string Url { get { return _url; } set { SetProperty(ref _url, value); } } private string _text; public string Text { get { return _text; } set { SetProperty(ref _text, value); } } } }