From 79f4896fbd53e9cb30893d59c7c14c09c06565e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=89=BE=E7=AB=B9?= Date: Sun, 5 Mar 2023 21:30:53 +0800 Subject: [PATCH] Mind Editoe --- .../ViewModels/MindViewModel.cs | 45 +- .../ViewModels/PageViewModel.cs | 12 +- .../MainWindow.xaml | 2 +- .../Views/FlowchartEditorView.xaml | 16 +- .../Views/MindEditorView.xaml | 12 +- .../Helpers/DoCommandManager.cs | 120 ++- .../Helpers/IEnumerableExtensions.cs | 85 +++ .../Routers/Routers.Orthogonal.cs | 5 +- .../Styles/TextBox.xaml | 6 +- .../Styles/ZoomBox.xaml | 6 +- .../Themes/ConnectorItem.xaml | 12 +- .../Themes/DesignerItem.xaml | 38 +- .../Themes/Generic.xaml | 7 +- .../Themes/Style.xaml | 1 - .../UserControls/ConnectorContainer.xaml | 2 +- .../UserControls/DiagramControl.xaml | 184 ++--- .../UserControls/LineControl.xaml | 14 +- .../UserControls/TextControl.xaml | 10 +- .../UserControls/TextControl.xaml.cs | 16 +- .../BaseViewModel/ConnectionViewModel.cs | 16 +- .../BaseViewModel/DiagramViewModel.cs | 59 +- .../ViewModels/IDiagramViewModel.cs | 8 + .../DiagramDataExtention.cs | 66 +- .../Controls/DropDownButton.xaml | 171 +++++ .../Controls/DropDownButton.xaml.cs | 685 ++++++++++++++++++ AIStudio.Wpf.Mind/Controls/MindEditor.xaml | 2 +- AIStudio.Wpf.Mind/Controls/MindEditor.xaml.cs | 19 +- .../Controls/ToolBoxControl.xaml | 148 +++- AIStudio.Wpf.Mind/Helpers/DirectoryLayout.cs | 8 +- AIStudio.Wpf.Mind/Helpers/FishBoneLayout.cs | 8 +- AIStudio.Wpf.Mind/Helpers/LogicalLayout.cs | 6 +- AIStudio.Wpf.Mind/Helpers/MindLayout.cs | 14 +- .../Helpers/OrganizationalLayout.cs | 7 +- .../Styles/Button.xaml | 8 +- AIStudio.Wpf.Mind/Styles/ContextMenu.xaml | 61 ++ AIStudio.Wpf.Mind/Themes/Generic.xaml | 1 + AIStudio.Wpf.Mind/Themes/MindNode.xaml | 48 +- .../ViewModels/IMindDiagramViewModel.cs | 57 ++ .../ViewModels/MindDiagramViewModel.cs | 382 ++++++++++ AIStudio.Wpf.Mind/ViewModels/MindNode.cs | 205 ++---- Directory.Build.Props | 2 +- 41 files changed, 2090 insertions(+), 484 deletions(-) create mode 100644 AIStudio.Wpf.DiagramDesigner/Helpers/IEnumerableExtensions.cs create mode 100644 AIStudio.Wpf.Mind/Controls/DropDownButton.xaml create mode 100644 AIStudio.Wpf.Mind/Controls/DropDownButton.xaml.cs rename {AIStudio.Wpf.DiagramDesigner => AIStudio.Wpf.Mind}/Styles/Button.xaml (91%) create mode 100644 AIStudio.Wpf.Mind/Styles/ContextMenu.xaml create mode 100644 AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs create mode 100644 AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs diff --git a/AIStudio.Wpf.DiagramApp/ViewModels/MindViewModel.cs b/AIStudio.Wpf.DiagramApp/ViewModels/MindViewModel.cs index 09a0434..47c5cae 100644 --- a/AIStudio.Wpf.DiagramApp/ViewModels/MindViewModel.cs +++ b/AIStudio.Wpf.DiagramApp/ViewModels/MindViewModel.cs @@ -32,27 +32,18 @@ namespace AIStudio.Wpf.Flowchart DiagramViewModel.GridCellSize = new Size(100, 100); DiagramViewModel.ShowGrid= false; - _service.DrawModeViewModel.LineDrawMode = DrawMode.ConnectingLineSmooth; DiagramViewModel.AllowDrop = false; } - - private MindType _mindType = Mind.MindType.FishBone; - public MindType MindType - { - get - { - return _mindType; - } - set - { - SetProperty(ref _mindType, value); - } - } - protected override void Init() { - base.Init(); + DiagramViewModels = new ObservableCollection() + { + new MindDiagramViewModel(){Name= "页-1", DiagramType = DiagramType}, + }; + DiagramViewModel = DiagramViewModels.FirstOrDefault(); + + InitDiagramViewModel(); MindNode level1node = new MindNode(DiagramViewModel, Mind.NodeLevel.Level1, MindType) { Text = "思维导图" }; DiagramViewModel.DirectAddItemCommand.Execute(level1node); @@ -76,12 +67,28 @@ namespace AIStudio.Wpf.Flowchart MindNode level2node1_3 = new MindNode(DiagramViewModel, Mind.NodeLevel.Level2, MindType) { Text = "分支主题3" }; level1node.AddChild(level2node1_3); - DiagramViewModel.ClearSelectedItemsCommand.Execute(null); + DiagramViewModel.ClearSelectedItemsCommand.Execute(null); level1node.LayoutUpdated(); - - } + + private MindType _mindType = Mind.MindType.Organizational; + public MindType MindType + { + get + { + return _mindType; + } + set + { + if (SetProperty(ref _mindType, value)) + { + //DiagramViewModel as MindDiagramViewModel + } + } + } + + public override void Dispose() { base.Dispose(); diff --git a/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs b/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs index 3ef6179..6226992 100644 --- a/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs +++ b/AIStudio.Wpf.DiagramApp/ViewModels/PageViewModel.cs @@ -31,12 +31,6 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels Status = status; DiagramType = diagramType; - DiagramViewModels = new ObservableCollection() - { - new DiagramViewModel(){Name= "页-1", DiagramType = diagramType}, - }; - DiagramViewModel = DiagramViewModels.FirstOrDefault(); - Init(); } public PageViewModel(string filename) @@ -61,6 +55,12 @@ namespace AIStudio.Wpf.DiagramApp.ViewModels protected virtual void Init() { + DiagramViewModels = new ObservableCollection() + { + new DiagramViewModel(){Name= "页-1", DiagramType = DiagramType}, + }; + DiagramViewModel = DiagramViewModels.FirstOrDefault(); + InitDiagramViewModel(); } diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/MainWindow.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/MainWindow.xaml index 0cd7ab3..5008c8e 100644 --- a/AIStudio.Wpf.DiagramDesigner.Demo/MainWindow.xaml +++ b/AIStudio.Wpf.DiagramDesigner.Demo/MainWindow.xaml @@ -9,7 +9,7 @@ Icon="A.ico" Identifier="RootWindow" Style="{StaticResource AIStudio.Styles.WindowBase}" - Height="450" Width="800"> + Height="600" Width="850"> diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/FlowchartEditorView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/FlowchartEditorView.xaml index 424ada0..99d74f5 100644 --- a/AIStudio.Wpf.DiagramDesigner.Demo/Views/FlowchartEditorView.xaml +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/FlowchartEditorView.xaml @@ -16,10 +16,17 @@ + - - + + + + + @@ -40,11 +47,6 @@ Height="50"/> - - diff --git a/AIStudio.Wpf.DiagramDesigner.Demo/Views/MindEditorView.xaml b/AIStudio.Wpf.DiagramDesigner.Demo/Views/MindEditorView.xaml index a103e68..9b828a5 100644 --- a/AIStudio.Wpf.DiagramDesigner.Demo/Views/MindEditorView.xaml +++ b/AIStudio.Wpf.DiagramDesigner.Demo/Views/MindEditorView.xaml @@ -16,10 +16,14 @@ + - - + + + + @@ -40,10 +44,6 @@ Height="50"/> - - - diff --git a/AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs b/AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs index 96d25c6..3417918 100644 --- a/AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs +++ b/AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace AIStudio.Wpf.DiagramDesigner { - class DoCommandManager + public class DoCommandManager { #region Command定义 public class Command @@ -24,9 +24,18 @@ namespace AIStudio.Wpf.DiagramDesigner this.clearAction = clearAction; } - internal void Do() { action(); } - internal void UnDo() { unDoAction(); } - internal void Clear() { if (clearAction != null) clearAction(); } + internal void Do() + { + action(); + } + internal void UnDo() + { + unDoAction(); + } + internal void Clear() + { + if (clearAction != null) clearAction(); + } public override string ToString() { @@ -35,35 +44,57 @@ namespace AIStudio.Wpf.DiagramDesigner } #endregion - public Stack ReDoActionStack { get; private set; } - public Stack UnDoActionStack { get; private set; } + public Stack ReDoActionStack + { + get; private set; + } + public Stack UnDoActionStack + { + get; private set; + } public int Capacity { get; set; } = 10; public DoCommandManager() + { + Init(); + } + + public void Init() { ReDoActionStack = new Stack(); UnDoActionStack = new Stack(); } + private bool _undoing; public void DoNewCommand(string name, Action action, Action unDoAction, Action clearAction = null, bool doit = true) { - if (UnDoActionStack.Count >= Capacity) - { - //清理 - var clear = UnDoActionStack.LastOrDefault(); - clear.Clear(); - - UnDoActionStack = new Stack(UnDoActionStack.Take(Capacity - 1).Reverse()); - } - - var cmd = new Command(name, action, unDoAction, clearAction); - UnDoActionStack.Push(cmd); - - ReDoActionStack.Clear(); - if (doit) + if (_undoing == true) return; + try { - cmd.Do(); + _undoing = true; + + if (UnDoActionStack.Count >= Capacity) + { + //清理 + var clear = UnDoActionStack.LastOrDefault(); + clear.Clear(); + + UnDoActionStack = new Stack(UnDoActionStack.Take(Capacity - 1).Reverse()); + } + + var cmd = new Command(name, action, unDoAction, clearAction); + UnDoActionStack.Push(cmd); + + ReDoActionStack.Clear(); + if (doit) + { + cmd.Do(); + } + } + finally + { + _undoing = false; } } @@ -72,9 +103,19 @@ namespace AIStudio.Wpf.DiagramDesigner if (!CanUnDo) return; - var cmd = UnDoActionStack.Pop(); - ReDoActionStack.Push(cmd); - cmd.UnDo(); + if (_undoing == true) return; + try + { + _undoing = true; + + var cmd = UnDoActionStack.Pop(); + ReDoActionStack.Push(cmd); + cmd.UnDo(); + } + finally + { + _undoing = false; + } } public void ReDo() @@ -82,13 +123,34 @@ namespace AIStudio.Wpf.DiagramDesigner if (!CanReDo) return; - var cmd = ReDoActionStack.Pop(); - UnDoActionStack.Push(cmd); - cmd.Do(); + if (_undoing == true) return; + try + { + _undoing = true; + var cmd = ReDoActionStack.Pop(); + UnDoActionStack.Push(cmd); + cmd.Do(); + } + finally + { + _undoing = false; + } } - public bool CanUnDo { get { return UnDoActionStack.Count != 0; } } - public bool CanReDo { get { return ReDoActionStack.Count != 0; } } + public bool CanUnDo + { + get + { + return UnDoActionStack.Count != 0; + } + } + public bool CanReDo + { + get + { + return ReDoActionStack.Count != 0; + } + } //public IEnumerable Actions { get { return ReDoActionStack.Reverse().Concat(UnDoActionStack); } } } } diff --git a/AIStudio.Wpf.DiagramDesigner/Helpers/IEnumerableExtensions.cs b/AIStudio.Wpf.DiagramDesigner/Helpers/IEnumerableExtensions.cs new file mode 100644 index 0000000..1bc60af --- /dev/null +++ b/AIStudio.Wpf.DiagramDesigner/Helpers/IEnumerableExtensions.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AIStudio.Wpf.DiagramDesigner.Helpers +{ + public static class IEnumerableExtensions + { + /// + /// Invokes a transform function on each element of a sequence and returns the minimum Double value + /// if the sequence is not empty; otherwise returns the specified default value. + /// + /// The type of the elements of source. + /// A sequence of values to determine the minimum value of. + /// A transform function to apply to each element. + /// The default value. + /// The minimum value in the sequence or default value if sequence is empty. + public static double MinOrDefault(this IEnumerable source, Func selector, double defaultValue=default(double)) + { + if (source.Any()) + return source.Min(selector); + + return defaultValue; + } + + /// + /// Invokes a transform function on each element of a sequence and returns the maximum Double value + /// if the sequence is not empty; otherwise returns the specified default value. + /// + /// The type of the elements of source. + /// A sequence of values to determine the maximum value of. + /// A transform function to apply to each element. + /// The default value. + /// The maximum value in the sequence or default value if sequence is empty. + public static double MaxOrDefault(this IEnumerable source, Func selector, double defaultValue=default(double)) + { + if (source.Any()) + return source.Max(selector); + + return defaultValue; + } + + + public static TResult MinOrDefault(this IEnumerable source, Func selector, TResult defaultValue) + { + if (source.Any()) + { + return source.Min(selector); + } + return defaultValue; + + } + + + public static TResult MaxOrDefault(this IEnumerable source, Func selector, TResult defaultValue) + { + if (source.Any()) + { + return source.Max(selector); + } + return defaultValue; + } + + /// + /// Invokes a transform function on each element of a sequence and returns the minimum Double value + /// if the sequence is not empty; otherwise returns the specified default value. + /// + /// The type of the elements of source. + /// A sequence of values to determine the minimum value of. + /// A transform function to apply to each element. + /// The default value. + /// The minimum value in the sequence or default value if sequence is empty. + public static double SumOrDefault(this IEnumerable source, Func selector, double defaultValue=default(double)) + { + if (source.Any()) + return source.Sum(selector); + + return defaultValue; + } + + + } +} diff --git a/AIStudio.Wpf.DiagramDesigner/Routers/Routers.Orthogonal.cs b/AIStudio.Wpf.DiagramDesigner/Routers/Routers.Orthogonal.cs index ddde2d8..ba814a5 100644 --- a/AIStudio.Wpf.DiagramDesigner/Routers/Routers.Orthogonal.cs +++ b/AIStudio.Wpf.DiagramDesigner/Routers/Routers.Orthogonal.cs @@ -540,9 +540,10 @@ namespace AIStudio.Wpf.DiagramDesigner var nodeB = Get(b); if (nodeA == null || nodeB == null) - return; + return; - nodeA.AdjacentNodes.Add(nodeB, a.DistanceTo(b)); + if (!nodeA.AdjacentNodes.ContainsKey(nodeB)) + nodeA.AdjacentNodes.Add(nodeB, a.DistanceTo(b)); } public bool Has(PointBase p) diff --git a/AIStudio.Wpf.DiagramDesigner/Styles/TextBox.xaml b/AIStudio.Wpf.DiagramDesigner/Styles/TextBox.xaml index 78e5a8d..6e32127 100644 --- a/AIStudio.Wpf.DiagramDesigner/Styles/TextBox.xaml +++ b/AIStudio.Wpf.DiagramDesigner/Styles/TextBox.xaml @@ -1,6 +1,6 @@  + xmlns:dd="clr-namespace:AIStudio.Wpf.DiagramDesigner"> - - - - + + - - + + - + @@ -525,21 +525,21 @@ - + - - + + - - + + - + @@ -572,9 +572,9 @@ Value="{Binding Left}" /> - - @@ -608,13 +608,13 @@ VerticalAlignment="Stretch" Content="{TemplateBinding Content}" /> - - + + - + - - + + @@ -652,9 +652,9 @@ Value="{Binding Left}" /> - - @@ -685,15 +685,15 @@ - - + + - + - - + + @@ -733,7 +733,7 @@ Value="{Binding Left}" /> - @@ -746,11 +746,11 @@ - + - + - - @@ -799,12 +799,12 @@ - + Visibility="{Binding Path=ShowConnectors, Converter={x:Static dd:BoolToVisibilityConverter.Instance}}" /> + ItemContainerStyleSelector="{x:Static dd:DesignerItemsControlItemStyleSelector.Instance}"> - - + - - + + @@ -870,10 +870,10 @@ HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> + ItemContainerStyleSelector="{x:Static dd:DesignerItemsControlItemStyleSelector.Instance}"> - - + - - + + - - - - - - + + + + + + + + \ No newline at end of file diff --git a/AIStudio.Wpf.Mind/Themes/Generic.xaml b/AIStudio.Wpf.Mind/Themes/Generic.xaml index 0255b79..3eb9e28 100644 --- a/AIStudio.Wpf.Mind/Themes/Generic.xaml +++ b/AIStudio.Wpf.Mind/Themes/Generic.xaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> + diff --git a/AIStudio.Wpf.Mind/Themes/MindNode.xaml b/AIStudio.Wpf.Mind/Themes/MindNode.xaml index a347efb..aa89042 100644 --- a/AIStudio.Wpf.Mind/Themes/MindNode.xaml +++ b/AIStudio.Wpf.Mind/Themes/MindNode.xaml @@ -37,6 +37,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -143,8 +185,8 @@ diff --git a/AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs b/AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs new file mode 100644 index 0000000..a3ec4f6 --- /dev/null +++ b/AIStudio.Wpf.Mind/ViewModels/IMindDiagramViewModel.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AIStudio.Wpf.DiagramDesigner; + +namespace AIStudio.Wpf.Mind.ViewModels +{ + public interface IMindDiagramViewModel : IDiagramViewModel + { + MindType MindType + { + get;set; + } + + SimpleCommand AddParentCommand + { + get; + } + + SimpleCommand AddChildCommand + { + get; + } + + SimpleCommand AddPeerCommand + { + get; + } + + SimpleCommand DeleteSelfCommand + { + get; + } + + SimpleCommand MoveForwardCommand + { + get; + } + + SimpleCommand MoveBackCommand + { + get; + } + + SimpleCommand ChangeMindTypeCommand + { + get; + } + + SimpleCommand ChangeMindThemeCommand + { + get; + } + } +} diff --git a/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs new file mode 100644 index 0000000..55701ea --- /dev/null +++ b/AIStudio.Wpf.Mind/ViewModels/MindDiagramViewModel.cs @@ -0,0 +1,382 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AIStudio.Wpf.DiagramDesigner; + +namespace AIStudio.Wpf.Mind.ViewModels +{ + public class MindDiagramViewModel : DiagramViewModel, IMindDiagramViewModel + { + #region + private MindType _mindType = Mind.MindType.Mind; + public MindType MindType + { + get + { + return _mindType; + } + set + { + if (SetProperty(ref _mindType, value)) + { + ExecutedChangeMindTypeCommand(value); + } + } + } + #endregion + + #region 命令 + + public SimpleCommand AddParentCommand + { + get; private set; + } + + public SimpleCommand AddChildCommand + { + get; private set; + } + + public SimpleCommand AddPeerCommand + { + get; private set; + } + + public SimpleCommand DeleteSelfCommand + { + get; private set; + } + + public SimpleCommand MoveForwardCommand + { + get; private set; + } + + public SimpleCommand MoveBackCommand + { + get; private set; + } + + private SimpleCommand _changeMindTypeCommand; + public SimpleCommand ChangeMindTypeCommand + { + get + { + return this._changeMindTypeCommand ?? (this._changeMindTypeCommand = new SimpleCommand(MindExecuteEnable, this.ExecutedChangeMindTypeCommand)); + } + } + + public SimpleCommand ChangeMindThemeCommand + { + get; private set; + } + + public SimpleCommand ResetLayout + { + get; private set; + } + + public SimpleCommand Expand2Level1 + { + get; private set; + } + + public SimpleCommand Expand2Level2 + { + get; private set; + } + + public SimpleCommand Expand2Level3 + { + get; private set; + } + + public SimpleCommand Expand2Level4 + { + get; private set; + } + + public SimpleCommand Expand2Level5 + { + get; private set; + } + + public SimpleCommand Expand2Level6 + { + get; private set; + } + #endregion + + public MindDiagramViewModel() + { + AddChildCommand = new SimpleCommand(MindExecuteEnable, ExecuteAddChildCommand); + AddParentCommand = new SimpleCommand(MindLevelEnable, ExecuteAddParentCommand); + AddPeerCommand = new SimpleCommand(MindLevelEnable, ExecuteAddPeerCommand); + DeleteSelfCommand = new SimpleCommand(MindLevelEnable, ExecuteDeleteSelfCommand); + MoveForwardCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveForwardCommand); + MoveBackCommand = new SimpleCommand(MindExecuteEnable, ExecuteMoveBackCommand); + } + + public bool MindExecuteEnable(object para) + { + if (ExecuteEnable(para) == false) return false; + + if (SelectedItem is MindNode) return true; + + return false; + } + + private bool MindLevelEnable(object obj) + { + if (MindExecuteEnable(obj) == false) return false; + + return (SelectedItem as MindNode).NodeLevel != NodeLevel.Level1; + } + + #region 操作 + private void ExecutedChangeMindTypeCommand(object obj) + { + if (obj is MindType mindType) + { + Items.OfType().ToList().ForEach(item => { item.MindType = mindType; }); + + Items.OfType().FirstOrDefault()?.LayoutUpdated(); + } + } + + public void ExecuteAddChildCommand(object parameter) + { + List items = new List(); + if (parameter is MindNode parent) + { + + } + else if (parameter is IEnumerable para) + { + parent = para.FirstOrDefault();//第一个固定为父节点 + items = para.Skip(1).ToList(); + } + else + { + parent = SelectedItem as MindNode; + } + + if (items?.Count == 0) + { + var node = new MindNode(this, (NodeLevel)Math.Min((int)parent.NodeLevel + 1, (int)NodeLevel.Level3), this.MindType) { Text = "分支主题" }; + items.Add(node); + } + + DoCommandManager.DoNewCommand(this.ToString(), + () => { + foreach (var item in items) + { + parent.AddChild(item); + } + parent.LayoutUpdated(); + }, + () => { + foreach (var item in items) + { + parent.RemoveChild(item); + } + parent.LayoutUpdated(); + }); + + } + + public void ExecuteAddParentCommand(object parameter) + { + List items = new List(); + if (parameter is MindNode node) + { + + } + else if (parameter is IEnumerable para) + { + node = para.FirstOrDefault();//第一个固定为父节点 + items = para.Skip(1).ToList(); + } + else + { + node = SelectedItem as MindNode; + } + if (items?.Count == 0) + { + items.Add(new MindNode(this, node.NodeLevel, this.MindType) { Text = "分支主题" }); + } + + if (node.Parent is MindNode parent) + { + DoCommandManager.DoNewCommand(this.ToString(), + () => { + int index = parent.Children.IndexOf(node); + + parent.AddChild(items[0], index + 1); + parent.RemoveChild(node); + items[0].AddChild(node); + + parent.LayoutUpdated(); + }, + () => { + int index = parent.Children.IndexOf(items[0]); + items[0].RemoveChild(node); + parent.AddChild(node, index + 1); + + parent.LayoutUpdated(); + }); + + + } + } + + public void ExecuteAddPeerCommand(object parameter) + { + List items = new List(); + if (parameter is MindNode pear) + { + + } + else if (parameter is IEnumerable para) + { + pear = para.FirstOrDefault();//第一个固定为同级节点 + items = para.Skip(1).ToList(); + } + else + { + pear = SelectedItem as MindNode; + } + + if (items?.Count == 0) + { + var node = new MindNode(this, pear.NodeLevel, this.MindType) { Text = "分支主题" }; + items.Add(node); + } + + + if (pear.Parent is MindNode parent) + { + DoCommandManager.DoNewCommand(this.ToString(), + () => { + int index = parent.Children.IndexOf(pear); + for (int i = 0; i < items.Count; i++) + { + parent.AddChild(items[i], index + i + 1); + } + + parent.LayoutUpdated(); + }, + () => { + for (int i = 0; i < items.Count; i++) + { + parent.RemoveChild(items[i]); + } + parent.LayoutUpdated(); + }); + + } + + } + + private void ExecuteMoveBackCommand(object parameter) + { + if (parameter is MindNode node) + { + + } + else + { + node = SelectedItem as MindNode; + } + + if (node.Parent is MindNode parent) + { + DoCommandManager.DoNewCommand(this.ToString(), + () => { + int index = parent.Children.IndexOf(node); + if (index < parent.Children.Count - 1) + { + parent.RemoveChild(node); + parent.AddChild(node, index + 1); + parent.LayoutUpdated(); + } + }, + () => { + int index = parent.Children.IndexOf(node); + if (index > 0) + { + parent.RemoveChild(node); + parent.AddChild(node, index - 1); + parent.LayoutUpdated(); + } + }); + } + + } + + private void ExecuteMoveForwardCommand(object parameter) + { + if (parameter is MindNode node) + { + + } + else + { + node = SelectedItem as MindNode; + } + + if (node.Parent is MindNode parent) + { + DoCommandManager.DoNewCommand(this.ToString(), + () => { + int index = parent.Children.IndexOf(node); + if (index > 0) + { + parent.RemoveChild(node); + parent.AddChild(node, index - 1); + parent.LayoutUpdated(); + } + }, + () => { + int index = parent.Children.IndexOf(node); + if (index < parent.Children.Count - 1) + { + parent.RemoveChild(node); + parent.AddChild(node, index + 1); + parent.LayoutUpdated(); + } + }); + } + + } + + private void ExecuteDeleteSelfCommand(object parameter) + { + if (parameter is MindNode node) + { + + } + else + { + node = SelectedItem as MindNode; + } + + if (node.Parent is MindNode parent) + { + int index = parent.Children.IndexOf(node); + DoCommandManager.DoNewCommand(this.ToString(), + () => { + parent.RemoveChild(node, true); + parent.LayoutUpdated(); + }, + () => { + parent.AddChild(node, index); + parent.LayoutUpdated(); + }); + } + + } + #endregion + + } +} diff --git a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs index 037c707..ee698f5 100644 --- a/AIStudio.Wpf.Mind/ViewModels/MindNode.cs +++ b/AIStudio.Wpf.Mind/ViewModels/MindNode.cs @@ -20,6 +20,7 @@ using AIStudio.Wpf.Flowchart.Models; using AIStudio.Wpf.Mind.Helpers; using AIStudio.Wpf.Mind.Models; + namespace AIStudio.Wpf.Mind.ViewModels { public class MindNode : DiagramItemViewModel @@ -31,20 +32,19 @@ namespace AIStudio.Wpf.Mind.ViewModels public MindNode(IDiagramViewModel root, NodeLevel nodeLevel, MindType mindType = MindType.Mind) : base(root) { NodeLevel = nodeLevel; - MindType = mindType; + MindType = mindType; - InitLayout(); - MindLayout.Appearance(this); + InitLayout(true); } public MindNode(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer) { - InitLayout(); + InitLayout(false); } public MindNode(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType) { - InitLayout(); + InitLayout(false); } public override SelectableItemBase GetSerializableObject() @@ -58,21 +58,25 @@ namespace AIStudio.Wpf.Mind.ViewModels 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); + AddChildCommand = (Root as IMindDiagramViewModel)?.AddChildCommand; + AddParentCommand = (Root as IMindDiagramViewModel)?.AddParentCommand; + AddPeerCommand = (Root as IMindDiagramViewModel)?.AddPeerCommand; + DeleteSelfCommand = (Root as IMindDiagramViewModel)?.DeleteSelfCommand; + MoveForwardCommand = (Root as IMindDiagramViewModel)?.MoveForwardCommand; + MoveBackCommand = (Root as IMindDiagramViewModel)?.MoveBackCommand; BuildMenuOptions(); - - this.PropertyChanged += this.Item_PropertyChanged; } - protected void InitLayout() + protected void InitLayout(bool initAppearance) { 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(); + + if (initAppearance) + { + MindLayout.Appearance(this); + } + this.PropertyChanged += this.Item_PropertyChanged; } protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase) @@ -103,8 +107,6 @@ namespace AIStudio.Wpf.Mind.ViewModels } - - private bool Level_Enable(object obj) { if (Command_Enable(obj) == false) return false; @@ -115,7 +117,7 @@ namespace AIStudio.Wpf.Mind.ViewModels #region 属性 public IMindLayout MindLayout { - get;set; + get; set; } [Browsable(false)] private NodeLevel _nodeLevel; @@ -130,6 +132,29 @@ namespace AIStudio.Wpf.Mind.ViewModels SetProperty(ref _nodeLevel, value); } } + //public MindNode ParentNode + //{ + // get + // { + // return Parent as MindNode; + // } + + //} + + //public int NodeLevel + //{ + // get + // { + // if (ParentNode == null) + // { + // return 0; + // } + // else + // { + // return ParentNode.NodeLevel + 1; + // } + // } + //} private MindType _mindType; public MindType MindType @@ -142,7 +167,7 @@ namespace AIStudio.Wpf.Mind.ViewModels { SetProperty(ref _mindType, value); } - } + } private bool _isExpanded = true; public bool IsExpanded @@ -214,7 +239,7 @@ namespace AIStudio.Wpf.Mind.ViewModels public bool LayoutUpdating { - get;set; + get; set; } #endregion @@ -314,7 +339,7 @@ namespace AIStudio.Wpf.Mind.ViewModels get; private set; } - public SimpleCommand DeleteCommand + public SimpleCommand DeleteSelfCommand { get; private set; } @@ -337,136 +362,37 @@ namespace AIStudio.Wpf.Mind.ViewModels CinchMenuItem menuItem = new CinchMenuItem(); menuItem.Text = "下级"; menuItem.Command = AddChildCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "同级"; menuItem.Command = AddPeerCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "上级"; menuItem.Command = AddParentCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "前移"; menuItem.Command = MoveForwardCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "后移"; menuItem.Command = MoveBackCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); menuItem = new CinchMenuItem(); menuItem.Text = "删除"; - menuItem.Command = DeleteCommand; + menuItem.Command = DeleteSelfCommand; + menuItem.CommandParameter = this; menuOptions.Add(menuItem); } #endregion - #region 操作 - public void ExecuteAddChildCommand(object obj) - { - if (obj is MindNode node) - { - } - else - { - node = new MindNode(Root, (NodeLevel)Math.Min((int)NodeLevel + 1, (int)NodeLevel.Level3), 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(); - } - } - + #region 操作 public void AddChild(MindNode item, int index = -1) { if (this.NodeLevel == NodeLevel.Level1) @@ -486,13 +412,10 @@ namespace AIStudio.Wpf.Mind.ViewModels 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 }); + Root?.DirectAddItemCommand.Execute(new SelectableDesignerItemViewModelBase[] { item, connector }); + connector.ZIndex = -1; + this.IsSelected = true; } public void RemoveChild(MindNode item, bool removeall = false) @@ -535,17 +458,9 @@ namespace AIStudio.Wpf.Mind.ViewModels 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(MindType): + InitLayout(true); + break; case nameof(Left): { if (e is ValuePropertyChangedEventArgs valuePropertyChangedEventArgs) @@ -625,7 +540,7 @@ namespace AIStudio.Wpf.Mind.ViewModels #endregion } - + public class LinkInfo : BindableBase { private string _url; diff --git a/Directory.Build.Props b/Directory.Build.Props index 4d652c4..b3d0e9d 100644 --- a/Directory.Build.Props +++ b/Directory.Build.Props @@ -1,7 +1,7 @@ - netcoreapp3.1;net5.0-windows + net461;netcoreapp3.1;net5.0-windows